/** MyApplet16: Basic GUI Components and the Games n-Nim ** (for n = 3, 4, 5) ** ** n-Nim is a version of the game Nim, in which there ** are several sticks (counters) laying on a table, ** and on each turn a player must take at least one, ** but no more than n sticks. There are two players ** alternating turns, and the player who takes the last ** stick is the loser. So, the goal of the game is to ** force your opponent to take the last stick. ** ** This is a modified version of MyApplet15.java, which ** was designed to play 5-Nim. This version has been ** changed to allow the player to chose among three ** different nim games to play: 3-Nim, 4-Nim, or 5-Nim. ** ** Assignment: Play the game until you think you have ** a winning strategy and then study the program and ** try to understand how everything works. Compare ** this program to MyApplet15, and when you understand ** the changes, extend this program so that the player ** can also choose to play 6-Nim. ** ** Also, take a look at the MyApplet16.html webpage ** file for displaying this applet. **/ import java.applet.Applet; import java.awt.*; public class MyApplet16 extends Applet { private List nimVersionList; // Specify GUI layout items. private Choice randomPlayChoice; private List startCountersList; private Choice playFirstChoice; private Button startGameButton; private Checkbox[] chooseNumberBox; private Label computerMoveLabel; private Label numberLeftLabel; private Label gameOverLabel; private int nimVersion; // Specify global integer variables. private int startCounters; private int numLeft; private boolean nimVersion3; // Specify global boolean (true/false) variables. private boolean nimVersion4; private boolean nimVersion5; private boolean computerRandom; private boolean humanFirst; public void init() { add(new Label("Which version of Nim do you want to play?")); // Add label to GUI layout. nimVersionList = new List(3, false); // Create scrollable List (nimVersionList). nimVersionList.addItem("3-Nim"); nimVersionList.addItem("4-Nim"); nimVersionList.addItem("5-Nim"); nimVersionList.select(0); add(nimVersionList); // Add scrollable List to GUI layout. add(new Label("How do you want the computer to play?")); // Add label to GUI layout. randomPlayChoice = new Choice(); // Create drop-down menu Choice list (randomPlayChoice). randomPlayChoice.addItem("Randomly"); randomPlayChoice.addItem("Intelligently"); randomPlayChoice.select(0); add(randomPlayChoice); // Add drop-down menu Choice list to GUI layout. add(new Label("How many counters to start with?")); // Add label to GUI layout. startCountersList = new List(8, false); // Create scrollable List (startCountersList). startCountersList.addItem("10"); startCountersList.addItem("11"); startCountersList.addItem("12"); startCountersList.addItem("13"); startCountersList.addItem("14"); startCountersList.addItem("15"); startCountersList.addItem("16"); startCountersList.addItem("17"); startCountersList.addItem("18"); startCountersList.addItem("19"); startCountersList.addItem("20"); startCountersList.addItem("21"); startCountersList.addItem("22"); startCountersList.addItem("23"); startCountersList.addItem("24"); startCountersList.addItem("25"); startCountersList.select(0); add(startCountersList); // Add scrollable List to GUI layout. add(new Label("Do you want to play first?")); // Add label to GUI layout. playFirstChoice = new Choice(); // Create drop-down menu Choice list (playFirstChoice). playFirstChoice.addItem("Yes"); playFirstChoice.addItem("No"); playFirstChoice.select(0); add(playFirstChoice); // Add drop-down menu Choice list to GUI layout. startGameButton = new Button("Start game"); // Create Button (StartGameButton). add(startGameButton); // Add Button to GUI layout. add(new Label("Select the number of counters to take:")); // Add label to GUI layout. CheckboxGroup chooseNumberGroup = new CheckboxGroup(); // Create CheckboxGroup (chooseNumberGroup). chooseNumberBox = new Checkbox[5]; // Create a list of five Checkboxes (chooseNumberBox) chooseNumberBox[0] = new Checkbox("One counter", chooseNumberGroup, false); // and group them together in chooseNumberGroup. chooseNumberBox[1] = new Checkbox("Two counters", chooseNumberGroup, false); chooseNumberBox[2] = new Checkbox("Three counters", chooseNumberGroup, false); chooseNumberBox[3] = new Checkbox("Four counters", chooseNumberGroup, false); // Additions for 5-Nim. chooseNumberBox[4] = new Checkbox("Five counters", chooseNumberGroup, false); for (int boxNum = 0; boxNum < 5; ++boxNum) // Add five Checkboxes to GUI layout. { add(chooseNumberBox[boxNum]); chooseNumberBox[boxNum].disable(); } computerMoveLabel = new Label(" "); // Create three labels, numberLeftLabel = new Label(" "); // initially all blank. gameOverLabel = new Label(" "); add(computerMoveLabel); // Add three labels to GUI layout, which add(numberLeftLabel); // will be filled in appropriately add(gameOverLabel); // during the play of the game. } private void startGame() // This method is called by the user action detection { // method (below), which starts the game. nimVersion3 = (nimVersionList.getSelectedItem() == "3-Nim"); // These three boolean variables are assigned the nimVersion4 = (nimVersionList.getSelectedItem() == "4-Nim"); // same truth value as the statement in parentheses. nimVersion5 = (nimVersionList.getSelectedItem() == "5-Nim"); if (nimVersion3) nimVersion = 3; // Capture the version of nim selected. if (nimVersion4) nimVersion = 4; if (nimVersion5) nimVersion = 5; startCounters = Integer.parseInt(startCountersList.getSelectedItem()); // Get the chosen value of startCounters (sticks) numLeft = startCounters; // and set numLeft = startCounters. computerRandom = (randomPlayChoice.getSelectedItem() == "Randomly"); // These two boolean variables are assigned the humanFirst = (playFirstChoice.getSelectedItem() == "Yes"); // same truth value as the statement in parentheses. for (int boxNum = 0; boxNum < nimVersion; ++boxNum) // Addition for choice of nim version. { chooseNumberBox[boxNum].enable(); // Enable chooseNumberBoxes, but make them chooseNumberBox[boxNum].setState(false); // unselected. } numberLeftLabel.setText(" There are " + numLeft + " counters left."); // Echo back the chosen number of counters (sticks). gameOverLabel.setText(" ");// Clear game over text--needed // if this is the 2nd time (or more) // the game is played. if (humanFirst) // If humanFirst = true, prompt user to move. computerMoveLabel.setText(" The computer is waiting for your move. "); // Otherwise, the computer should move first, else // so, call the computerMove() method. computerMove(); } private void computerMove() // This method is called by the user action detection { // method (below), or by the startGame() method (above). int numTake, maxTake; if (numLeft == 0) // If numLeft is 0 and computerMove() is called, then { // the user took the last one and lost the game. numberLeftLabel.setText(" There are 0 counters left. "); gameOverLabel.setText(" Game over. You lose! "); for (int boxNum = 0; boxNum < nimVersion; ++boxNum) // Addition for choice of nim version. { chooseNumberBox[boxNum].disable(); } return; } // Additions for choice of nim version. if (!computerRandom && (numLeft - 1) % (nimVersion + 1) != 0) // If the computer is supposed to play intelligently and { // the user didn't leave one more than a mulitple of nimVersion + 1, if (numLeft % (nimVersion + 1) == 0) numTake = nimVersion; // then the computer chooses a winning position. else numTake = (numLeft % (nimVersion + 1)) - 1; // Note that in the else clause: } // 2 < (numLeft % (nimVersion + 1)) < nimVersion. else // Otherwise, either the computer is supposed to play { // randomly or doesn't have a winning position. if (numLeft >= nimVersion) maxTake = nimVersion; // In either case, the computer just plays randomly. else maxTake = numLeft; numTake = (int)(maxTake * Math.random() + 1); } numLeft -= numTake; // Adjust numLeft and the report computerMoveLabel.setText(" The computer takes " + numTake + " counter(s). "); // the computer's move to the numberLeftLabel.setText(" There are " + numLeft + " counter(s) left. "); // user. for (int i = nimVersion; i >= 2; --i) // Additions for choice of nim version. { // If necessary disable some or if (numLeft < i) chooseNumberBox[i-1].disable(); // all of the chooseNumberBoxes. } if (numLeft == 0) { chooseNumberBox[0].disable(); gameOverLabel.setText(" Game over. You win! "); // Report that the user won the game. } } public boolean action(Event event, Object object) // Detect user action from the GUI (the game starts here). { if (event.target == startGameButton) // If the user clicks the startGameButton, startGame(); // then call the startGame() method. else if (event.target == chooseNumberBox[4]) // Otherwise, if the user makes a move, { // then update the numLeft variable, and numLeft -= 5; // call the computerMove() method. computerMove(); } else if (event.target == chooseNumberBox[3]) { numLeft -= 4; computerMove(); } else if (event.target == chooseNumberBox[2]) { numLeft -= 3; computerMove(); } else if (event.target == chooseNumberBox[1]) { numLeft -= 2; computerMove(); } else if (event.target == chooseNumberBox[0]) { numLeft -= 1; computerMove(); } return true; } }