I'm trying to implement a word game in Java, where each player takes turns extracting a number of random letters from a set, then trying to create a valid word with those letters. This is what I have so far (simplified for clarity's sake):
In the Game class, I start the game by running a thread for each player (and one for the timekeeper). I want the first player in the activePlayers list (which initially is the same as the players list) to make the first move, so I initialized the turn and turnIndex attributes to correspond to this player:
public void play()
{
this.turn = activePlayers.get(0); //the player who joined first goes first
this.turnIndex = 0; //the player's index in the ArrayList
for(Player player : players) {
new Thread(player).start();
}
new Thread(new Timekeeper()).start(); //keeps track of the game's duration
}
In the Player class, I want the players on stand-by to not do anything, and simply wait for the current player to finish their business, hence the first while loop. Then, when a player's turn has ended, I want that thread to yield the monitor to another player's thread and wait its next turn. This is how I decided to approach it:
private synchronized boolean submitWord() throws InterruptedException
{
while(game.turn != this)
{
System.out.println(this.name + " is waiting their turn...");
wait();
}
Thread.sleep(1000);
List<Tile> extracted = game.getBag().extractTiles(wordLength);
if(extracted.isEmpty())
return false; //if there are no more letters to extract, the thread ends its execution
//game logic goes here - creating and validating the word
//after this player is done, the next player makes their move
game.turnIndex++;
if(game.turnIndex >= game.activePlayers.size())
game.turnIndex = 0;
game.turn = game.activePlayers.get(game.turnIndex);
notifyAll();
return true;
}
@Override
public void run()
{
do {
try {
this.running = this.submitWord();
} catch(InterruptedException e) {
System.out.println("Something went wrong with " + this.name + "...");
e.printStackTrace();
}
} while(this.running);
game.activePlayers.remove(this); //the player is now inactive
if(game.winner == this)
System.out.println("Winner: " + this.name + " [" + this.score + " points]");
}
However, when I try to run the program, I get something like this:
Player 2 is waiting their turn...
Player 3 is waiting their turn...
1 seconds elapsed...
Player 1: AERIAL [36 points]
Player 1 is waiting their turn...
2 seconds elapsed...
3 seconds elapsed...
4 seconds elapsed...
5 seconds elapsed...
6 seconds elapsed...
Basically, the game doesn't move past Player 1's first try, and I get stuck in an infinite loop where nothing happens. Am I not using the wait() and notifyAll() methods properly? How should I make the player threads communicate with each other?