I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

Nim Game

From Rosetta Code


Task
Nim Game
You are encouraged to solve this task according to the task description, using any language you may know.

Nim is a simple game where the second player - if they know the trick - will always win.

The game has only 3 rules.

  • start with 12 tokens
  • each player takes 1, 2, or 3 tokens in turn
  • the player who takes the last token wins.


To win every time, the second player simply takes 4 minus the number the first player took. So if the first player takes 1, the second takes 3 - if the first player takes 2, the second should take 2 - and if the first player takes 3, the second player will take 1.


Task

Design a simple Nim game where the human player goes first, and the computer always wins. The game should enforce the rules.

8080 Assembly[edit]

It may not be a very interesting game, but it assembles to only 222 bytes.

bdos:		equ	5		; CP/M syscalls
puts: equ 9
putch: equ 2
getch: equ 1
 
maxtokens: equ 12 ; you can change this for more tokens
 
org 100h
lxi d,nim
call outs
mvi b,maxtokens ; 12 tokens
gameloop: lxi d,tokens ; Show tokens
call outs
mov c,b
showtokens: dcr c
jm tokensdone
mvi a,'|'
call outa
jmp showtokens
tokensdone: lxi d,nl
call outs
lxi d,prompt ; Show prompt
call outs
readinput: call ina ; Read input
sui '1' ; Subtract '1' (lowest acceptable
jc wrong ; input)
cpi 3 ; range of values is [0..2]
jnc wrong
cmp b ; can't take more than there are either
jnc wrong
cma ; negate; -a = ~(a-1)
mov c,a ; keep value
add b ; subtract from tokens
mov b,a
mvi a,4 ; computer take 4-X tokens
add c
mov c,a
lxi d,response ; print how many I take
call outs
mvi a,'0'
add c
call outa
mov a,b ; subtract the ones I take
sub c
jz done ; if I took the last one, I won
mov b,a
lxi d,nl
call outs
call outs
jmp gameloop
done: lxi d,lose ; there's no win condition
jmp outs
;; Invalid input
wrong: lxi d,wronginp
call outs
jmp readinput
;; Read character into A and keep registers
ina: push b
push d
push h
mvi c,getch
call bdos
jmp restore
;; Print A and keep registers
outa: push b
push d
push h
mvi c,putch
mov e,a
call bdos
jmp restore
;; Print string and keep registers
outs: push b
push d
push h
mvi c,puts
call bdos
;; Restore registers
restore: pop h
pop d
pop b
ret
nim: db 'Nim',13,10,13,10,'$'
prompt: db 'How many will you take (1-3)? $'
response: db 13,10,'I take $'
tokens: db 'Tokens: $'
lose: db 13,10,'You lose!$'
nl: db 13,10,'$'
wronginp: db 8,7,32,8,'$' ; beep and erase choice

8086 Assembly[edit]

Translation of: 8080 Assembly

This is a decent demonstration of the greater versatility of the 8086 when compared to the 8080. Where the 8080 only allowed complex operations on its A register, the other registers being limited to loading, incrementing and decrementing, the 8086 allows most operations to use any registers as its operands, leading to much shorter assembly code for the same program.

The trade-off is a more complex instruction encoding, usually requiring two bytes per instruction, minus any immediate operands. But that is ultimately worth it: whereas the 8080 version takes 222 bytes, this 8086 Nim assembles to only 173 bytes, mostly as a result of the three-instruction pattern of "load data into A, do something with it, then store it elsewhere" simplifying to just one instruction to manipulate the data in place.


		;; MS-DOS Nim; assembles with nasm.
bits 16
cpu 8086
getch: equ 1
putch: equ 2
puts: equ 9 ; INT 21h calls
maxtokens: equ 12 ; Amount of tokens there are
section .text
org 100h
mov dx,nim ; Print sign-on
call outs
mov ch,maxtokens ; CH = amount of tokens we have
loop: mov dx,tokens ; Tokens: |||...
call outs
mov ah,putch ; Print a | for each token
mov dl,'|'
mov dh,ch
puttoks: int 21h
dec dh
jnz puttoks
mov dx,prompt ; Ask the user how many to take
call outs
ask: mov ah,getch ; Read keypress
int 21h
sub al,'1' ; Make number (minus one)
jc bad ; Carry, it was <1 (bad)
inc al ; Add 1 (because we subtracted '1')
cmp al,3
ja bad ; If it was >3, it is bad
cmp al,ch
ja bad ; If it was > amount left, it is bad
sub ch,al ; Remove your tokens from pile
mov cl,4 ; I take 4-N, which is 3-N-1
sub cl,al
sub ch,cl ; Remove my tokens from pile
mov dx,response ; Tell the user how many I took.
call outs
mov dl,'0'
add dl,cl
mov ah,putch
int 21h
cmp ch,0 ; Are there any tokens left?
jne loop ; If not, prompt again
mov dx,lose ; But otherwise, you've lost
; Fall through into print string routine and then stop.
;; Print string in DX. (This saves a byte each CALL)
outs: mov ah,puts
int 21h
ret
;; Input is bad; beep, erase, ask again
bad: mov dx,wronginp
call outs
jmp ask
section .data
nim: db 'Nim$'
prompt: db 13,10,'How many will you take (1-3)? $'
response: db 13,10,'I take $'
tokens: db 13,10,13,10,'Tokens: $'
lose: db 13,10,'You lose!$'
wronginp: db 8,7,32,8,'$'

Ada[edit]

Works with: Ada version 2012
with Ada.Text_IO;
 
procedure Nim is
subtype Token_Range is Positive range 1 .. 3;
 
package TIO renames Ada.Text_IO;
package Token_IO is new TIO.Integer_IO(Token_Range);
 
procedure Get_Tokens(remaining : in Natural; how_many : out Token_Range) is
begin
loop
TIO.Put("How many tokens would you like to take? ");
begin
Token_IO.Get(TIO.Standard_Input, how_many);
exit when how_many < remaining;
raise Constraint_Error;
exception
when TIO.Data_Error | Constraint_Error =>
if not TIO.End_Of_Line(TIO.Standard_Input) then
TIO.Skip_Line(TIO.Standard_Input);
end if;
TIO.Put_Line("Invalid input.");
end;
end loop;
end;
 
tokens : Natural := 12;
how_many : Token_Range;
begin
loop
TIO.Put_Line(tokens'Img & " tokens remain.");
-- no exit condition here: human cannot win.
Get_Tokens(tokens, how_many);
TIO.Put_Line("Human takes" & how_many'Img & " tokens.");
tokens := tokens - how_many;
-- computer's turn: take the remaining N tokens to amount to 4.
how_many := tokens mod 4;
TIO.Put_Line("Computer takes" & how_many'Img & " tokens.");
tokens := tokens - how_many;
Ada.Text_IO.New_Line;
exit when tokens = 0;
end loop;
 
TIO.Put_Line("Computer won!");
end Nim;
Output:
 12 tokens remain.
How many tokens would you like to take? a
Invalid input.
How many tokens would you like to take? 1
Human takes 1 tokens.
Computer takes 3 tokens.

 8 tokens remain.
How many tokens would you like to take? 2
Human takes 2 tokens.
Computer takes 2 tokens.

 4 tokens remain.
How many tokens would you like to take? 3
Human takes 3 tokens.
Computer takes 1 tokens.

Computer won!

Algol-M[edit]

 
BEGIN
 
PROCEDURE WELCOME;
BEGIN
WRITE("THE GAME OF NIM");
WRITE("");
WRITE("WE BEGIN WITH 12 TOKENS. ON EACH TURN, A");
WRITE("PLAYER MAY TAKE BETWEEN 1 AND 3 TOKENS.");
WRITE("THE PLAYER WHO TAKES THE LAST TOKEN WINS.");
WRITE("");
END;
 
PROCEDURE SHOW(N);
INTEGER N;
BEGIN
WRITE("REMAINING TOKENS:",N);
END;
 
INTEGER FUNCTION GETNUM(LOWLIM, TOPLIM);
INTEGER LOWLIM, TOPLIM;
BEGIN
INTEGER OK, N;
OK := 0;
WHILE OK = 0 DO
BEGIN
WRITE("YOU TAKE:");
READ(N);
IF N < LOWLIM OR N > TOPLIM THEN
BEGIN
WRITE("MUST TAKE BETWEEN",LOWLIM," AND",TOPLIM,".");
WRITE("TRY AGAIN.");
END
ELSE
OK := 1;
END;
GETNUM := N;
END;
 
INTEGER FUNCTION PLAY(PLAYER, TOKENS, TAKEN);
INTEGER PLAYER, TOKENS, TAKEN;
BEGIN
IF PLAYER = 1 THEN  % HUMAN PLAYER'S MOVE %
TAKEN := GETNUM(1,3)
ELSE  % MACHINE'S MOVE %
TAKEN := 4 - TAKEN;
PLAY := TAKEN;
END;
 
PROCEDURE REPORT(WINNER);
INTEGER WINNER; % MACHINE = 0, HUMAN = 1 %
BEGIN
IF WINNER = 0 THEN
WRITE("I TOOK THE LAST ONE, SO I WIN. SORRY ABOUT THAT.")
ELSE
WRITE("YOU TOOK THE LAST ONE. YOU WIN. CONGRATULATIONS!");
END;
 
% MAIN CODE BEGINS HERE %
 
INTEGER PLAYER, TOKENS, TAKEN, HUMAN, MACHINE;
 
MACHINE := 0;
HUMAN := 1;
TOKENS := 12;
TAKEN := 0;
PLAYER := HUMAN;
WELCOME;
WRITE("YOU GO FIRST.");
WHILE TOKENS > 0 DO
BEGIN
SHOW(TOKENS);
TAKEN := PLAY(PLAYER, TOKENS, TAKEN);
TOKENS := TOKENS - TAKEN;
IF PLAYER = MACHINE THEN WRITE("I TOOK:",TAKEN);
IF TOKENS > 0 THEN PLAYER := 1 - PLAYER;
END;
REPORT(PLAYER);
WRITE("THANKS FOR PLAYING!");
 
END
Output:
THE GAME OF NIM

WE GEGIN WITH 12 TOKENS. ON EACH TURN, A
PLAYER MAY TAKE BETWEEN 1 AND 3 TOKENS.
THE PLAYER WHO TAKES THE LAST TOKEN WINS.

YOU GO FIRST.
REMAINING TOKENS:    12
YOU TAKE:
-> 4
MUST TAKE BETWEEN     1 AND     3.
TRY AGAIN.
YOU TAKE:
-> 3
REMAINING TOKENS:     9
I TOOK:     1
REMAINING TOKENS:     8
YOU TAKE:
->2
REMAINING TOKENS:     6
I TOOK:     2
REMAINING TOKENS:     4
YOU TAKE:
-> 1
REMAINING TOKENS:     3
I TOOK:     3
I TOOK THE LAST ONE, SO I WIN. SORRY ABOUT THAT.
THANKS FOR PLAYING!

AsciiDots[edit]

 
%$LMRTX
.-$"Nim Dots"-$""-
 
/$_"Number must be "\
T /----~------\ |
*M /---+-*-[o] | |
R [-]\ .>#3-+[>][<]-1#<.| |
.-#12>--^ \"stod "$-#_$-" ekat uoY"_$---/ \--*----*-/ |
.>$_"How many dots would you like to take"---#?---/ |
\X X---------<".3 dna 1 neewteb"$/
/-----*L |
[-]--\ R |
| *-$_"Computer takes "-$_#-$" dots"/
M-*#4[%]
\---/
 
/----------------$"computer wins!"-&
/---~--
*#0[=]
L-------------*---*>$_#-$" dots remaining."-$""
T
 
Output:
Nim Dots

How many dots would you like to take?: 3
You take 3 dots
9 dots remaining.

Computer takes 1 dots
8 dots remaining.

How many dots would you like to take?: 1
You take 1 dots
7 dots remaining.

Computer takes 3 dots
4 dots remaining.

How many dots would you like to take?: 2
You take 2 dots
2 dots remaining.

Computer takes 2 dots
0 dots remaining.

computer wins!

AWK[edit]

 
# syntax: GAWK -f NIM_GAME.AWK
BEGIN {
tokens = 12
printf("Nim game - using %d tokens\n",tokens)
while (tokens > 0) {
for (;;) {
printf("how many tokens 1-3? ")
getline ans
if (ans ~ /^[123]$/) {
tokens -= ans
prn("player")
break
}
print("invalid input, try again")
}
tokens -= ans = tokens % 4
prn("computer")
}
print("computer wins")
exit(0)
}
function prn(who) {
printf("%s takes %d token%s; there are %d remaining\n",who,ans,(ans==1)?"":"s",tokens)
}
 
Output:
Nim game - using 12 tokens
how many tokens 1-3? 1
player takes 1 token; there are 11 remaining
computer takes 3 tokens; there are 8 remaining
how many tokens 1-3? 2
player takes 2 tokens; there are 6 remaining
computer takes 2 tokens; there are 4 remaining
how many tokens 1-3? 3
player takes 3 tokens; there are 1 remaining
computer takes 1 token; there are 0 remaining
computer wins

BlooP[edit]

Bloop has no input capabilites, so the game is defined as a procedure, called with 3 numbers (since the game will last only 3 rounds anyhow). The procedure can be called with more numbers - extra parameters are ignored in most implementations I have found. Since there is no easy way to get more inputs, any incorrect values are converted to correct ones.

 
DEFINE PROCEDURE ''DIVIDE'' [A,B]:
BLOCK 0: BEGIN
IF A < B, THEN:
QUIT BLOCK 0;
CELL(0) <= 1;
OUTPUT <= 1;
LOOP AT MOST A TIMES:
BLOCK 2: BEGIN
IF OUTPUT * B = A, THEN:
QUIT BLOCK 0;
OUTPUT <= OUTPUT + 1;
IF OUTPUT * B > A, THEN:
BLOCK 3: BEGIN
OUTPUT <= CELL(0);
QUIT BLOCK 0;
BLOCK 3: END;
CELL(0) <= OUTPUT;
BLOCK 2: END;
BLOCK 0: END.
 
DEFINE PROCEDURE ''MINUS'' [A,B]:
BLOCK 0: BEGIN
IF A < B, THEN:
QUIT BLOCK 0;
LOOP AT MOST A TIMES:
BLOCK 1: BEGIN
IF OUTPUT + B = A, THEN:
QUIT BLOCK 0;
OUTPUT <= OUTPUT + 1;
BLOCK 1: END;
BLOCK 0: END.
 
DEFINE PROCEDURE ''MODULUS'' [A,B]:
BLOCK 0: BEGIN
CELL(0) <= DIVIDE[A,B];
OUTPUT <= MINUS[A,CELL(0) * B];
BLOCK 0: END.
 
DEFINE PROCEDURE ''PLAYER_TURN'' [TOKENS_LEFT, TAKE]:
BLOCK 0: BEGIN
CELL(0) <= TAKE;
 
IF TAKE > 3, THEN:
BLOCK 1: BEGIN
CELL(0) <= MODULUS [TAKE, 3] + 1;
PRINT ['take must be between 1 and 3. setting take to ', CELL(0), '.'];
BLOCK 1: END;
 
IF TAKE < 1, THEN:
BLOCK 2: BEGIN
CELL(0) <= 1;
PRINT ['take must be between 1 and 3. setting take to 1.'];
BLOCK 2: END;
 
OUTPUT <= MINUS [TOKENS_LEFT, CELL(0)];
 
PRINT ['player takes ', CELL(0), ' tokens.'];
PRINT ['tokens remaining: ', OUTPUT];
PRINT [''];
BLOCK 0: END.
 
DEFINE PROCEDURE ''COMPUTER_TURN'' [TOKENS_LEFT]:
BLOCK 0: BEGIN
CELL(0) <= MODULUS [TOKENS_LEFT, 4];
OUTPUT <= MINUS [TOKENS_LEFT, CELL(0)];
 
PRINT ['computer takes ', CELL(0), ' tokens.'];
PRINT ['tokens remaining: ', OUTPUT];
PRINT [''];
BLOCK 0: END.
 
DEFINE PROCEDURE ''PLAY_GAME'' [FST, SEC, THD]:
BLOCK 0: BEGIN
CELL(0) <= FST;
CELL(1) <= SEC;
CELL(2) <= THD;
OUTPUT <= 12;
 
LOOP 3 TIMES:
BLOCK 1: BEGIN
OUTPUT <= PLAYER_TURN [OUTPUT, CELL(0)];
CELL(0) <= CELL(1);
CELL(1) <= CELL(2);
 
OUTPUT <= COMPUTER_TURN [OUTPUT];
BLOCK 1: END;
 
PRINT ['computer wins!'];
BLOCK 0: END.
 
PLAY_GAME [1,4,3];
 
Output:

Sample game:

 > PLAYER TAKES 1 TOKENS.
 > TOKENS REMAINING: 11
 > 
 > COMPUTER TAKES 3 TOKENS.
 > TOKENS REMAINING: 8
 > 
 > TAKE MUST BE BETWEEN 1 AND 3. SETTING TAKE TO 2.
 > PLAYER TAKES 2 TOKENS.
 > TOKENS REMAINING: 6
 > 
 > COMPUTER TAKES 2 TOKENS.
 > TOKENS REMAINING: 4
 > 
 > PLAYER TAKES 3 TOKENS.
 > TOKENS REMAINING: 1
 > 
 > COMPUTER TAKES 1 TOKENS.
 > TOKENS REMAINING: 0
 > 
 > COMPUTER WINS!
=> 0

C[edit]

 
#include <stdio.h>
 
int playerTurn(int numTokens, int take);
int computerTurn(int numTokens);
 
int main(void)
{
printf("Nim Game\n\n");
 
int Tokens = 12;
 
while(Tokens > 0)
{
printf("How many tokens would you like to take?: ");
 
int uin;
scanf("%i", &uin);
 
int nextTokens = playerTurn(Tokens, uin);
 
if (nextTokens == Tokens)
{
continue;
}
 
Tokens = nextTokens;
 
Tokens = computerTurn(Tokens);
}
printf("Computer wins.");
 
return 0;
}
 
int playerTurn(int numTokens, int take)
{
if (take < 1 || take > 3)
{
printf("\nTake must be between 1 and 3.\n\n");
return numTokens;
}
int remainingTokens = numTokens - take;
 
printf("\nPlayer takes %i tokens.\n", take);
printf("%i tokens remaining.\n\n", remainingTokens);
 
return remainingTokens;
}
 
int computerTurn(int numTokens)
{
int take = numTokens % 4;
int remainingTokens = numTokens - take;
 
printf("Computer takes %u tokens.\n", take);
printf("%i tokens remaining.\n\n", remainingTokens);
 
return remainingTokens;
}
 
Output:

Sample game:

Nim Game

How many tokens would you like to take?: 4
Take must be between 1 and 3.

How many tokens would you like to take?: 2
Player takes 2 tokens.
10 tokens remaining.

Computer takes 2 tokens.
8 tokens remaining.

How many tokens would you like to take?: 1
Player takes 1 tokens.
7 tokens remaining.

Computer takes 3 tokens.
4 tokens remaining.

How many tokens would you like to take?: 3
Player takes 3 tokens.
1 tokens remaining.

Computer takes 1 tokens.
0 tokens remaining.

Computer wins.

C++[edit]

Translation of: Go
#include <iostream>
#include <limits>
 
using namespace std;
 
void showTokens(int tokens) {
cout << "Tokens remaining " << tokens << endl << endl;
}
 
int main() {
int tokens = 12;
while (true) {
showTokens(tokens);
cout << " How many tokens 1, 2 or 3? ";
int t;
cin >> t;
if (cin.fail()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << endl << "Invalid input, try again." << endl << endl;
} else if (t < 1 || t > 3) {
cout << endl << "Must be a number between 1 and 3, try again." << endl << endl;
} else {
int ct = 4 - t;
string s = (ct > 1) ? "s" : "";
cout << " Computer takes " << ct << " token" << s << endl << endl;
tokens -= 4;
}
if (tokens == 0) {
showTokens(0);
cout << " Computer wins!" << endl;
return 0;
}
}
}
Output:

Sample game:

Tokens remaining 12

  How many tokens 1, 2 or 3? nim

Invalid input, try again.

Tokens remaining 12

  How many tokens 1, 2 or 3? 1
  Computer takes 3 tokens

Tokens remaining 8

  How many tokens 1, 2 or 3? 0

Must be a number between 1 and 3, try again.

Tokens remaining 8

  How many tokens 1, 2 or 3? 2
  Computer takes 2 tokens

Tokens remaining 4

  How many tokens 1, 2 or 3? 3
  Computer takes 1 token

Tokens remaining 0

  Computer wins!

C#[edit]

 
using System;
 
namespace nimGame
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("There are twelve tokens.\n" +
"You can take 1, 2, or 3 on your turn.\n" +
"Whoever takes the last token wins.\n");
 
int tokens = 12;
 
while (tokens > 0)
{
Console.WriteLine("There are " + tokens + " remaining.");
Console.WriteLine("How many do you take?");
int playertake = Convert.ToInt32(Console.ReadLine());
 
if (playertake < 1 | playertake > 3)
{
Console.WriteLine("1, 2, or 3 only.");
}
else
{
tokens -= playertake;
Console.WriteLine("I take " + (4 - playertake) + ".");
tokens -= (4 - playertake);
}
}
Console.WriteLine("I win again.");
Console.ReadLine();
}
 
}
}
 
Output:

Sample game:

There are twelve tokens.
You can take 1, 2, or 3 on your turn.
Whoever takes the last token wins.

There are 12 remaining.
How many do you take?
3
I take 1.
There are 8 remaining.
How many do you take?
1
I take 3.
There are 4 remaining.
How many do you take?
2
I take 2.
I win again.


Common Lisp[edit]

 
(defun pturn (curTokens)
(write-string "How many tokens would you like to take?: ")
(setq ans (read))
(setq tokensRemaining (- curTokens ans))
(format t "You take ~D tokens~%" ans)
(printRemaining tokensRemaining)
tokensRemaining)
 
(defun cturn (curTokens)
(setq take (mod curTokens 4))
(setq tokensRemaining (- curTokens take))
(format t "Computer takes ~D tokens~%" take)
(printRemaining tokensRemaining)
tokensRemaining)
 
(defun printRemaining (remaining)
(format t "~D tokens remaining~%~%" remaining))
 
 
(format t "LISP Nim~%~%")
(setq tok 12)
(loop
(setq tok (pturn tok))
(setq tok (cturn tok))
(if (<= tok 0)
(return)))
(write-string "Computer wins!")
 
Output:
LISP Nim

How many tokens would you like to take?: 2
You take 2 tokens
10 tokens remaining

Computer takes 2 tokens
8 tokens remaining

How many tokens would you like to take?: 1
You take 1 tokens
7 tokens remaining

Computer takes 3 tokens
4 tokens remaining

How many tokens would you like to take?: 3
You take 3 tokens
1 tokens remaining

Computer takes 1 tokens
0 tokens remaining

Computer wins!

Crystal[edit]

tokens = 12
 
until tokens <= 0
puts "There are #{tokens} tokens remaining.\nHow many tokens do you take?"
until (input = (gets || "").to_i?) && (1..3).includes? input
puts "Enter an integer between 1 and 3."
end
puts "Player takes #{input} tokens.\nComputer takes #{4-input} tokens."
tokens -= 4
end
 
puts "Computer wins."

Factor[edit]

USING: interpolate io kernel math math.parser sequences ;
IN: rosetta-code.nim-game
 
: get-input ( -- n )
"Number of tokens to take (1, 2, or 3): " write readln
string>number dup { 1 2 3 } member?
[ drop "Invalid move." print get-input ] unless ;
 
: .remaining ( n -- )
nl [I -~~==[ ${} tokens remaining ]==~~-I] nl nl ;
 
: .choice ( str n -- )
dup 1 = "" "s" ? [I ${} took ${} token${}I] nl ;
 
: (round) ( -- )
"You" get-input "Computer" 4 pick - [ .choice ] [email protected] ;
 
: round ( n -- n-4 )
dup dup .remaining [ drop (round) 4 - round ] unless-zero ;
 
: nim-game ( -- ) 12 round drop "Computer wins!" print ;
 
MAIN: nim-game
Output:
-~~==[ 12 tokens remaining ]==~~-

Number of tokens to take (1, 2, or 3): 1
You took 1 token
Computer took 3 tokens

-~~==[ 8 tokens remaining ]==~~-

Number of tokens to take (1, 2, or 3): 3
You took 3 tokens
Computer took 1 token

-~~==[ 4 tokens remaining ]==~~-

Number of tokens to take (1, 2, or 3): 4
Invalid move.
Number of tokens to take (1, 2, or 3): 2
You took 2 tokens
Computer took 2 tokens

-~~==[ 0 tokens remaining ]==~~-

Computer wins!

FreeBASIC[edit]

dim as ubyte heap=12, take
 
while heap > 0
print using "There are ## tokens remaining. How many would you like to take?"; heap
input take
while take=0 orelse take>3
print "You must take 1, 2, or 3 tokens. How many would you like to take?"
input take
wend
 
print using "On my turn I will take ## tokens."; 4-take
heap = heap - 4
wend
 
print "I got the last token. I win! Better luck next time."

Go[edit]

package main
 
import (
"bufio"
"fmt"
"os"
"strconv"
)
 
func showTokens(tokens int) {
fmt.Println("Tokens remaining", tokens, "\n")
}
 
func main() {
tokens := 12
scanner := bufio.NewScanner(os.Stdin)
for {
showTokens(tokens)
fmt.Print(" How many tokens 1, 2 or 3? ")
scanner.Scan()
if scerr := scanner.Err(); scerr != nil {
fmt.Println("Error reading standard input:", scerr)
return
}
t, err := strconv.Atoi(scanner.Text())
if err != nil || t < 1 || t > 3 {
fmt.Println("\nMust be a number between 1 and 3, try again.\n")
} else {
ct := 4 - t
s := "s"
if ct == 1 {
s = ""
}
fmt.Print(" Computer takes ", ct, " token", s, "\n\n")
tokens -= 4
}
if tokens == 0 {
showTokens(0)
fmt.Println(" Computer wins!")
return
}
}
}
Output:

Sample game:

Tokens remaining 12 

  How many tokens 1, 2 or 3? 2
  Computer takes 2 tokens

Tokens remaining 8 

  How many tokens 1, 2 or 3? 4

Must be a number between 1 and 3, try again.

Tokens remaining 8 

  How many tokens 1, 2 or 3? 1
  Computer takes 3 tokens

Tokens remaining 4 

  How many tokens 1, 2 or 3? 3
  Computer takes 1 token

Tokens remaining 0 

  Computer wins!

IS-BASIC[edit]

100 PROGRAM "Nim.bas"
110 RANDOMIZE
120 CLEAR SCREEN
130 LET TOKENS=12
140 PRINT "Starting with";TOKENS;"tokens.":PRINT
150 DO
160 PRINT "How many tokens will you take? (1-3) ";
170 DO
180 LET K=VAL(INKEY$)
190 LOOP UNTIL K>0 AND K<4
200 LET TOKENS=MAX(TOKENS-K,0):LET G=0
210 PRINT K:PRINT TAB(19);TOKENS;"remainig.":PRINT
220 IF TOKENS>0 THEN
230 LET L=MOD(TOKENS,4)
240 IF L=0 THEN LET L=MIN(RND(3)+1,TOKENS)
250 LET TOKENS=TOKENS-L:LET G=-1
260 PRINT "Computer takes";L;"tokens.";TOKENS;"remaining.":PRINT
270 END IF
280 LOOP WHILE TOKENS>0
290 IF G THEN
300 PRINT "Computer wins!"
310 ELSE
320 PRINT "You win!"
330 END IF

Haskell[edit]

import Data.Char (isDigit, digitToInt)
import System.IO
 
prompt :: String
prompt = "How many do you take? 1, 2 or 3? "
 
getPlayerSelection :: IO Int
getPlayerSelection = do
hSetBuffering stdin NoBuffering
c <- getChar
putChar '\n'
if isDigit c && digitToInt c <= 3 then
pure (digitToInt c)
else do
putStrLn "Invalid input"
putStr prompt
getPlayerSelection
 
play :: Int -> IO ()
play n = do
putStrLn $ show n ++ token n ++ " remain."
if n == 0 then putStrLn "Computer Wins!"
else do
putStr prompt
playerSelection <- getPlayerSelection
let computerSelection
| playerSelection > 4 = playerSelection - 4
| otherwise = 4 - playerSelection
putStrLn $ "Computer takes " ++ show computerSelection ++ token computerSelection ++ ".\n"
play (n - computerSelection - playerSelection)
where token 1 = " token"
token _ = " tokens"
 
main :: IO ()
main = play 12
Output:
12 tokens remain.
How many do you take? 1, 2 or 3? 3
Computer takes 1 token.

8 tokens remain.
How many do you take? 1, 2 or 3? 2
Computer takes 2 tokens.

4 tokens remain.
How many do you take? 1, 2 or 3? 1
Computer takes 3 tokens.

0 tokens remain.
Computer Wins!

Java[edit]

 
import java.util.Scanner;
 
public class NimGame {
 
public static void main(String[] args) {
runGame(12);
}
 
private static void runGame(int tokens) {
System.out.printf("Nim game.%n%n");
 
Scanner in = new Scanner(System.in);;
 
do {
boolean humanInputOk = false;
int humanTokens = 0;
while ( ! humanInputOk ) {
System.out.printf("Human takes how many tokens? ");
String input = in.next();
try {
humanTokens = Integer.parseInt(input);
if ( humanTokens >= 1 && humanTokens <= 3 ) {
humanInputOk = true;
}
else {
System.out.printf("Try a number between 1 and 3.%n");
}
}
catch (NumberFormatException e) {
System.out.printf("Invalid input. Try a number between 1 and 3.%n");
}
}
 
tokens -= humanTokens;
 
System.out.printf("You take %d token%s.%n%d token%s remaining.%n%n", humanTokens, humanTokens > 1 ? "s" : "", tokens, tokens != 1 ? "s" : "");
if ( tokens == 0 ) {
System.out.printf("You win!!.%n%n");
break;
}
int computerTokens = 4 - humanTokens;
tokens -= computerTokens;
 
System.out.printf("Computer takes %d token%s.%n%d token%s remaining.%n%n", computerTokens, computerTokens != 1 ? "s" : "", tokens, tokens != 1 ? "s" : "");
if ( tokens == 0 ) {
System.out.printf("Computer wins!!.%n%n");
}
 
} while (tokens > 0);
 
in.close();
}
 
}
 
Output:

Sample game:

Nim game.

Human takes how many tokens?  nim
Invalid input.  Try a number between 1 and 3.
Human takes how many tokens?  0
Try a number between 1 and 3.
Human takes how many tokens?  2
You take 2 tokens.
10 tokens remaining.

Computer takes 2 tokens.
8 tokens remaining.

Human takes how many tokens?  1
You take 1 token.
7 tokens remaining.

Computer takes 3 tokens.
4 tokens remaining.

Human takes how many tokens?  3
You take 3 tokens.
1 token remaining.

Computer takes 1 token.
0 tokens remaining.

Computer wins!!.

JavaScript[edit]

Browser Version[edit]

This is the easy but dirty way - with prompt for input, and console.log for output. The Nim class was structured so that input and output could be customized, for example to use HTML DOM elements for in and out, instead of the terminal.

 
class Nim {
constructor(tokens, printFun) {
this.startTokens = tokens;
this.tokens = tokens;
this.printFun = printFun;
}
 
playerTurn(take) {
take = Math.round(take);
 
if (take < 1 || take > 3) {
this.printFun("take must be between 1 and 3.\n")
return false;
}
this.tokens -= take;
this.printFun("Player takes " + take + " tokens.");
this.printRemaining()
 
if (this.tokens === 0) {
this.printFun("Player wins!\n");
}
return true;
}
 
computerTurn() {
let take = this.tokens % 4;
this.tokens -= take;
this.printFun("Computer takes " + take + " tokens.");
this.printRemaining();
 
if (this.tokens === 0) {
this.printFun("Computer wins.\n");
}
 
}
 
printRemaining() {
this.printFun(this.tokens + " tokens remaining.\n");
}
}
 
 
let game = new Nim(12, console.log);
while (true) {
if (game.playerTurn(parseInt(prompt("How many tokens would you like to take?")))){
game.computerTurn();
}
if (game.tokens == 0) {
break;
}
}
 
Output:

Sample game:

(prompt) How many tokens would you like to take? 2
Player takes 2 tokens.
10 tokens remaining.

Computer takes 2 tokens.
8 tokens remaining.

(prompt) How many tokens would you like to take? 4
take must be between 1 and 3.

(prompt) How many tokens would you like to take? 0
take must be between 1 and 3.

(prompt) How many tokens would you like to take? 3
Player takes 3 tokens.
5 tokens remaining.

Computer takes 1 tokens.
4 tokens remaining.

(prompt) How many tokens would you like to take? 1
Player takes 1 tokens.
3 tokens remaining.

Computer takes 3 tokens.
0 tokens remaining.

Computer wins.

Julia[edit]

Translation of: Raku
function nimgame()
tcount = 12
takenum = 0
while true
while true
permitted = collect(1:min(3,tcount))
println("$tcount tokens remain.\nHow many do you take ($permitted)? ")
takenum = parse(Int, strip(readline(stdin)))
if takenum in permitted
break
end
end
tcount -= 4
println("Computer takes $(4 - takenum). There are $tcount tokens left.")
if tcount < 1
println("Computer wins as expected.")
break
end
end
end
 
nimgame()
 
Output:
12 tokens remain.
How many do you take ([1, 2, 3])?
3
Computer takes 1. There are 8 tokens left.
8 tokens remain.
How many do you take ([1, 2, 3])?
2
Computer takes 2. There are 4 tokens left.
4 tokens remain.
How many do you take ([1, 2, 3])?
1
Computer takes 3. There are 0 tokens left.
Computer wins as expected.

Kotlin[edit]

Translation of: Go
// Version 1.3.21
 
fun showTokens(tokens: Int) {
println("Tokens remaining $tokens\n")
}
 
fun main() {
var tokens = 12
while (true) {
showTokens(tokens)
print(" How many tokens 1, 2 or 3? ")
var t = readLine()!!.toIntOrNull()
if (t == null || t < 1 || t > 3) {
println("\nMust be a number between 1 and 3, try again.\n")
} else {
var ct = 4 - t
var s = if (ct > 1) "s" else ""
println(" Computer takes $ct token$s\n")
tokens -= 4
}
if (tokens == 0) {
showTokens(0)
println(" Computer wins!")
return
}
}
}
Output:

Sample game:

Tokens remaining 12

  How many tokens 1, 2 or 3? 3
  Computer takes 1 token

Tokens remaining 8

  How many tokens 1, 2 or 3? nim

Must be a number between 1 and 3, try again.

Tokens remaining 8

  How many tokens 1, 2 or 3? 2
  Computer takes 2 tokens

Tokens remaining 4

  How many tokens 1, 2 or 3? 1
  Computer takes 3 tokens

Tokens remaining 0

  Computer wins!

Lua[edit]

 
tokens = 12
 
print("Nim Game\n")
print("Starting with " .. tokens .. " tokens.\n\n")
 
function printRemaining()
print(tokens .. " tokens remaining.\n")
end
 
function playerTurn(take)
take = math.floor(take)
if (take < 1 or take > 3) then
print ("\nTake must be between 1 and 3.\n")
return false
end
 
tokens = tokens - take
 
print ("\nPlayer takes " .. take .. " tokens.")
printRemaining()
return true
end
 
function computerTurn()
take = tokens % 4
tokens = tokens - take
 
print("Computer takes " .. take .. " tokens.")
printRemaining()
end
 
while (tokens > 0) do
io.write("How many tokens would you like to take?: ")
if playerTurn(io.read("*n")) then
computerTurn()
end
end
 
print ("Computer wins.")
 
Output:

Sample game output:

Nim Game

Starting with 12 tokens.


How many tokens would you like to take?: 3
Player takes 3 tokens.
9 tokens remaining.

Computer takes 1 tokens.
8 tokens remaining.

How many tokens would you like to take?: 4
Take must be between 1 and 3.

How many tokens would you like to take?: 1
Player takes 1 tokens.
7 tokens remaining.

Computer takes 3 tokens.
4 tokens remaining.

How many tokens would you like to take?: 2
Player takes 2 tokens.
2 tokens remaining.

Computer takes 2 tokens.
0 tokens remaining.

Computer wins.

MiniScript[edit]

Translation of: Lua
tokens = 12
 
print "Nim Game"
print "Starting with " + tokens + " tokens."
print
 
printRemaining = function()
print tokens + " tokens remaining."
print
end function
 
playerTurn = function(take)
take = floor(val(take))
if take < 1 or take > 3 then
print "Take must be between 1 and 3."
return false
end if
 
globals.tokens = tokens - take
 
print "Player takes " + take + " tokens."
printRemaining
return true
end function
 
computerTurn = function()
take = tokens % 4
globals.tokens = tokens - take
 
print "Computer takes " + take + " tokens."
printRemaining
end function
 
while tokens > 0
if playerTurn(input("How many tokens would you like to take? ")) then
computerTurn
end if
end while
 
print "Computer wins."
Output:
Nim Game
Starting with 12 tokens.

How many tokens would you like to take? 0
Take must be between 1 and 3.
How many tokens would you like to take? 1
Player takes 1 tokens.
11 tokens remaining.
 
Computer takes 3 tokens.
8 tokens remaining.
 
How many tokens would you like to take? 2
Player takes 2 tokens.
6 tokens remaining.
 
Computer takes 2 tokens.
4 tokens remaining.
 
How many tokens would you like to take? 2
Player takes 2 tokens.
2 tokens remaining.
 
Computer takes 2 tokens.
0 tokens remaining.
 
Computer wins.

Nim[edit]

import strutils
import terminal
 
var tokens = 12
 
styledEcho(styleBright, "Nim in Nim\n")
 
proc echoTokens() =
styledEcho(styleBright, "Tokens remaining: ", resetStyle, $tokens, "\n")
 
proc player() =
var take = '0'
styledEcho(styleBright, "- Your turn -")
echo "How many tokens will you take?"
while true:
stdout.styledWrite(styleDim, "Take (1–3): ", resetStyle)
take = getch()
stdout.write(take, '\n')
if take in {'1'..'3'}:
tokens -= parseInt($take)
break
else:
echo "Please choose a number between 1 and 3."
echoTokens()
 
proc computer() =
styledEcho(styleBright, "- Computer's turn -")
let take = tokens mod 4
tokens -= take
styledEcho("Computer took ", styleBright, $take, " ",
if take == 1: "token"
else: "tokens")
echoTokens()
 
while tokens > 0:
player()
computer()
 
styledEcho(styleBright, "Computer wins!")
Output:
- Your turn -
How many tokens will you take?
Take (1–3): 1
Tokens remaining: 11

- Computer's turn -
Computer took 3 tokens
Tokens remaining: 8

- Your turn -
How many tokens will you take?
Take (1–3): 2
Tokens remaining: 6

- Computer's turn -
Computer took 2 tokens
Tokens remaining: 4

- Your turn -
How many tokens will you take?
Take (1–3): 3
Tokens remaining: 1

- Computer's turn -
Computer took 1 token
Tokens remaining: 0

Computer wins!

Perl[edit]

Translation of: Raku
use strict;
use warnings;
use feature 'say';
 
my $tokens = 12;
say "$tokens tokens remaining.\n";
 
while (1) {
print "How many tokens do you want to remove; 1, 2 or 3? : ";
(my $player = <>) =~ s/\s//g;
say "Nice try. $tokens tokens remaining.\n" and next
unless $player =~ /^[123]$/;
$tokens -= 4;
say "Computer takes @{[4 - $player]}.\n$tokens tokens remaining.\n";
say "Computer wins." and last
if $tokens <= 0;
}
Output:
12 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 3
Computer takes 1.
8 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : -1
Nice try. 8 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 2
Computer takes 2.
4 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 1
Computer takes 3.
0 tokens remaining.

Computer wins.

Phix[edit]

Translation of: Raku
integer tokens = 12, player = 0
 
while true do
printf(1,"%2d tokens remaining. ",tokens)
if tokens=0 then printf(1,"Computer wins.\n") exit end if
printf(1,"How many tokens do you want to remove; 1, 2, or 3?:")
while player<1 or player>3 do player=getc(0)-'0' end while
printf(1,"%d. Computer takes %d.\n",{player,4-player})
tokens -= 4; player = 0
end while
Output:
12 tokens remaining. How many tokens do you want to remove; 1, 2, or 3?:1. Computer takes 3.
 8 tokens remaining. How many tokens do you want to remove; 1, 2, or 3?:2. Computer takes 2.
 4 tokens remaining. How many tokens do you want to remove; 1, 2, or 3?:3. Computer takes 1.
 0 tokens remaining. Computer wins.

Prolog[edit]

nim :- next_turn(12), !.
 
next_turn(N) :-
% Player Turn
format('How many dots would you like to take? '),
read_line_to_codes(user_input, Line),
number_codes(PlayerGuess, Line),
member(PlayerGuess,[1,2,3]),
N1 is N - PlayerGuess,
format('You take ~d dots~n~d dots remaining.~n~n', [PlayerGuess, N1]),
 
% Computer Turn
CompGuess is 4 - PlayerGuess,
N2 is N1 - CompGuess,
format('Computer takes ~d dots~n~d dots remaining.~n~n', [CompGuess, N2]),
(
N2 = 0
-> format('Computer wins!')
; next_turn(N2)
).
Output:
?- nim.
How many dots would you like to take? 2
You take 2 dots
10 dots remaining.

Computer takes 2 dots
8 dots remaining.

How many dots would you like to take? 3
You take 3 dots
5 dots remaining.

Computer takes 1 dots
4 dots remaining.

How many dots would you like to take? 1
You take 1 dots
3 dots remaining.

Computer takes 3 dots
0 dots remaining.

Computer wins!
true.

?-

Python[edit]

Works on Python 3

 
print("Py Nim\n")
 
def getTokens(curTokens):
global tokens
 
print("How many tokens would you like to take? ", end='')
take = int(input())
 
if (take < 1 or take > 3):
print("Number must be between 1 and 3.\n")
getTokens(curTokens)
return
 
tokens = curTokens - take
print(f'You take {take} tokens.')
print(f'{tokens} tokens remaining.\n')
 
def compTurn(curTokens):
global tokens
 
take = curTokens % 4
tokens = curTokens - take
print (f'Computer takes {take} tokens.')
print (f'{tokens} tokens remaining.\n')
 
 
tokens = 12
while (tokens > 0):
getTokens(tokens)
compTurn(tokens)
 
print("Computer wins!")
 
Output:
Py Nim

How many tokens would you like to take? 2
You take 2 tokens.
10 tokens remaining.

Computer takes 2 tokens.
8 tokens remaining.

How many tokens would you like to take? 1
You take 1 tokens.
7 tokens remaining.

Computer takes 3 tokens.
4 tokens remaining.

How many tokens would you like to take? 3
You take 3 tokens.
1 tokens remaining.

Computer takes 1 tokens.
0 tokens remaining.

Computer wins!

Racket[edit]

 
#lang racket
 
(define (print-remaining tokens-remaining)
(printf "~a tokens remain.\n" tokens-remaining))
 
(define (read-tokens)
(define num (read))
(cond
[(and (natural? num) (< num 4)) num]
[else
(display "Please enter a number between 1 to 3\n")
(read-tokens)]))
 
(define (pturn tokens-remaining)
(cond
[(not (zero? tokens-remaining))
(print-remaining tokens-remaining)
(display "Your turn. How many tokens? ")
(define n (read-tokens))
(cturn (- tokens-remaining n) n)]
[else (display "Computer wins!")]))
 
 
(define (cturn tokens-remaining p-took)
(cond
[(not (zero? tokens-remaining))
(print-remaining tokens-remaining)
(define c-take (- 4 p-took))
(printf "Computer takes ~a tokens\n" c-take)
(pturn (- tokens-remaining c-take))]
[else (display "You win!")]))
 
(pturn 12)
 

Raku[edit]

(formerly Perl 6)

Works with: Rakudo version 2019.03
say my $tokens = 12, " tokens remaining.\n";
 
loop {
my $player = trim prompt "How many tokens do you want to remove; 1, 2 or 3? : ";
say "Nice try. $tokens tokens remaining.\n" and
next unless $player eq any <1 2 3>;
$tokens -= 4;
say "Computer takes {4 - $player}.\n$tokens tokens remaining.\n";
say "Computer wins." and last if $tokens <= 0;
}
Sample output:
12 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 3
Computer takes 1.
8 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 6
Nice try. 8 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : G
Nice try. 8 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 2
Computer takes 2.
4 tokens remaining.

How many tokens do you want to remove; 1, 2 or 3? : 1
Computer takes 3.
0 tokens remaining.

Computer wins.

REXX[edit]

Programming notes:   extra error checking was done with specific informative error messages.   Also included was a method of quitting the game.   The number of (starting) tokens   (the pot)   can be specified on the command line,   the default is   12.

/*REXX program plays the NIM game with a human opponent; the pot size can be specified. */
parse arg pot _ . 1 __ /*obtain optional argument from the CL.*/
if pot=='' | pot=="," then pot= 12 /*Not specified? Then use the default.*/
if _\=='' then do; call ser "Too many arguments entered: " __; exit 13; end
if \isNum(pot) then do; call ser "argument isn't numeric: " pot; exit 13; end
if \isInt(pot) then do; call ser "argument isn't an integer: " pot; exit 13; end
if pot<4 then do; call ser "The pot number is too small: " pot; exit 13; end
if pot>100 then do; call ser "The pot number is too large: " pot; exit 13; end
pad= copies('─', 8) /*literal used as an eyecatcher in msgs*/
pot= pot/1 /*normalize the pot (number). */
t= pot//4
if pot>12 & t\==0 then do; say pad 'The computer takes ' t " token"s(t).
pot= pot - t
end
 
do forever; call show pot
do until ok; ok= 1; say
say pad "How many tokens do you want to take away (1, 2, or 3) (or QUIT)?"
parse pull t _ . 1 q 1 __; upper q; say
if abbrev('QUIT',q,1) then do; say pad 'Quitting.'; exit 1; end
if t='' then call ser "No arguments entered."
if _\=='' then call ser "Too many arguments entered: " __
if \isNum(t) then call ser "Argument isn't numeric: " t
if \isInt(t) then call ser "Argument isn't an integer: " t
if t<1 then call ser "Argument can't be less than 1: " t
if t>3 then call ser "Argument can't be greater than 3: " t
end /*while*/
t= t/1 /*Normalize the number: 001 2. +3 */
#= max(1, 4-t) /*calculate the computer's take─away. */
say pad 'The computer takes ' # " token"s(#).
pot= pot - t - # /*calculate the number of tokens in pot*/
if pot==0 then do; say pad 'No tokens left.' /*No tokens left in the pot? */
say pad "The computer wins!" /*Display a braggart message.*/
exit /*exit this computer program.*/
end
end /*forever*/ /*keep looping until there's a winner. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
isNum: return datatype( arg(1), 'N') /*verify that the arg is a number. */
isInt: return datatype( arg(1), 'W') /* " " " " " an integer. */
show: say; say pad "Tokens remaining: " arg(1)' ' pad; say; return
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1)
ser: if ok then say pad '***error***' arg(1); ok= 0; return
output   when using the default input:
──────── Tokens remaining:  12  ────────


──────── How many tokens do you want to take away  (1, 2, or 3)    (or QUIT)?
2                                            ◄■■■■■■■■■■■ user input                                             

──────── The computer takes  2  tokens.

──────── Tokens remaining:  8  ────────


──────── How many tokens do you want to take away  (1, 2, or 3)    (or QUIT)?
3                                            ◄■■■■■■■■■■■ user input

──────── The computer takes  1  token.

──────── Tokens remaining:  4  ────────


──────── How many tokens do you want to take away  (1, 2, or 3)    (or QUIT)?
1                                            ◄■■■■■■■■■■■ user input 

──────── The computer takes  3  tokens.
──────── No tokens left.
──────── The computer wins!

Ring[edit]

 
load "stdlib.ring"
load "guilib.ring"
 
limit = 4
limit1 = 1
limit2 = 3
limit3 = 5
limit4 = 7
 
match1 = limit1
match2 = limit2
match3 = limit3
match4 = limit4
 
move1 = 0
move2 = 0
move3 = 0
move4 = 0
 
Button1 = list(limit1)
Button2 = list(limit2)
Button3 = list(limit3)
Button4 = list(limit4)
 
pcMove = 0
 
width = 60
height = 60
 
yourScore = 0
pcScore = 0
 
C_FONTSIZE = 15
C_NIM = "images/nim.jpg"
C_COMPUTER = "images/computer.jpg"
C_PROGRAMMER = "images/programmer.jpg"
 
app = new qApp
{
win = new qWidget() {
app.StyleFusionBlack()
setWindowTitle('CalmoSoft Nim Game')
setWinIcon(self,"images/nim.jpg")
reSize(800,600)
 
for Col = 1 to limit1
Button1[Col] = new QPushButton(win) {
y = 230+(Col-1)*height
setgeometry(y+10,70,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
}
next
 
for Col = 1 to limit2
Button2[Col] = new QPushButton(win) {
y = 170+(Col-1)*height
setgeometry(y+10,150,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
}
next
 
for Col = 1 to limit3
Button3[Col] = new QPushButton(win) {
y = 110+(Col-1)*height
setgeometry(y+10,230,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
}
next
 
for Col = 1 to limit4
Button4[Col] = new QPushButton(win) {
y = 50+(Col-1)*height
setgeometry(y+10,310,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
}
next
 
Row1 = new QPushButton(win) {
setgeometry(500,70,width,height)
setStyleSheet("color:Black;background-color:Orange")
setSizePolicy(1,1)
setclickevent("deleteRow1()")
settext("Row1") }
 
 
Row2 = new QPushButton(win) {
setgeometry(500,150,width,height)
setStyleSheet("color:Black;background-color:Orange")
setSizePolicy(1,1)
setclickevent("deleteRow2()")
settext("Row2") }
 
 
Row3 = new QPushButton(win) {
setgeometry(500,230,width,height)
setStyleSheet("color:Black;background-color:Orange")
setSizePolicy(1,1)
setclickevent("deleteRow3()")
settext("Row3") }
 
 
Row4 = new QPushButton(win) {
setgeometry(500,310,width,height)
setStyleSheet("color:Black;background-color:Orange")
setSizePolicy(1,1)
setclickevent("deleteRow4()")
settext("Row4") }
 
labelYourScore = new QLabel(win) { setgeometry(60,20,150,30)
setFont(new qFont("Verdana",C_FONTSIZE,50,0))
settext("Your score: 0") }
 
labelComputerScore = new QLabel(win) { setgeometry(350,20,150,30)
setFont(new qFont("Verdana",C_FONTSIZE,50,0))
settext("PC score: 0") }
 
btnNewGame = new QPushButton(win) { setgeometry(60,400,80,30)
setFont(new qFont("Verdana",C_FONTSIZE,50,0))
settext("New")
setclickevent("newGame()") }
 
btnExit = new QPushButton(win) { setgeometry(400,400,80,30)
setFont(new qFont("Verdana",C_FONTSIZE,50,0))
settext("Exit")
setclickevent("pQuit()") }
 
btnPcMove = new QPushButton(win) { setgeometry(200,400,140,30)
setFont(new qFont("Verdana",C_FONTSIZE,50,0))
settext("PC move")
setclickevent("pcMove()") }
 
show()
}
exec()
}
 
func deleteRow1()
if move2 = 1 or move3 = 1 or move4 = 1
move1 = 0
return
else
move1 = 1
ok
if (match1 > 0) and (move1 = 1)
if pcMove = 1
Button1[match1] { seticon(new qicon(new qpixmap(C_COMPUTER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match1 = match1 - 1
move1 = 0
ok
 
if pcMove = 0
Button1[match1] { seticon(new qicon(new qpixmap(C_PROGRAMMER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match1 = match1 - 1
ok
gameOver()
ok
 
func deleteRow2()
if move1 = 1 or move3 = 1 or move4 = 1
move2 = 0
return
else
move2 = 1
ok
if match2 > 0 and move2 = 1
if pcMove = 1
Button2[match2] { seticon(new qicon(new qpixmap(C_COMPUTER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match2 = match2 - 1
move2 = 0
ok
 
if pcMove = 0
Button2[match2] { seticon(new qicon(new qpixmap(C_PROGRAMMER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match2 = match2 - 1
ok
gameOver()
ok
 
func deleteRow3()
if move1 = 1 or move2 = 1 or move4 = 1
move3 = 0
return
else
move3 = 1
ok
if match3 > 0 and move3 = 1
if pcMove = 1
Button3[match3] { seticon(new qicon(new qpixmap(C_COMPUTER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match3 = match3 - 1
move3 = 0
ok
 
if pcMove = 0
Button3[match3] { seticon(new qicon(new qpixmap(C_PROGRAMMER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match3 = match3 - 1
ok
gameOver()
ok
 
func deleteRow4()
if move1 = 1 or move2 = 1 or move3 = 1
move4 = 0
return
else
move4 = 1
ok
if match4 > 0 and move4 = 1
if pcMove = 1
Button4[match4] { seticon(new qicon(new qpixmap(C_COMPUTER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match4 = match4 - 1
move4 = 0
ok
 
if pcMove = 0
Button4[match4] { seticon(new qicon(new qpixmap(C_PROGRAMMER)))
setIconSize(new qSize(55,55))
setenabled(false) }
match4 = match4 - 1
ok
gameOver()
ok
 
func pcMove()
 
move1 = 0
move2 = 0
move3 = 0
move4 = 0
pcMove = 1
for n = 1 to limit
if match1 > 0
rnd = random(match1-1)+1
for m = 1 to rnd
deleteRow1()
next
exit
ok
 
if match2 > 0
rnd = random(match2-1)+1
for m = 1 to rnd
deleteRow2()
next
exit
ok
 
if match3 > 0
rnd = random(match3-1)+1
for m = 1 to rnd
deleteRow3()
next
exit
ok
 
if match4 > 0
rnd = random(match4-1)+1
for m = 1 to rnd
deleteRow4()
next
exit
ok
next
pcMove = 0
 
func gameOver()
if (match1 = 0) and (match2 = 0) and (match3 = 0) and (match4 = 0)
if pcMove = 0
pcScore = pcScore + 1
labelComputerScore.settext("PC score: " + string(pcScore))
msgBox("Game Over! You Lost!")
else
yourScore = yourScore + 1
labelYourScore.settext("Your score: " + string(yourScore))
msgBox("Game Over! You Win!")
ok
ok
 
func newGame()
 
match1 = limit1
match2 = limit2
match3 = limit3
match4 = limit4
 
move1 = 0
move2 = 0
move3 = 0
move4 = 0
 
pcMove = 0
 
for Col = 1 to limit1
Button1[Col] = new QPushButton(win) {
y = 230+(Col-1)*height
setgeometry(y+10,70,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
show()
}
next
 
for Col = 1 to limit2
Button2[Col] = new QPushButton(win) {
y = 170+(Col-1)*height
setgeometry(y+10,150,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
show()
}
next
 
for Col = 1 to limit3
Button3[Col] = new QPushButton(win) {
y = 110+(Col-1)*height
setgeometry(y+10,230,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
show()
}
next
 
for Col = 1 to limit4
Button4[Col] = new QPushButton(win) {
y = 50+(Col-1)*height
setgeometry(y+10,310,width,height)
setSizePolicy(1,1)
seticon(new qicon(new qpixmap(C_NIM)))
setIconSize(new qSize(60,60))
show()
}
next
 
func msgBox(cText)
mb = new qMessageBox(win) {
setWindowTitle('CalmoSoft Nim Game')
setText(cText)
setstandardbuttons(QMessageBox_OK)
result = exec()
}
 
func pQuit()
win.close()
 

Necessary image files: Images file

Output images:

Nim Game #1

Nim Game #2

Ruby[edit]

[12, 8, 4].each do |remaining|
puts "There are #{remaining} dots.\nHow many dots would you like to take? "
unless (num=gets.to_i).between?(1, 3)
puts "Please enter one of 1, 2 or 3"
redo
end
puts "You took #{num} dots, leaving #{remaining-num}.\nComputer takes #{4-num}.\n\n"
end
 
puts "Computer took the last and wins."
 
Output:
There are 12 dots.
How many dots would you like to take? 
foo
Please enter one of 1, 2 or 3
There are 12 dots.
How many dots would you like to take? 
1
You took 1 dots, leaving 11.
Computer takes 3.

There are 8 dots.
How many dots would you like to take? 
3
You took 3 dots, leaving 5.
Computer takes 1.

There are 4 dots.
How many dots would you like to take? 
2
You took 2 dots, leaving 2.
Computer takes 2.

Computer took the last and wins.

Rust[edit]

 
fn main() {
let mut tokens = 12;
println!("Nim game");
println!("Starting with {} tokens.", tokens);
println!("");
 
loop {
tokens = p_turn(&tokens);
print_remaining(&tokens);
tokens = c_turn(&tokens);
print_remaining(&tokens);
 
if tokens == 0 {
println!("Computer wins!");
break;
}
}
}
 
fn p_turn(tokens: &i32) -> i32 {
loop { //try until we get a good number
println!("How many tokens would you like to take?");
 
let mut take = String::new();
io::stdin().read_line(&mut take)
.expect("Sorry, I didn't understand that.");
 
let take: i32 = match take.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("Invalid input");
println!("");
continue;
}
};
 
if take > 3 || take < 1 {
println!("Take must be between 1 and 3.");
println!("");
continue;
}
 
return tokens - take;
}
}
 
fn c_turn(tokens: &i32) -> i32 {
let take = tokens % 4;
 
println!("Computer takes {} tokens.", take);
 
return tokens - take;
}
 
fn print_remaining(tokens: &i32) {
println!("{} tokens remaining.", tokens);
println!("");
}
 
Output:

sample game:

Nim game
Starting with 12 tokens.

How many tokens would you like to take?
foo
Invalid input

How many tokens would you like to take?
3
9 tokens remaining.

Computer takes 1 tokens.
8 tokens remaining.

How many tokens would you like to take?
5
Take must be between 1 and 3.

How many tokens would you like to take?
2
6 tokens remaining.

Computer takes 2 tokens.
4 tokens remaining.

How many tokens would you like to take?
1
3 tokens remaining.

Computer takes 3 tokens.
0 tokens remaining.

Computer wins!

S-Basic[edit]

 
$constant maxtokens = 12
$constant machine = 0
$constant human = 1
$constant false = 0
$constant true = 0FFFFH
 
procedure welcome
print "Welcome to the Game of Nim."
print "We begin with";maxtokens;" tokens. On each turn, a player"
print "may take between 1 and 3 tokens. The player who takes the"
print "last token wins."
print
end
 
procedure show(n = integer)
var i = integer
print "Available tokens:";n;" ";
rem - provide a visual display
for i = 1 to n
print "o ";
next i
print
end
 
function getnum(lowlim, toplim = integer) = integer
var ok, n = integer
repeat
begin
input "You take:";n
if n < lowlim or n > toplim then
begin
print "Must take between";lowlim;" and";toplim
print "Try again."
ok = false
end
else
ok = true
end
until ok
end = n
 
function play(player, tokens, taken = integer) = integer
if player = human then
taken = getnum(1,3)
else
taken = 4 - taken
end = taken
 
procedure report(player = integer)
if player = human then
print "You took the last one. You win. Congratulations!"
else
print "I took the last one, so I win. Sorry about that."
end
 
var player, tokens, taken = integer
 
welcome
tokens = maxtokens
taken = 0
player = human
print "You go first."
repeat
begin
show tokens
taken = play(player, tokens, taken)
tokens = tokens - taken
if player = machine then print "I took:";taken
if tokens > 0 then player = 1 - player
end
until tokens = 0
report player
print "Thanks for playing!"
 
end
Output:
Welcome to the Game of Nim.
We begin with 12 tokens. On each turn, a 
player may take between 1 and 3 tokens. The player
who takes the last token wins.

You go first.
Available tokens: 12  o o o o o o o o o o o o
You take:? 4
Must take between 1 and 3
Try again.
You take:? 3
Available tokens: 9  o o o o o o o o o
I took: 1
Available tokens: 8  o o o o o o o o
You take:? 2
Available tokens: 6  o o o o o o
I took: 2
Available tokens: 4  o o o o
You take:? 1
Available tokens: 3  o o o
I took: 3
I took the last one, so I win. Sorry about that.
Thanks for playing!


Scala[edit]

 
var tokens = 12
 
def playerTurn(curTokens: Int): Unit =
{
val take = readLine("How many tokens would you like to take? ").toInt
if (take < 1 || take > 3) {
println("Number must be between 1 and 3.")
playerTurn(curTokens)
}
else {
tokens = curTokens - take
println(s"You take $take tokens. $tokens tokens remaining.\n")
}
}
 
def compTurn(curTokens: Int): Unit =
{
val take = curTokens % 4
tokens = curTokens - take
println(s"Computer takes $take tokens. $tokens remaining.\n")
}
 
def main(args: Array[String]): Unit =
{
while (tokens > 0)
{
playerTurn(tokens)
compTurn(tokens)
}
println("Computer wins!")
}
 

Smalltalk[edit]

Works with: GNU Smalltalk
 
Object subclass: Nim [
| tokens |
<comment: 'I am a game of nim'>
Nim class >> new [
<category: 'instance creation'>
^(super new) init: 12
]
 
init: t [
<category: 'instance creation'>
tokens := t.
^self
]
 
 
pTurn [
| take |
<category: 'gameplay'>
Transcript nextPutAll: 'How many tokens will you take?: '.
take := (stdin nextLine) asNumber.
((take < 1) | (take > 3))
ifTrue: [Transcript nextPutAll: 'Invalid input';nl;nl. self pTurn]
ifFalse: [tokens := tokens - take]
]
 
cTurn [
| take |
<category: 'gameplay'>
take := tokens - (4 * (tokens // 4)). "tokens % 4"
Transcript nextPutAll: 'Computer takes '.
take printOn: Transcript.
Transcript nextPutAll: ' tokens';nl.
tokens := tokens - take
]
 
mainLoop [
<category: 'main loop'>
Transcript nextPutAll: 'Nim game';nl.
Transcript nextPutAll: 'Starting with '.
tokens printOn: Transcript.
Transcript nextPutAll: ' tokens';nl;nl.
1 to: 3 do: [ :n | "The computer always wins on the 3rd turn"
self pTurn.
self printRemaining.
self cTurn.
self printRemaining.
(tokens = 0)
ifTrue:[Transcript nextPutAll: 'Computer wins!';nl. ^0]
]
]
 
printRemaining [
<category: 'information'>
tokens printOn: Transcript.
Transcript nextPutAll: ' tokens remaining';nl;nl
]
]
 
g := Nim new.
g mainLoop.
 
Output:

sample game:

Nim game
Starting with 12 tokens

How many tokens will you take?: foo
Invalid input

How many tokens will you take?: 3
9 tokens remaining

Computer takes 1 tokens
8 tokens remaining

How many tokens will you take?: 4
Invalid input

How many tokens will you take?: 2
6 tokens remaining

Computer takes 2 tokens
4 tokens remaining

How many tokens will you take?: 1
3 tokens remaining

Computer takes 3 tokens
0 tokens remaining

Computer wins!