I'm learning Java at college and this is from my assignment. The task is to create a x by y grid of color squares that each run in a separate thread and every k ms either change it's color to a random one or average the color of it's neighbours.
Now, if I create a 30 by 30 grid everything runs fine. However, if I try it with 40 by 40, I get the following exception once when the app starts and once when I close it. Apart from that it appears to run correctly, although the grid appears to be positioned within the window slightly wrongly (it's narrower than it should be).
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:747)
at java.util.TimSort.mergeAt(TimSort.java:483)
at java.util.TimSort.mergeCollapse(TimSort.java:410)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:136)
at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(SortingFocusTraversalPolicy.java:110)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:435)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:166)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(SortingFocusTraversalPolicy.java:515)
at java.awt.FocusTraversalPolicy.getInitialComponent(FocusTraversalPolicy.java:169)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:380)
at java.awt.Component.dispatchEventImpl(Component.java:4731)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:729)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:688)
at java.awt.EventQueue$3.run(EventQueue.java:686)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:702)
at java.awt.EventQueue$4.run(EventQueue.java:700)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:699)
at java.awt.SequencedEvent.dispatch(SequencedEvent.java:128)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:727)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:688)
at java.awt.EventQueue$3.run(EventQueue.java:686)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:702)
at java.awt.EventQueue$4.run(EventQueue.java:700)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:699)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Here's my code: The main class Symulacja:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.Random;
// main class
@SuppressWarnings("serial")
public class Symulacja extends JPanel {
public Symulacja(int x, int y, int k, double p) {
super();
Field.delay = k;
Field.p = p;
Field.random = new Random();
setLayout(new GridLayout(y, x));
//creating Field objects and adding them to the panel
Field fv[][] = new Field[y][];
for (int i = 0; i<y; i++){
fv[i] = new Field[x];
for (int j = 0; j<x; j++){
fv[i][j] = new Field();
add(fv[i][j]);
}
}
//setting the neighbours in all Field objects
for (int i = 0; i<y; i++){
for (int j = 0 ; j<x; j++){
Field fv2[] = {fv[(i+1)%y][j], fv[(i+y-1)%y][j], fv[i][(j+1)%x], fv[i][(j+x-1)%x]};
fv[i][j].setArr(fv2);
}
}
//starting the threads
for (int i = 0; i<y; i++){
for (int j = 0 ; j<x; j++){
new Thread(fv[i][j]).start();
}
}
}
public static void main(String[] args) {
Symulacja s = new Symulacja(30,30,100,0); //works
//Symulacja s = new Symulacja(40,40,100,0); //throws exception
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.add(s, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setSize(400, 400);
}
}
The Field class (a single grid element):
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
@SuppressWarnings("serial")
class Field extends Canvas implements Runnable
{
Field()
{
color = nextInt();
randFlag = false;
//zmiana koloru na losowy po kliknięciu myszą
addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
randFlag = true;
}
});
}
void setArr(Field[] a)
{
fieldArr = a;
}
public void run()
{
while (true){
double rand = nextDouble();
int newcolor;
if (rand <= p || randFlag){ // losowy kolor lub kliknięcie myszą
newcolor = nextInt();
randFlag = false;
}
else{ // uśredniony kolor
newcolor = 0;
for (Field f: fieldArr)
newcolor+=f.getColor()/4;
}
if (newcolor!=getColor()){
setColor(newcolor);
repaint();
}
try {
Thread.sleep((long)((nextDouble() + 0.5)*delay));
} catch (InterruptedException e) {
return;
}
}
}
public void paint(Graphics g)
{
g.setColor(new Color(getColor()));
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
}
synchronized public int getColor()
{
return color;
}
synchronized private void setColor(int color)
{
this.color = color;
}
private int nextInt()
{
synchronized (random) {
return random.nextInt();
}
}
private double nextDouble()
{
synchronized (random) {
return random.nextDouble();
}
}
static public int delay;
static public double p;
Field fieldArr[];
private int color;
boolean randFlag;
static Random random;
}