Spring Semester 2003


Lecture Notes Fourteen: Computer Games. (In which Tigger has guests from another tale).
Have you ever played Nim? No. But do you play croquet?

I'd love to but I don't have the time. Well, how do you play Nim?

Allow me to describe it.

Very well, but please be very clear, my dear.

Yes, try to be very clear.

Nim is a well-known game with a number of variants. We will consider the following variant, which has an interesting winning strategy. Two players alternately take marbles from a pile. In each move, a player chooses how many marbles to take, then removes the marbles.

The player must take
  • at least one but
  • at most half
of the marbles.
Then the other player takes a turn.

You already said that. I thought you were sleeping.

This is very provoking... Sorry, dear. Ahem.

The player who takes the last marble loses.


You will write a program in which a computer plays agains a human opponent. Generate a random number between 10 and 100 to denote the initial size of the pile.

Generate a random integer between 0 and 1 to decide whether the computer or the human takes the first turn. Then start the game. This variant of the game has an interesting winning strategy. Careful thinking will reveal that whoever moves first can win.

How? Take off enough marbles to make the pile a power of two minus one, that is 1, 3, 7, 15, 31, or 63.

I see. One could program the computer to always play in what could be called smart mode.

That would not be too much fun for the user. One could also program the computer to always perform a random legal move.

That's what we'll do, as it seems a bit more fair. OK, let's get started.

First of all, what do we need? No pile of marbles, no Nim.

Let's bring one in. How does it look?

What do you think of this? Looks like a good start.
class PileOfMarbles {
  int height; 
  PileOfMarbles (int height) {
    this.height = height; 
  }
  int report() {
    return this.height;
  }
}

A pile of marbles is like a bank account. Whoever withdraws the last cent loses.

It has a balance (height). An a get balance (report) method.

We also need a withdraw, don't we? Yes, let's call it move.

What do you think of this? You have to be careful when withdrawing.
void move(int number) {
  System.out.println("***Removing " + number + " marbles from the pile."); 
  this.height -= number; 
  System.out.println("Pile of marbles is now: " + this.report());
} 

So how do you check that? How about this condition?
if (number <= 0 || ((number > height / 2) && (number != 1))) { 
  // then it's a bad move
} else {
  // it is a good move
}

Can I look at this again? You mean the check for a bad move?

Yes. Here it is (a bad move).
if (number <= 0 || ((number > height / 2) && (number != 1))) {
  System.out.println("***Bad move: you lose."); 
  System.exit(0); 
} else {
Or, just the condition, again:
(number <= 0 || ((number > height / 2) && (number != 1)))
Either zero marbles or less, ... ... or more than half, and not the last.

I think this last part is rather tricky. Using de Morgan's law we can reformulate this to represent a good move. Perhaps that would help.

Yes, let's write down its negation. Here it is (a good move):
(number > 0 && ((number <= height / 2) || (number == 1)))

To me this looks better, easier to understand. It does seem that way to me too.

Even if this is no easier to read than the first version you now have a choice, an option. I quite agree with that.

So we can finish report now. Yes. Let's make the pile of marble responsible for announcing the end of the game too.

Then it needs to know who moved. I think I can accommodate that.
void move(int number, String user) {
  System.out.println("***Removing " + number + 
                     " marbles from the pile for: " + user); 
  if (number <= 0 || ((number > height / 2) && (number != 1))) {
    System.out.println("***Bad move for " + user + ". " + 
                       user + " loses."); 
    System.exit(0); 
  } else {
    this.height -= number; 
    if (this.height == 0) {
       System.out.println("***End of game. " + user + " loses.");
       System.exit(0); 
    } 
  } 
  System.out.println("Pile of marbles is now: " + this.report());
}

That's pretty much it, isn't it? Yes. Now we need to set up the game.

We need a while loop. We need a loop, like we did in Echo, yes.

Here's my suggestion. Looks like you finished it altogether now.
int height = (int)(Math.random() * 90 + 10); 

PileOfMarbles pile = new PileOfMarbles(height); 

System.out.println("Game starts with a pile of height: " 
                   + pile.report());

int number, currentHeight; 

while (true) {

    System.out.println("*** Computer moves."); 

    System.out.println("Pile of marbles of height: " + pile.report()); 

    currentHeight = pile.report(); 

    if (currentHeight == 1) { 
      number = 1; 
    } else { 
      number = (int)(Math.random() * (currentHeight / 2)) + 1; 
    } 

    System.out.println("Computer chooses to remove: " + 
                       number + " marbles.");

    pile.move(number, "Computer"); 

    System.out.println("--------------------------"); 

    System.out.println("*** Now " + user + " has to move."); 

    System.out.println("Pile of marbles of height: " + pile.report()); 

    System.out.print(user + 
                     ", please enter number of marbles you want to take: "); 

    number = console.readInt(); 
               
    pile.move(number, user); 
               
    System.out.println("--------------------------"); 
               
}

Yes, here's the whole thing:
class Nim {
    public static void main(String[] args) {

	ConsoleReader console = new ConsoleReader(System.in);
	
	System.out.println("Hello, and welcome to the game of Nim!");
	System.out.print("What is your name: "); 
	String user = console.readLine(); 
	
	int height = (int)(Math.random() * 90 + 10); 
	
	PileOfMarbles pile = new PileOfMarbles(height); 
	
	System.out.println("Game starts with a pile of height: " 
			   + pile.report());
	
	int number, currentHeight; 
	
	while (true) {
	    
	    System.out.println("*** Computer moves."); 
	    
	    System.out.println("Pile of marbles of height: " + 
                               pile.report()); 
	    
	    currentHeight = pile.report(); 
	    
	    if (currentHeight == 1) { 
		number = 1; 
	    } else { 
		number = (int)(Math.random() * (currentHeight / 2)) + 1; 
	    } 
	    
	    System.out.println("Computer chooses to remove: " + 
			       number + " marbles.");
	    
	    pile.move(number, "Computer"); 
	    
	    System.out.println("--------------------------"); 
	    
	    System.out.println("*** Now " + user + " has to move."); 
	    
	    System.out.println("Pile of marbles of height: " + 
                               pile.report()); 
	    
	    System.out.print(user + 
                 ", please enter number of marbles you want to take: "); 
	    
	    number = console.readInt(); 
	    
	    pile.move(number, user); 
	    
	    System.out.println("--------------------------"); 
	    
	}
    }
}

class PileOfMarbles {
    int height; 
    PileOfMarbles (int height) {
	this.height = height; 
    }
    int report() {
	return this.height;
    }
    void move(int number, String user) {
	System.out.println("***Removing " + number + 
			   " marbles from the pile for: " + user); 
	if (number <= 0 || ((number > height / 2) && (number != 1))) {

	    System.out.println("***Bad move for " + user + ". " + 
			       user + " loses."); 

	    System.exit(0); 
	} else {
	    this.height -= number; 
	    if (this.height == 0) {
		System.out.println("***End of game. " + 
                                   user + " loses.");
		System.exit(0); 
	    } 
	} 
	System.out.println("Pile of marbles is now: " + this.report());
    }
}

Don't forget your ConsoleReader! I'm ready!

Let's play! (This is Problem Six-Seventeen).
frilled.cs.indiana.edu%javac Nim.java
frilled.cs.indiana.edu%java Nim
Hello, and welcome to the game of Nim!
What is your name: Mary-Ann
Game starts with a pile of height: 86
*** Computer moves.
Pile of marbles of height: 86
Computer chooses to remove: 23 marbles.
***Removing 23 marbles from the pile for: Computer
Pile of marbles is now: 63
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 63
Mary-Ann, please enter number of marbles you want to take: 30
***Removing 30 marbles from the pile for: Mary-Ann
Pile of marbles is now: 33
--------------------------
*** Computer moves.
Pile of marbles of height: 33
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
Pile of marbles is now: 32
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 32
Mary-Ann, please enter number of marbles you want to take: 16
***Removing 16 marbles from the pile for: Mary-Ann
Pile of marbles is now: 16
--------------------------
*** Computer moves.
Pile of marbles of height: 16
Computer chooses to remove: 7 marbles.
***Removing 7 marbles from the pile for: Computer
Pile of marbles is now: 9
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 9
Mary-Ann, please enter number of marbles you want to take: 2
***Removing 2 marbles from the pile for: Mary-Ann
Pile of marbles is now: 7
--------------------------
*** Computer moves.
Pile of marbles of height: 7
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
Pile of marbles is now: 6
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 6
Mary-Ann, please enter number of marbles you want to take: 3
***Removing 3 marbles from the pile for: Mary-Ann
Pile of marbles is now: 3
--------------------------
*** Computer moves.
Pile of marbles of height: 3
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
Pile of marbles is now: 2
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 2
Mary-Ann, please enter number of marbles you want to take: 1
***Removing 1 marbles from the pile for: Mary-Ann
Pile of marbles is now: 1
--------------------------
*** Computer moves.
Pile of marbles of height: 1
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
***End of game. Computer loses.
frilled.cs.indiana.edu%java Nim
Hello, and welcome to the game of Nim!
What is your name: Queen
Game starts with a pile of height: 77
*** Computer moves.
Pile of marbles of height: 77
Computer chooses to remove: 8 marbles.
***Removing 8 marbles from the pile for: Computer
Pile of marbles is now: 69
--------------------------
*** Now Queen has to move.
Pile of marbles of height: 69
Queen, please enter number of marbles you want to take: 33
***Removing 33 marbles from the pile for: Queen
Pile of marbles is now: 36
--------------------------
*** Computer moves.
Pile of marbles of height: 36
Computer chooses to remove: 11 marbles.
***Removing 11 marbles from the pile for: Computer
Pile of marbles is now: 25
--------------------------
*** Now Queen has to move.
Pile of marbles of height: 25
Queen, please enter number of marbles you want to take: 12
***Removing 12 marbles from the pile for: Queen
Pile of marbles is now: 13
--------------------------
*** Computer moves.
Pile of marbles of height: 13
Computer chooses to remove: 5 marbles.
***Removing 5 marbles from the pile for: Computer
Pile of marbles is now: 8
--------------------------
*** Now Queen has to move.
Pile of marbles of height: 8
Queen, please enter number of marbles you want to take: 1
***Removing 1 marbles from the pile for: Queen
Pile of marbles is now: 7
--------------------------
*** Computer moves.
Pile of marbles of height: 7
Computer chooses to remove: 2 marbles.
***Removing 2 marbles from the pile for: Computer
Pile of marbles is now: 5
--------------------------
*** Now Queen has to move.
Pile of marbles of height: 5
Queen, please enter number of marbles you want to take: 2
***Removing 2 marbles from the pile for: Queen
Pile of marbles is now: 3
--------------------------
*** Computer moves.
Pile of marbles of height: 3
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
Pile of marbles is now: 2
--------------------------
*** Now Queen has to move.
Pile of marbles of height: 2
Queen, please enter number of marbles you want to take: 1
***Removing 1 marbles from the pile for: Queen
Pile of marbles is now: 1
--------------------------
*** Computer moves.
Pile of marbles of height: 1
Computer chooses to remove: 1 marbles.
***Removing 1 marbles from the pile for: Computer
***End of game. Computer loses.

Oh, Nim is so easy. I like Nim.


frilled.cs.indiana.edu%java Nim
Hello, and welcome to the game of Nim!
What is your name: Mary-Ann
Game starts with a pile of height: 11
*** Computer moves.
Pile of marbles of height: 11
Computer chooses to remove: 4 marbles.
***Removing 4 marbles from the pile for: Computer
Pile of marbles is now: 7
--------------------------
*** Now Mary-Ann has to move.
Pile of marbles of height: 7
Mary-Ann, please enter number of marbles you want to take: 6
***Removing 6 marbles from the pile for: Mary-Ann
***Bad move for Mary-Ann. Mary-Ann loses.
frilled.cs.indiana.edu%

"Why, Mary Ann, what are you doing out here?

Run home this moment, and fetch me a pair of gloves and a fan! Quick, now!"


Last updated: Feb 23, 2003 by Adrian German for A201