import java.util.Random; /** * A thread has a run method that gets run when it is started. By extending * (deriving from) thread, we can override the run method to do what we want. */ class Player extends Thread { private String name; // Name of this player private GameMonitor monitor; // Monitor used to synchronize the players /** * Make a player with the given name. The player will use the given monitor * to synchronize with other players. * @param name - Name of the player * @param monitor - Monitor to control players */ Player(String name, GameMonitor monitor) { this.name = name; this.monitor = monitor; } public void run() { // Make a new random number generator. Random rand = new Random(); // This try/catch block is just to handle errors that can occur // in sleep and in wait (inside the monitor) try { while (true) { // Sleep for a little while int sleeptime = Math.abs(rand.nextInt()) % 100; Thread.sleep(sleeptime); // Randomly choose a number int choice = rand.nextInt(); // Say what our choice is. System.out.println(name + ": chooses " + choice); if (monitor.decide(choice)) { System.out.println(name + ": I win!!!"); } } } catch (InterruptedException e) { System.out.println(name + " got an exception"); } } } /** * Main class for starting the game. It just contains a main method that gets * run when the program is started. */ public class Game { public static void main(String[] args) { // Local variable used for making players (which are each threads) Player p; // Make a monitor that all the threads will use GameMonitor monitor = new GameMonitor(); // Make three threads, give each one a different name and give // each one a reference to the monitor. p = new Player("Larry", monitor); p.start(); p = new Player("Curly", monitor); p.start(); p = new Player("Moe", monitor); p.start(); // Now, the threads do all the work. } } class GameMonitor { /** * Constructor for the monitor. You can initialize any variables you need in * here. */ public GameMonitor() { } /** * Monitor function to decide the winner from among the three participating * threads. (You can assume there are exactly three.) The throws * InterruptedException part is necessary for the wait() call. * * @param vote - Player's vote * * @return true if player won; false otherwise */ public boolean decide(int vote) throws InterruptedException { test(vote, false); return false; // Probably should change this } private static boolean modDecision(int vote, int modSum) { boolean rtn = false; switch (modSum) { case 0: // All even rtn = false; break; case 3: // All odd rtn = false; break; case 1: // 1 odd rtn = vote % 2 != 0; break; case 2: // 1 even rtn = vote % 2 == 0; break; default: System.err.println("Impossible value for modulo sum"); System.exit(1); } return rtn; } // Number of players private static final int NUMPLAYERS = 3; // Maximum round for test private static final int MAXROUND = 100000; // Count of times each thread has called decide() private java.util.Map playerCount = new java.util.HashMap(); // Current round of game private int round = 1; // Count of players calling decide() within round private int testCallCt = 0; // Votes during round for each player private java.util.Map playerVotes = new java.util.HashMap(); // Decisions during round for each player private java.util.Map playerDecisions = new java.util.HashMap(); private void test(int vote, boolean rtn) { // Compute and store decide() call count for current thread Thread curThd = Thread.currentThread(); int curCt = (playerCount.containsKey(curThd) ? playerCount.get(curThd) : 0) + 1; playerCount.put(curThd, curCt); // Store player votes and decisions playerVotes.put(curThd, vote); playerDecisions.put(curThd, rtn); // Call count for current thread must match round if (curCt != round) { System.err.println(curThd + ": Current player count (" + curCt + ") doesn't match round (" + round + ")"); System.exit(1); } // Other players in current or previous round for (int othrPlyrCt : playerCount.values()) { if (othrPlyrCt != round && othrPlyrCt != round - 1) { System.err.println("Player counts off"); System.exit(1); } } // If end of round, test correctness of results, increment round, and reset control vars if (++testCallCt == NUMPLAYERS) { int modSum = 0; for (int playerVote : playerVotes.values()) { modSum += Math.abs(playerVote % 2); } if (modDecision(vote, modSum) != playerDecisions.get(curThd)) { System.err.println("Bad decision"); System.exit(1); } testCallCt = 0; if (++round == MAXROUND) { System.out.println("SUCCESS"); System.exit(1); } } } }