Classic Computer Magazine Archive COMPUTE! ISSUE 89 / OCTOBER 1987 / PAGE 87

Nim: The Ultimate Binary Game

Jim Butterfield, Associate Editor

The Best way to beat the computer in this classic strategy game is to know how to convert numbers from decimal to binary. The accompanying program was written in Commodore BASIC and runson any Commodore eight-bit computer. With minor modifications, it could also be adapted to work with other versions of Microsoft BASIC.


"Nim" is one of the simplest games ever invented, yet successful play requires at least an intuitive grasp of binary numbers, the system used by all digital computers.

Here‘s how Nim is played. You take a bunch of objects (toothpicks, matches, coins, whatever) and arrange them randomly in three or more piles. You and your opponent alternate taking turns. During a turn, a player may take as many objects as he or she wishes from any one pile (but only from one pile). The player taking the last object wins.

That‘s a description of the standard game of Nim. Several variations exist. In one variation, the player taking the last object loses. In another, there is a maximum number of objects that may be taken during a turn. The program presented here plays all three versions of the game, switching the rules from one game to the next. Type the program in and save a copy before you run it. The program should run as listed on any eight–bit Commodore computer, and with minor modifications on any eight–bit computer.

Simple Play Theory

The classic game of Nim (last object wins, pick any number) has a very elegant playing strategy that requires knowledge of binary numbers. (If you are not familiar with the binary numbering system, see "From Decimal to Binary," accompanying this article.)

Count the number of objects in each pile, and write down each number, one above the other, in binary. For example, if there are three piles of objects, containing three, four and five objects, respectively, you would write

3		1	1
4	1	0	0
5	1	0	1

Note that the binary numbers are lined up on the right side, just as we would arrange conventional numbers. Now, you should ask, does every column (not row) have an even number of 1's in it?

If the answer is yes, you're stuck. The best you can do is make some random move and hope your opponent stumbles when he or she plays.

But if the answer is no, you have a winning play. The play is to take from a pile in such a way so that all columns have even parity— an even number of 1's.

Let's look at the example given above. The right column has two bits set, so that's even parity. The middle column has only one bit set. That's an odd number, so you have a winning play.

It takes some time, at first, to examine the possible moves. In this case, it turns out there's only one move that produces even parity. Here's the move: Take two from the first column, leaving

1			1
4	1	0	0
5	1	0	1

Examine the columns of the binary numbers, and you'll see that they all contain an even number of bits (zero or two in this case). Your opponent now has no satisfactory play.

Let's carry this game through to its conclusion. Suppose your opponent takes four objects from the largest column, leaving one. Line up the numbers again:

1			1
4	1	0	0
1			1

Your play to restore even parity is obvious. Grab the entire pile of four to leave:

1	1
0	0
1	1

What can your opponent do now? Not much. On the next turn, he or she must take the lone piece from either one of the piles, after which you will take the last object from the remaining pile and win.

Variations

The classic game has a clear and easy strategy. The task becomes more complex when we limit the number of objects that may be taken on each play. Extra difficulties arise when we decide that the player taking the last object will lose instead of win. But the basic game strategy remains, built upon a foundation of binary numbers.

I won't go into the extra theory and strategy here. If you're interested, you can examine the program to see what makes it such a good player.

The Good And The Bad

You might find it dull to play against a computer that wins every time, so the computer has been given an IQ. The computer asks at the beginning of the game if it should play the best it can. If you you reply N for no, it will sometimes make mistakes, giving even an inexperienced player a chance to win.

Even if you don't know binary, you can become skilled at this game—you'll begin to spot winning combinations. Be forewarned: Every time the computer loses a game, it becomes a better player. So the next game may not be as easy.

Eventually, if you master the theory of play, you will be able to beat the computer every time. That's because the computer, after setting up a random board, asks you whether you want the first move. If you have a good play, take the first move and make it. If you don't seem to have a good move, pass the first move to the computer.

Program Notes

One odd expression in the program implements exclusive OR. Unlike the standard OR operator, exclusive OR is true only when one operand is true and the other is false (the standard OR is also true when both operands are true). Exclusive OR can be simulated with the AND, OR, and NOT operators:

X = (A OR B) AND NOT(A AND B)

If your specialty is machine language, the 6502 processor has an exclusive OR (EOR) command built in.

If you are interested in figuring out how the program works, you'll need to understand the roles of some variables. R is the playing rule—if it is 1, the last player wins, if it is 0, the last player loses. N9 is the maximum number of objects you are allowed to pick up. If you are allowed to choose any number of objects, N9 is set to 99.

From Decimal To Binary

The binary numbering system is used by computers because each bit—the smallest unit of storage in a computer's memory—can have only two states, 0 or 1. These two states correspond to the off and on states of the electronic switches that make up the brain of the computer. Just as it is easy for us to do decimal (base 10) math with our fingers, so it is easy for computers to do binary (base 2) math.

The binary and decimal systems are just two different ways of looking at the same thing: numeric quantities. Instead of saying, "Look! There are seven (base 10) trees," we could just as correctly state, "Look! There are 111 (base 2) trees." The trick is learning how to convert from one base to another.

Perhaps the simplest way to convert from base 10 to base 2 is to construct a value box (at first on paper, but eventually in your head). Here's a value box that will convert numbers from 0 to 255 in decimal.

Now let's pick a number to be converted. We'll use 20.

Going from left to right, find the first number in the value box that is less than or equal to 20. In this case, the number is 16. Color in the box under the number 16.

We have represented 16 of the 20 objects that we wish to represent. Subtract 16 from 20—we have 4 more objects to represent. Continue scanning across from left to right. We pass 8, but since 4 is less than or equal to 4, we color in the box under the 4, When we subtract 4 from 4, we get 0, so we have now completed our conversion. All of the empty boxes represent 0s, and all of the filled boxes represent 1s. The result is 00010100. We can write binary numbers without leading zeros (those to the left of the first significant digit), so decimal 20 is 10100 in binary.

The array A() holds the playing board. P() is the original (previous) board, in case you want to play the same game over again. S() is a scrambling array, to give the computer's strategy a little variety. If the computer player has more than one possible winning move, it might pick either one, depending on the contents of S().

Playing Against Humans

If you play this game against another person, remember that psychology is an important part of your playing style. You should make your moves without hesitation if possible. This is especially true when you don't have a winning move—you don't want to tip off your opponent that you may be in trouble.

And don't take a piece of paper and start writing out numbers in binary. Learn to do it in your head. It's a good step to computer literacy.

Nim

For instructions on entering this program, please refer to "COMPUTE!'s Guide to Typing In Programs" elsewhere in this issue.

XQ	100	PRINT"{CLR}{2 DOWN}" : PRINT TAB(17)" "{RVS} NIM"
KE	110	 J = RND (-T1)
ED	120	 DIM A(5), P(5), S(5), N(5)
JK	130	 FOR J = 1 TO 4 : S(J) = J : NEXT J
ME	140	 H$ = "{HOME}{13 DOWN}"
EG	150	 C$ = H$ + "{35 SPACES}" + H$
EP	160	 PRINT CHR$(8);CHR$(142)
RH	170	 PRINT"RULES : "
MG	180	 PRINT"{2 SPACES} EACH PLAYER PICKS AS MANY ITEMS"
SG	190	 PRINT"{2 SPACES} AS DESIRED FROM ANY ONE ROW"
HD	200	 PRINT
GF	210	 PRINT"THE WINNER IS THE PLAYER WHO PICKS"
RB	220	 PRINT"THE LAST ITEM."
PG	230	 PRINT
ED	240	 PRINT"WE EACH PALY IN TURN."
DH	250	 PRINT
PX	260	 X$ = "N" : INPUT "SHOULD I PLAY MY BEST GAME" ;X$
QE	270	 I = .5 : IF X$ = "Y" OR X$ = "YES" THEN I = 1
HK	280	 PRINT
CD	290	 IF I = 1 THEN PRINT"PUNY {SPACE} HUMAN1{2 SPACES} YOU HAVEN'T A HOPE."
XX	300	 IF I < 1 THEN PRINT"MAYBE I'LL LET YOU WIN ONE OR TWO GAMES.
FC	310	 FOR J = 1 TO 500 : NEXT
RK	320	 R = 1 : N9 = 99
CB	330	 T = 0
HQ	340	 FOR J = 1 TO 4
XC	350	 A(J) = INT (RND(1) * 7 : T = T + A(J)
XR	360	 NEXT J
PS	370	 IF T < 4 THEN 330
EB	380	 FOR J = 1 TO 4
BA	390	 P(J) = A(J) : K = INT(RND(1) * 4) + 1
DG	400	 NEXT J
BG	420	 M = 0 : M0 = 0
MH	430	 PRINT"{CLR}{DOWN}PLAYER TAKING LAST ITEM";
SS	440	 IF R = 0 THEN PRINT "LOSES"
DB	450	 IF R = 1 THEN PRINT "WINS"
CE	460	 PRINT
GF	470	 IF N9 = 99 THEN PRINT "PICK AS MANY AS YOU LIKE"
EQ	480	 IF N9<99 THEN PRINT "YOU MAY PICK NO MORE THAN" ;N9
SH	490	 PRINT
XJ	500	 R9 = 0 : T6 = 0 : T8 : T9 = 0
SG	510	 FOR J = 1 TO 4
EB	520	 PRINT CHR$ (J + 64); " : ";
FQ	530	 FOR K = 1 TO 9
PR	540	 C = 209 : IF K>A(J) THEN C = 32
PF	550	 PRINT CHR$(C);"";
MM	560	 NEXT K
JE	570	 PRINT : PRINT
RM	580	 K = S(J)
MB	590	 N = INT (A(K) / (N9 + 1)) : N(K) = A(K) - N * (N9 + 1)
KJ	600	 IF N(K) = 1 THEN T8 = T8 + 1 : T3 = K
QF	610	 IF N(K)>1 THEN T9 = T9 + 1 : T4 = K
DF	620	 IF A(K)>T6 THEN T6 = A(K) : T5 = K
DR	630	 NEXT J
BB	640	 IF M>0 THEN 680
PE	650	 PRINT C$;
JF	660	 X$ = "N" : INPUT" DO YOU WANT THE FIRST MOVE";X$
BM	670	 IF X$ = "Y" OR X$ = "YES" THEN M0 = 1
RF	680	 M = M + 1 : IF M0 = 1 THEN 900
QJ	690	 T = 0
EM	700	 IF R = 1 THEN 770
KC	710	 IF T9 = 0 AND T8 = 0 THEN 800
QC	720	 J12 = T3 : IF T9>0 THEN J1 = T4
JA	730	 X = N(J1) : IF T8 = INT (T8/2) * 2 THEN X = X - 1
AX	740	 IF X = 0 THEN 770
BJ	750	 IF T9<2 THEN 870
BE	760	 REM CONVENTIONAL ANALYSIS
RK	770	 FOR J = 1 TO 4
KJ	780	 T = (T OR N(J)) AND NOT (TAND N(J))
BJ	790	 NEXT J
JR	800	 IF J1 = T5 : X = T6 : IF X>N9 THEN X = N9
HC	810	 IF T = 0 THEN 870
EM	820	 FOR J = 1 TO 4
KK	830	 K = S(J)
BM	840	 TO = (T OR N(K)) AND NOT (T AND N(K))
EF	850	 IF TO <N(K) AND (N(K) - T0)<N9 THEN J1 = K : X = N(K) - T 0
AQ	860	 NEXT J
KX	870	 IF RND (1)>I THEN X = INT(RND(1) * T6) + 1 : J1 = T5 : IF X>N9 THEN X = N9
BK	880	 PRINT C$; "I TAKE&rdqup; ;X; "FROM ROW";CHR$(J1 + 64)
GP	890	 GOTO 1000
EE	900	 PRINT C$;"CHOOSE A ROW {SPACE} (OR {RVS} G{OFF} TO GIVE UP) : ";
XE	910	 GET X$ : IF X$ = "" THEN910
KX	920	 IF X$ = "G" THEN MO = R : GOTO 1140
HC	930	 J1 = ASC(X$) - 64 : IF JL<1 OR J1>4 THEN 900
HG	940	 IF A (J1) = 0 THEN 900
FS	950	 PRINT C$;"HOW MANY FROM ROW"CHR$(64 + J1);" : &rdqup; :
BX	960	 GET X$ : IF X$ = "&dquo; THEN 960
BB	970	 X = ASC(X$) - 48 : IF x<0 OR {SPACE}X>9 THEN 960
GP	980	 IF X = 0 OR X>A(J1) OR X> N9 THEN PRINT "????" : FOR J = 1 TO 500 : NEXT : GOTO 900
CK	990	 PRINT X
EE	1000	 PRINT "{HOME} {2 DOWN}"
FJ	1010	 FOR K = 1 TO JI : PRINT : PRINT : NEXT K
CX	1020	 PRINT TAB (3);
BS	1030	 FOR K = 1 TO X : PRINT " - "; : NEXT K
JK	1040	 A(J1) = A(J1) - X
GG	1050	 T = 0
PX	1060	 FOR J = 1 TO 4
FR	1070	 IF A(J) < > 0 THEN T = 1
HS	1080	 NEXT J
PM	1090	 M0 = 1 - M0
PK	1100	 FOR J = 1 TO 750 : NEXT J
MB	1120	 PRINT "{HOME} {4 DOWN}"
AD	1130	 GOTO 500
JC	1140	 PRINT C$;
DR	1150	 IF R = M0 THEN W0 = W0 + 1 : PRINT "I WIN!"
GK	1160	 IF R < > M0 THEN W1 = W1 + 1 : PRINT "YOU WIN!"
JH	1170	 PRINT
MG	1180	 PRINT "THAT MAKES" W1; "GAME;"
DX	1190	 IF W1 < > 1 THEN PRINT"S"
PC	1200	 PRINT " FOR YOU"
CD	1210	 PRINT "AND";WO; "FOR ME."
BG	1220	 IF I<1 AND W1 > W0 AND R < > M0 AND R1 = 0 THEN GOSUB 1380
MJ	1230	 PRINT
JP	1240	 R1 = 0
GQ	1250	 X$ = "Y : " : INPUT "PLAY AGAIN" : X$
QB	1260	 IF X$ = "N" : OR X$ = "NO" THEN END
SC	1270	 X$ = "N" : INPUT "SAME GAME AS LAST TIME" ; X$
QJ	1280	 IF X$<> "N&rdquo AND X$ <> "NO" THEN 1350
CD	1290	 IF RND (1)>.35 THEN 330
SM	1300	 IF RND (1)>.6 THEN 1330
CC	1310	 R = 1 - R : R9 = 5 : PRINT : PRINT "{RVS} RULE CHANGE"
SG	1320	 FOR J = 1 TO 500 : NEXT J
CG	1330	 IF RND (1)<.6 THEN N9 = INT (RND(1) * 4) + 3 : IF N9>5 THEN N9 = 99
QB	1340	 GOTO 330
CC	1350	 R1 = 1
JC	1360	 FOR J = 1 TO 4 : A(J) = P(J) : NEXT J
MD	1370	 GOTO 420
RC	1380	 I = I↑.75
HG	1390	 PRINT "DON'T FEEL TOO SMART."
SE	1400	 PRINT "I CAN DO BETTER!"
RK	1410	 RETURN