The title could be incorrect but I couldn't think of anything else to name this question.
My issue comes with some Java code I've been writing that is driving me insane. Basically I'm trying to make a "card memory" game where I have a 4X4 grid of cards laid out; when you click one it flips, then you click the second, it flips, and if they're the same card it disappears and if they're different cards it flips them back over.
This works fine except one little detail. When you click the first card it flips, then when you click the second card it flips it and checks the value of it so fast that you can't tell if the 2nd card flips at all before they're gone or the first one is flipped back over. So I added
try{Thread.sleep(2000);}catch(InterruptedException ex) {}
after I flipped the second card. Well now it's becoming clear that the second card doesn't flip at all. I click the first card, it flips, I click the second card, it waits 2 seconds (thread sleep) and then it determines the equality and either hides or flips the first card back. All without ever showing what the 2nd card was.
I am going to add all the code I have below. I'm sorry that it's a lot but I don't know which part is relevant.
Card.java
import objectdraw.*;
import java.awt.Image;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class Card {
private int value;
private VisibleImage imageFront, imageBack;
public Card(int val, Location p, double w, double h, DrawingCanvas c) {
value = val;
String urlStr = "images/" + val + ".png";
BufferedImage img = null, imgb = null;
try {
img = ImageIO.read(new File(urlStr));
imgb = ImageIO.read(new File("images/card-back.png"));
} catch(IOException ex) {}
imageFront = new VisibleImage(img,p,w,h,c);
imageFront.hide();
imageBack = new VisibleImage(imgb,p,w,h,c);
}
public void flip() {
if(imageFront.isHidden()) {
imageFront.show();
imageBack.hide();
} else {
imageBack.show();
imageFront.hide();
}
}
public Boolean contains(Location p) {
if(imageFront.isHidden()) {
return imageBack.contains(p);
} else {
return imageFront.contains(p);
}
}
public void moveTo(double x, double y) {
imageFront.moveTo(x,y);
imageBack.moveTo(x,y);
}
public int getValue() {
return value;
}
public void hide() {
imageFront.hide();
imageBack.hide();
}
}
Grid.java
import objectdraw.*;
public class Grid {
private static final int ROWS = 4;
private static final int COLS = 4;
private Card[] cards = new Card[COLS * ROWS];
public Grid(double cardW, double cardH, DrawingCanvas c) {
int cnt = 0;
Location p1 = new Location(0,0);
Location p2 = new Location(0,(ROWS/2)*cardH);
for(int i = 0; i < ROWS; i++) {
for(int j = 0; j < COLS; j++) {
// Set up 2 of the same card, one at cnt and one at cnt + cards.length/2
if(cnt < cards.length/2) {
cards[cnt] = new Card(cnt+1,p1,cardW,cardH,c);
p1.translate(cardW,0);
cards[cnt + cards.length/2] = new Card(cnt+1,p2,cardW,cardH,c);
p2.translate(cardW,0);
cnt++;
}
}
p1.translate(-(cardW * COLS),cardH);
p2.translate(-(cardW * COLS),cardH);
}
}
private static int sel = -1;
public void select(Location p) {
for(int i = 0; i < cards.length; i++) {
// Find the correct card
if(cards[i].contains(p)) {
if(sel == -1) {
// This is the first card selected
System.out.printf("\nThis is the first card selected");
cards[i].flip();
sel = i;
break;
} else {
System.out.printf("\nThis is the second card");
// They selected the same card
if(i == sel) {
break;
} else {
// This is the second card selected and it's unique
// Flip it and check if they match. If they do, then hide both,
// if they don't then flip both back
cards[i].flip();
if(cards[i].getValue() == cards[sel].getValue()) {
try {
remove(cards[i], cards[sel]);
} catch(InterruptedException ex) {}
sel = -1;
break;
} else {
cards[i].flip();
cards[sel].flip();
sel = -1;
break;
}
}
}
}
} // for loop
}
public void remove(final Card card1, final Card card2) throws InterruptedException {
new Thread() {
public void run() {
sleep(2000);
card1.hide();
card2.hide();
}
}.start();
}
}
Client.java
import objectdraw.*;
public class Client extends WindowController {
public static void main(String[]args) {
new Client().startController(310,460);
}
Grid board;
public void begin() {
board = new Grid(75,102,canvas);
}
public void onMouseClick(Location p) {
board.select(p);
}
}
For reference all of this comes from the objectdraw library
I would separate the select() and remove() logic. Exactly here:
if(cards[i].getValue() == cards[sel].getValue()) {
remove(cards[i], cards[sel]); //call the remove
And remove() would start a Thread and remove the wanted values:
public void remove(final Card card1, final Card card2) {
new Thread() {
#Override
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
}
card1.hide();
card2.hide();
}
}.start();
}
So this way you don't block the UI thread (the user can see the flip) and the new thread will hide the cards after the two seconds.
Related
I'm working on a program which should instantiate n amount of threads. Their job is to draw from a deck existing of 52 distinct cards, wait until the round have been evaluated(who had the highest card) and the user has the highest card shown and then repeat until the deck is empty.
The first round runs flawless, not accounting for the wrong evaluation of the cards, but then the program just locks. Never drawing new cards.
I can't quite figure out what the problem is, but my guess is that I'm calling notifyAll() before the threads wake, causing a deadlock. Even though I'm counting the number of waiting threads and only notifying if the number of waiting threads corresponds to the number of players.
EDIT: I found out that if I debug, the code runs smoothly and as intended. But as soon as I run it, it runs as earlier described.
public class Deck {
Stack<Card> stack = new Stack<>();
public Deck()
{
makeAndShuffleDeck();
}
public synchronized Card drawOneCard()
{
Card card = stack.pop();
System.out.println(Thread.currentThread() + " is drawing " + card);
return card;
}
public void setCardValues(int x)
{
if(x == 0)
{
Rank.ACE.setValue(14);
}
else
{
Rank.ACE.setValue(1);
}
}
public void makeAndShuffleDeck()
{
for(Suit suit : Suit.values())
{
for(Rank value : Rank.values())
{
stack.add(new Card(suit,value));
}
}
Collections.shuffle(stack);
}
public Stack<Card> getDeck()
{
return stack;
}
}
public class Round {
ArrayList<Thread> playersInTheRound = new ArrayList<>();
ArrayList<Card> cardsDrawnInTheRound = new ArrayList<>();
Deck deck;
int numberOfRounds;
public Round(int nrOfPlayers, Deck deck)
{
this.deck = deck;
fillListWithPlayers(nrOfPlayers);
calcNumberOfRounds();
for(Thread p: playersInTheRound)
{
p.start();
}
}
public void fillListWithPlayers(int nrOfPlayers)
{
for (int i = 0; i < nrOfPlayers; i++)
{
playersInTheRound.add(new Thread(new Player(deck, this)));
}
}
public void addPlayerCards(Card card)
{
cardsDrawnInTheRound.add(card);
}
public void calcNumberOfRounds()
{
numberOfRounds = deck.getDeck().size()/playersInTheRound.size();
}
public void playRound()
{
while(numberOfRounds > 0)
{
findWinnerOfRound();
cardsDrawnInTheRound.clear();
while(Player.waiting == playersInTheRound.size())
{
synchronized (this)
{
this.notifyAll();
}
Player.waiting = 0;
}
numberOfRounds--;
}
}
public void findWinnerOfRound()
{
Card highestCard = null;
Comparator<Card> comp = (Card c1, Card c2) ->
{
if (c1.rank.getValue() == c2.rank.getValue())
{
if (c1.suit.getRank() > c2.suit.getRank())
{
return 1;
}
return -1;
}
if (c1.rank.getValue() > c2.rank.getValue())
{
return 1;
}
return -1;
};
for (int i = 0; i < cardsDrawnInTheRound.size()-1; i++)
{
for (int j = i+1; j < cardsDrawnInTheRound.size(); j++)
{
if(comp.compare(cardsDrawnInTheRound.get(i), cardsDrawnInTheRound.get(j)) == -1)
{
highestCard = cardsDrawnInTheRound.get(j);
}
highestCard = cardsDrawnInTheRound.get(i);
}
}
System.out.println(cardsDrawnInTheRound);
System.out.println("Winner: " + highestCard);
}
}
public class Player implements Runnable {
Deck deck;
Round round;
public static int waiting = 0;
public Player(Deck deck, Round round)
{
this.deck = deck;
this.round = round;
}
#Override
public void run()
{
Card card = deck.drawOneCard();
synchronized (round)
{
try
{
round.addPlayerCards(card);
waiting++;
round.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
I'm trying to create an example with some graphics for a ´Stack´.
I want the Wagons to "Spawn" and move in one track which are the ´stacks´.
The moving process is made by the ´Wagon´ itself. I already tried to give the Wagon a reference to my ´Frame´ called ´Window´ to repaint it in every loop but it still doesn't show up until it reached it's stop.
Wagon:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Window extends JFrame {
private Stack stack1 = new Stack(1);
public Window() {
setSize(800, 400);
setResizable(false);
setLayout(null); //Not perfect, but it works for those little things
setVisible(true);
createTracks(); //Tracksgraphic made out of gray rects
}
public void addWagon(Wagon wagon) { //Is called when adding a Wagon
this.add(wagon);
stack1.addWagon(wagon);
}
public static void main(String[] args) { //main
new Window();
}
}
Stack:
public class Stack {
private int gleis; //gleis = german for track
private Wagon first = null;
public Stack(int g) {
gleis = g;
}
public void addWagon(Wagon wagon) {
if (first != null) {
wagon.setNext(first);
}
first = wagon;
first.moveRight(gleis);
}
public void removeWagon(int id, Stack nextStack) {
Wagon speicherFirst = first;
first.moveLeft(null);
first = first.getNext();
while (speicherFirst.getID() != id) {
speicherFirst.setNext(first);
first.moveLeft(speicherFirst);
speicherFirst = first;
first = first.getNext();
}
nextStack.addWagon(speicherFirst);
if (speicherFirst.getNext() != null) {
speicherFirst = speicherFirst.getNext();
while (speicherFirst!= null) {
speicherFirst.moveRight(gleis);
speicherFirst = speicherFirst.getNext();
}
}
}
public boolean hasID(int id) {
return first.isID(id);
}
}
Wagon:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Wagon extends JPanel { //Entspricht einem Canvas aus .awt
private Wagon next;
private int id;
public Wagon(int i) {
id = i;
setSize(50, 20);
Random r = new Random();
setBackground(new Color(r.nextFloat(), r.nextFloat(), r.nextFloat()));
setVisible(true);
}
public boolean isID(int i) {
if (id == i) {
return true;
} else if (next == null) {
return false;
} else {
return next.isID(i);
}
}
public void setNext(Wagon n) {
next = n;
}
public void moveRight(int gleis) {
setLocation(getX(), gleis * 100);
if (next != null) {
while (next.getX() - getX() < 70) {
next.moveRight(gleis);
move(3);
}
} else {
while (getX() < 700) {
move(3);
}
}
}
public Wagon getNext() {
return next;
}
public int getID() {
return id;
}
public void moveLeft(Wagon previous) {
if (previous == null) {
while (getX() > 50) {
move(-3);
}
} else {
while (getX() - previous.getX() > 50) {
move(-3);
}
}
}
public void move(int dir) {
this.setLocation(getX() + dir, getY());
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}
}
it still doesn't show up until it reached it's stop.
Your code is executing on the Event Dispatch Thread (EDT), which is the thread that is responsible for handling GUI events and repainting the GUI. The Thread.sleep() prevents the GUI from repainting itself until the while/loop is finished executing so you only see the painting at the end. Read the section from the Swing tutorial on Concurrency for more information.
The solution is to use a Swing Timer to provide the animation, not Thread.sleep().
It looks like you don't actually have the replaint(); call anywhere in your code. I would have that in both the moveLeft() and moveRight() commands.
Another thing, you're using JPanels as your wagons. I wouldn't do this, it'll take more resources and is bad practice. Unless there's a specific reason, I'd use a base sprite image, and load it to an int[] array, and paint that array to that screen using BufferedImage, instead of having x number of JPanel's running around.
I asked this question yesterday and have attempted to implement the top answer I received. So from the code from yesterday I have tried adding synchronized to my methods and using wait() and notifyAll(). I have been looking up a bunch of examples, and reading the documentation but I'm definitely not doing it right.
Basically, once a touchEvent happens my ButtonListener stops all of my other code from executing, and only performs the code contained within the ButtonListener. This only happens on one of my computers though, my laptop runs the code the way I expected it to, my desktop gets stuck in the ButtonListener. This was a school assignment I turned in a couple weeks ago and initially received a 70%, but I explained to my teacher that it works on some computers and he ran it on his office desktop, and viola, it worked and I got a 100%. Of course I want to figure out what the problem is though so that is why I'm still working on this.
Here are the offending code snippets:
public synchronized void playOneTurn(int player)
throws InterruptedException {
waiting = true;
while (waiting) {
try {
System.out.println("playOneTurn before wait.");
wait();
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
System.out.println("playOneTurn AFTER wait.");
}
My method here, playOneTurn, is the last bit of code that runs before the first touch event. Previously, as you can tell by looking at my question linked at the top, I used a simple while loop that waited for my ButtonListener to flip a boolean, waiting. Above is my attempt to use synchronized.
class ButtonListener implements ActionListener {
#Override
public synchronized void actionPerformed(ActionEvent e) {
System.out.println("Entering Action Performed");
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
if (e.getSource() == cells[i][j]) {
if (model[i][j] == 'e') {
cells[i][j].setText("");
currentSpot[0] = i;
currentSpot[1] = j;
if (count % 2 == 0) {
cells[i][j].setBackground(Color.GREEN);
cells[i][j].setIcon(X_MARK);
model[i][j] = 'x';
count++;
waiting = false;
System.out.println("Boolean hit");
notifyAll();
} else {
cells[i][j].setBackground(Color.CYAN);
cells[i][j].setIcon(O_MARK);
model[i][j] = 'o';
count++;
waiting = false;
System.out.println("Boolean hit");
notifyAll();
}
} else {
System.out
.println("Hey, you can't move there silly!");
}
}
}
}
}
}
Here is my ButtonListener where my program just chills in and stops doing anything else. Please disregard my random printlns everywhere, I was just getting aggravated and trying to find out what this thing is doing.
I also had to add this try/catch block to my controller class:
while (!game.haveWinner() && !game.isFull()) {
player = (player + 1) % 2;
try {
game.playOneTurn(player);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("While loop looped");
}
I have been trying every way I can think of to correctly implement synchronized but I'm obviously doing something wrong.
Here is a Dropbox link to the entire program if it would help.
This:
while (!game.haveWinner() && !game.isFull()) {
Is going to tie up the Swing event thread and freeze your entire application .... don't do it.
Your code looks like you're trying to hack a linear console program into a Swing GUI, and that never works because their program flow and logic are completely different. The solution is to change your logic to more event-driven.
You presumably have a game loop somewhere, perhaps using a Swing Timer ... so check with each iteration of the loop for winner or for is full.
You need to get all waiting, all synchronized, all notifies out of your program. Instead make a button press change it's state.
Edit
I was playing around with your code, and came up with something like this. Note that synchronization is not my strong suite, so take this with a grain of salt, but my key goal is to make sure that Swing GUI creation code and state changing code is called only on the Swing event thread, and that any other code, especially code that requires synchronization with other threads, is not called on the Swing event thread.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;
import javax.swing.*;
public class TicTacToeApp {
public static void main(String[] args) {
TicTacToeGame game;
int size, need, player = 1;
String[] names = new String[2];
Scanner kbd = new Scanner(System.in);
// TODO: uncomment in running code
// System.out.print("Enter Player 1's name: ");
// names[0] = kbd.nextLine();
// System.out.print("Enter Player 2's name: ");
// names[1] = kbd.nextLine();
//
// System.out.print("Enter the TIC-TAC-TOE grid size: ");
// size = kbd.nextInt();
// System.out.print("Enter how many in a row you need to win: ");
// need = kbd.nextInt();
// System.out.println();
// TODO: For test purposes only. Delete in running code
size = 3;
need = 3;
names[0] = "Foo";
names[1] = "Bar";
game = new TicTacToeGame(size, need, names);
while (!game.haveWinner() && !game.isFull()) {
player = (player + 1) % 2;
try {
game.playOneTurn(player);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("While loop looped");
}
if (game.haveWinner())
System.out.println(names[player] + " is the winner!");
else
System.out.println("It's a TIE!");
System.out.println("\nBye!");
}
}
#SuppressWarnings("serial")
class TicTacToeGame extends JPanel {
private static final Object LOCK = new Object();
private volatile int player = 0;
private int size;
private int need;
private String[] names;
private JLabel nameLabel = new JLabel();
// private JButton testButton = new JButton();
private JButton[][] buttonGrid;
private volatile boolean waiting = false;
public TicTacToeGame(int size, int need, String[] names) {
this.size = size;
this.need = need;
this.names = names;
nameLabel.setText(names[0]);
JPanel topPanel = new JPanel();
topPanel.add(new JLabel("Player:"));
topPanel.add(nameLabel);
buttonGrid = new JButton[size][size];
ButtonListener actionListener = new ButtonListener(this);
JPanel middlePanel = new JPanel(new GridLayout(size, size));
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
JButton button = new JButton(" ");
middlePanel.add(button);
buttonGrid[row][col] = button;
button.addActionListener(actionListener);
}
}
setLayout(new BorderLayout());
add(topPanel, BorderLayout.NORTH);
add(middlePanel, BorderLayout.CENTER);
// run GUI on Swing event thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(TicTacToeGame.this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public int getPlayer() {
return player;
}
public synchronized void playOneTurn(final int player)
throws InterruptedException {
this.player = player;
System.out.printf("Player %d before wait%n", player);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
nameLabel.setText(names[player]);
}
});
synchronized (LOCK) {
waiting = true;
while (waiting) {
LOCK.wait();
}
}
}
public boolean isFull() {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (buttonGrid[row][col].isEnabled()) {
return false;
}
}
}
return true;
}
public boolean haveWinner() {
// TODO finish this
return false;
}
public void doNotification() {
new Thread(new Runnable() {
public void run() {
synchronized (LOCK) {
waiting = false;
LOCK.notifyAll();
}
}
}).start();
}
public void tttButtonPressed(ActionEvent e) {
AbstractButton source = (AbstractButton) e.getSource();
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
if (buttonGrid[r][c] == source) {
String text = player == 0 ? "X" : "0";
source.setText(text);
source.setEnabled(false);
}
}
}
doNotification();
}
}
class ButtonListener implements ActionListener {
private TicTacToeGame ticTacToeGame;
public ButtonListener(TicTacToeGame ticTacToeGame) {
this.ticTacToeGame = ticTacToeGame;
}
public void actionPerformed(ActionEvent e) {
ticTacToeGame.tttButtonPressed(e);
};
}
Oh OK, I found the bug.
public class TicTacToeGame extends JFrame {
public synchronized void playOneTurn(int player)
throws InterruptedException {
wait();
}
class ButtonListener implements ActionListener {
#Override
public synchronized void actionPerformed(ActionEvent e) {
notifyAll();
}
}
}
I reduced the code so it's more obvious. playOneTurn is synchronized and waits on the TicTacToeGame instance but actionPerformed is synchronized and notifies on the ButtonListener instance.
A fix would be something like this (since ButtonListener is an inner class):
#Override
public void actionPerformed(ActionEvent e) {
synchronized (TicTacToeGame.this) {
TicTacToeGame.this.notifyAll();
}
}
Or create a separate object just to be a monitor.
But as I said before (and #HovercraftFullOfEels also seems to be saying), you could do to simply remove the while loop from the program and just use the event as a single entry point.
Also: don't forget to create your GUI on the EDT with invokeLater.
When code of the ActionListner more time consuming in execution, it halts all other part of the program from running.
So, create a new thread when the control enters the ActionListner. so it leverage the main thread to run other code while the thread you created runs your ActionListner part of the code.
Example:
void actionPerformed(ActionEvent e) {
Thread t = new Thread(new runnable()) {
public void run() {
System.out.println("Entering Action Performed");
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
if (e.getSource() == cells[i][j]) {
if (model[i][j] == 'e') {
cells[i][j].setText("");
currentSpot[0] = i;
currentSpot[1] = j;
if (count % 2 == 0) {
cells[i][j].setBackground(Color.GREEN);
cells[i][j].setIcon(X_MARK);
model[i][j] = 'x';
count++;
waiting = false;
System.out.println("Boolean hit");
notifyAll();
} else {
cells[i][j].setBackground(Color.CYAN);
cells[i][j].setIcon(O_MARK);
model[i][j] = 'o';
count++;
waiting = false;
System.out.println("Boolean hit");
notifyAll();
}
} else {
System.out
.println("Hey, you can't move there silly!");
}
}
}
}
}
};// runnable ends here
}
My homework was to create project using parallelization that all should be proper.
However, I made my project but my profesor mentioned something is wrong in my code "please look at array list, something is not ok, maybe synchronization?".
I would like ask you community to help me and point what could be wrong. I think it might be problem with not covering by synchronize brackets my array list, am I right?
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* My project finds all dividors for specific number
*It must use threads, so I made them. First I start them (first loop)
*then join them (second loop). My project must have that loops.
*Problem might be with not synchronizing methods array list...
*/
public class Main {
private final static int NUMBER = 100;
private final static List<Integer> dividors = new ArrayList<Integer>();
public static void main(String[] args) {
new Main().doStuff();
}
private int sqr;
private int sqrp1;
private void doStuff() {
sqr = (int) Math.sqrt(NUMBER);
sqrp1 = sqr + 1;
Thread[] t = new Thread[sqrp1];
//starting tasks
for (int i = 1; i < sqrp1; i++) {
final int it = i;
if (NUMBER % i == 0) {
final int e = i;
t[i] = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("sta"+e);
if (!checkContains(e)) {
addElement(e);
}
final int dividednumber = NUMBER / e;
if (!checkContains(dividednumber)) {
addElement(dividednumber);
}
}
});
t[i].start();
}
}
//calling join for tasks
for (int i = 1; i < sqrp1; i++) {
final int it = i;
if (NUMBER % i == 0) {
try {
System.out.println("sto"+i);
t[i].join();
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
System.out.println("xxx");
Collections.sort(dividors);
Integer[] arrayDividors = dividors.toArray(new Integer[0]);
for (int i = 0; i < arrayDividors.length; i++) {
System.out.println(arrayDividors[i]);
}
}
private synchronized void addElement(int element) {
dividors.add(element);
}
private synchronized boolean checkContains(int element) {
return dividors.contains(element);
}
}
Am I right changing this part, is it ok now?
t[i] = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("waiting " + e);
synchronized (this) {
System.out.println("entering " + e);
if (!checkContains(e)) {
addElement(e);
}
final int dividednumber = NUMBER / e;
if (!checkContains(dividednumber)) {
addElement(dividednumber);
}
System.out.println("leaving " + e);
}
}
});
You need to turn this into a single atomic operation.
if (!checkContains(dividednumber)) {
addElement(dividednumber);
}
Imagine you have two threads.
T1: if (!checkContains(dividednumber)) { // false
T2: if (!checkContains(dividednumber)) { // false
T1: addElement(dividednumber); // adds number
T2: addElement(dividednumber); // adds same number
If you have one addElementWithoutDuplicates, this won't happen.
There are no errors showing up in eclipse, but when I go to run the code, nothing happens in the application. It is broken up into three classes. The first class contains the if statements. I am wondering if my issue lies here.
package course.infsci0017.lab04;
import java.util.Scanner;
import javax.swing.JFrame;
public class GameOfLife {
public static void main(String[] args) {
int testCase = 1;
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setTitle("Conway's Game of Life");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Cell[][] universe = new Cell[100][100];
for (int x = 0; x < universe.length-1; x++) {
for (int y = 0; y < universe[x].length-1; y++) {
universe[x][y] = new Cell();
}
}
if (testCase == 1) {
universe[3][2].calculateNext(3);
universe[3][2].updateCurrent();
universe[3][3].calculateNext(3);
universe[3][3].updateCurrent();
universe[3][4].calculateNext(3);
universe[3][4].updateCurrent();
} else if (testCase == 2) {
universe[49][50].calculateNext(3);
universe[49][50].updateCurrent();
universe[49][51].calculateNext(3);
universe[49][51].updateCurrent();
universe[50][49].calculateNext(3);
universe[50][49].updateCurrent();
universe[50][50].calculateNext(3);
universe[50][50].updateCurrent();
universe[51][50].calculateNext(3);
universe[51][50].updateCurrent();
} else {
}
UniverseComponent component = new UniverseComponent(universe);
frame.add(component);
frame.setVisible(true);
Scanner in = new Scanner(System.in);
String input = in.nextLine();
while (input.length() == 0) {
int neighborCount = 0;
for (int x=1; x<universe.length-2; x++) {
for (int y=1; y<universe[x].length-2; y++) {
neighborCount = 0;
if (universe[x-1][y-1].isAlive()) {
neighborCount++;
}
if (universe[x-1][y].isAlive()) {
neighborCount++;
}
if (universe[x-1][y+1].isAlive()) {
neighborCount++;
}
if (universe[x][y-1].isAlive()) {
neighborCount++;
}
if (universe[x][y+1].isAlive()) {
neighborCount++;
}
if (universe[x+1][y-1].isAlive()) {
neighborCount++;
}
if (universe[x+1][y].isAlive()) {
neighborCount++;
}
if (universe[x+1][y+1].isAlive()) {
neighborCount++;
}
universe[x][y].calculateNext(neighborCount);
}
}
for (int x=1; x<universe.length-2; x++) {
for (int y=1; y<universe[x].length-2; y++) {
universe[x][y].updateCurrent();
}
}
component.repaint();
input = in.nextLine();
}
in.close();
}
}
Class 2
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class UniverseComponent extends JComponent {
private Cell[][] universe;
public UniverseComponent(Cell[][] universe) {
super();
this.universe = universe;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
for (int x=0; x<universe.length-1; x++) {
for (int y=0; y<universe[x].length-1; y++) {
if (universe[x][y].isAlive()) {
g2.fillRect(x*5, y*5, 4, 4);
}
}
}
}
}
Class 3
public class Cell {
private boolean current;
private boolean next;
public Cell() {
current = false;
next = false;
}
public Cell(int neighborCount) {
calculateNext(neighborCount);
updateCurrent();
}
public void calculateNext(int neighborCount) {
if (current) {
if ((neighborCount < 2) || (neighborCount > 3)) {
next = false;
} else {
next = true;
}
} else {
if (neighborCount == 3) {
next = true;
} else {
next = false;
}
}
}
public void updateCurrent() {
current = next;
}
public boolean isAlive() {
return current;
}
}
If any one has any idea what how to fix this please let me know. Feel free to copy and paste code if necessary. It will not let me post an image because i do not have enough reputation. Apologies
Your while loop says
while (input.length() == 0)
But if you type anything into the input at all, it will not be equal to zero, so the loop will not be executed and your program will exit.
The program seems to be designed to only allow the user to hit 'enter' without typing any words at the console. That is, the loop will be executed if you type nothing but enter, otherwise the program will exit.
This is obviously not your own code, since it doesn't appear to have a bug after all but your usage of it is incorrect. Please be more honest with your questions (and I hope you haven't been plagiarising).