Nim game

From Rosetta Code
(Redirected from Nim Game)


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.

11l

Translation of: Python
V tokens = 12

F getTokens(curTokens) -> N
   print(‘How many tokens would you like to take? ’, end' ‘’)
   V take = Int(input())

   I (take < 1 | take > 3)
      print("Number must be between 1 and 3.\n")
      getTokens(curTokens)
      R

   :tokens = curTokens - take
   print(‘You take #. tokens.’.format(take))
   print("#. tokens remaining.\n".format(:tokens))

F compTurn(curTokens)
   V take = curTokens % 4
   :tokens = curTokens - take
   print(‘Computer takes #. tokens.’.format(take))
   print("#. tokens remaining.\n".format(:tokens))

L tokens > 0
   getTokens(tokens)
   compTurn(tokens)

print(‘Computer wins!’)
Output:
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!

8080 Assembly

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

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,'$'

Action!

BYTE FUNC PlayerTurn(BYTE tokens)
  BYTE t,max

  IF tokens<3 THEN
    max=tokens
  ELSE
    max=3
  FI

  DO
    PrintF("How many tokens would you like to take (1-%B)? ",max)
    t=InputB()
  UNTIL t>=1 AND t<=max
  OD
  PrintF("Player takes %B tokens.%E",t)
  t=tokens-t
  IF t=0 THEN
    PrintE("Player wins.")
  FI
RETURN (t)

BYTE FUNC ComputerTurn(BYTE tokens)
  BYTE t

  t=tokens MOD 4
  PrintF("Computer takes %B tokens.%E",t)
  t=tokens-t
  IF t=0 THEN
    PrintE("Computer wins.")
  FI
RETURN (t)

PROC Main()
  BYTE tokens=[12],t
  BYTE player=[1]

  WHILE tokens>0
  DO
    PrintF("Available tokens: %B%E",tokens)
    IF player THEN
      tokens=PlayerTurn(tokens)
    ELSE
      tokens=ComputerTurn(tokens)
    FI
    player=1-player
  OD
RETURN
Output:

Screenshot from Atari 8-bit computer

Available tokens: 12
How many tokens would you like to take (1-3)? 3
Player takes 3 tokens.
Available tokens: 9
Computer takes 1 tokens.
Available tokens: 8
How many tokens would you like to take (1-3)? 2
Player takes 2 tokens.
Available tokens: 6
Computer takes 2 tokens.
Available tokens: 4
How many tokens would you like to take (1-3)? 1
Player takes 1 tokens.
Available tokens: 3
Computer takes 3 tokens.
Computer wins.

Ada

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 68

BEGIN # play Nim #
    # gets a single character answer from standin and returns it #
    PROC answer = ( STRING prompt )CHAR:
         BEGIN
             STRING s;
             INT left := 0;
             WHILE print( ( prompt, "> " ) );
                   read( ( s, newline ) );
                   left      := LWB s;
                   INT right := UPB s;
                   WHILE IF left  > right THEN FALSE ELSE s[ left  ] = " " FI DO left  +:= 1 OD;
                   WHILE IF right < left  THEN FALSE ELSE s[ right ] = " " FI DO right -:= 1 OD;
                   left /= right
             DO
                 print( ( "Please reply with a single character", newline ) )
             OD;
             s[ left ]
         END # answer # ;
    # play one game #
    INT    tokens := 12;
    STRING suffix := "";
    WHILE
        CHAR  user;
        WHILE user := answer( "There are "
                            + whole( tokens, 0 )
                            + " tokens"
                            + suffix
                            + ", how many do you want to take (1, 2 or 3)"
                            );
              user /= "1" AND user /= "2" AND user /= "3"
        DO
            print( ( "please answer 1, 2 or 3", newline ) )
        OD;
        INT move = ABS user - ABS "0";
        print( ( "I take ", whole( 4 - move, 0 ), newline ) );
        suffix  := " left";
        tokens -:= 4;
        tokens > 0
    DO SKIP OD;
    print( ( "I win!", newline ) )
END
Output:
There are 12 tokens, how many do you want to take (1, 2 or 3)> 3
I take 1
There are 8 tokens left, how many do you want to take (1, 2 or 3)> t
please answer 1, 2 or 3
There are 8 tokens left, how many do you want to take (1, 2 or 3)> 4
please answer 1, 2 or 3
There are 8 tokens left, how many do you want to take (1, 2 or 3)> 1
I take 3
There are 4 tokens left, how many do you want to take (1, 2 or 3)> 2
I take 2
I win!

ALGOL-M

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 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.
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!

Arturo

total: 12
while ø [
    tk: 0 
    print "YOUR turn:"
    while [not? contains? 1..3 tk: <= to :integer input "How many tokens will you take? (1-3) "][]
    total: total-tk
    print [total "tokens remaining\n"]

    print ["COMPUTER's turn:"]
    print ["taking:" 4-tk]
    total: total-(4-tk)
    print [total "tokens remaining\n"]
    if total=0 [
        print "COMPUTER won. :)"
        break
    ]
]
Output:
YOUR turn:
How many tokens will you take? (1-3) 3
9 tokens remaining
 
COMPUTER's turn: 
taking: 1 
8 tokens remaining
 
YOUR turn:
How many tokens will you take? (1-3) 2
6 tokens remaining
 
COMPUTER's turn: 
taking: 2 
4 tokens remaining
 
YOUR turn:
How many tokens will you take? (1-3) 1
3 tokens remaining
 
COMPUTER's turn: 
taking: 3 
0 tokens remaining
 
COMPUTER won. :)

AsciiDots

%$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!

AutoHotkey

Play:
tokens := 12
while tokens {
	while !(D>0 && D<4)
		InputBox, D, Nim Game, % "Tokens Remaining = " tokens
		. "`nHow many tokens would you like to take?"
		. "`nChoose 1, 2 or 3"
	tokens -= D
	MsgBox % "Computer Takes " 4-D
	tokens -= 4-d, d:=0
}
MsgBox, 262212,,Computer Always Wins!`nWould you like to play again?
IfMsgBox, Yes
	gosub Play
else
	ExitApp
return

AWK

# 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

BASIC

Applesoft BASIC

This one-liner demonstrates the 240 character line limit. The program has been crafted to be exactly 244 characters long. The last 4 characters HEAP will be truncated from the last statement in the line. The HEAP variable is optional in the out-most NEXT statement so the program still runs correctly.

0ST$(0)="YOU MUST TAKE 1, 2, OR 3 TOKENS.":FORHEAP=12TO1STEP-4:PRINT"THERE ARE "HEAP" TOKENS REMAINING.":FORI=0TO1:INPUT"HOW MANY WOULD YOU LIKE TO TAKE?";T%:I=T%>0ANDT%<4:PRINTST$(I):NEXTI:PRINT"ON MY TURN I WILL TAKE "4-T%" TOKENS.":NEXTHEAP

BASIC256

Works with: BASIC256 version 1.99.99.14+
monton = 12
llevar = 0

while monton > 0
	print "There are "; monton; " tokens remaining. How many would you like to take? ";
	input integer llevar
	while llevar = 0 or llevar > 3
		print "You must take 1, 2, or 3 tokens. How many would you like to take ";
		input integer llevar
	end while

	print "On my turn I will take "; 4 - llevar; " token(s)."
	monton = monton - 4
end while

print
print "I got the last token. I win! Better luck next time."
end

Craft Basic

let h = 12

label loop

	alert "There are ", h ," tokens remaining."
	input "How many would you like to take? ", t

	if t > 3 or t < 1 then

		alert "You must take between 1 to 3 tokens."

	endif

	if h - t < 0 then

		alert "You cannot take that many. There's only ", h ," left."

	endif

	if t <= 3 and t >= 1 and h - t >= 0 then

		let h = h - t

		if h = 0 then

			alert "Congratulations. You got the last token."
			end

		endif

		let t = 4 - t

		if h >= 15 then

			let t = 3

		endif

		if h <= 3 then

			let t = h

		endif

		alert "I will take ", t ," tokens."
		let h = h - t

		if h = 0 then

			alert "I got the last token. I win. Better luck next time."
			end

		endif

	endif

goto loop

FreeBASIC

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."

FTCBASIC

define tokens = 12, take = 0

gosub intro

do

	print "There are " \
	print tokens \
	print " tokens remaining."
	crlf
	print "How many would you like to take? " \

	input take

	if take > 3 or take < 1 then

		print "You must take between 1 to 3 tokens."

	endif

	if tokens - take < 0 then

		print "You cannot take that many."

	endif

	if take <= 3 and take >= 1 and tokens - take >= 0 then

		let tokens = tokens - take

		if tokens = 0 then

			bell
			print "Congratulations. You got the last token."
			pause
			end

		endif

		let take = 4 - take

		if tokens >= 15 then

			let take = 3

		endif

		if tokens <= 3 then

			let take = tokens

		endif

		print "I will take " \
		print take \
		print " of the tokens."

		let tokens = tokens - take

		if tokens = 0 then

			print "I got the last token. I win. Better luck next time."
			pause
			end

		endif

	endif

loop

sub intro

	cls
	print "NIM game"
	crlf
	print "Press any key to play..."
	cls

return

GW-BASIC

10 HEAP = 12
20 WHILE HEAP>0
30 TAKE = 0
40 PRINT "There are ";HEAP;" tokens left."
50 WHILE TAKE < 1 OR TAKE > 3 OR TAKE > HEAP
60 INPUT "How many would you like to take? ", TAKE
70 IF TAKE = HEAP THEN GOTO 140
80 WEND
90 PRINT "I will take ";4-TAKE;" tokens."
100 HEAP = HEAP - 4
110 WEND
120 PRINT "I got the last token. Better luck next time."
130 END
140 PRINT "You got the last token. Congratulations!"
150 END

IS-BASIC

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

PureBasic

OpenConsole()
Define monton.i = 12, llevar.i

While monton > 0
  Print("There are " + Str(monton) + " tokens remaining. How many would you like to take? ")
  llevar = Val(Input())
  While llevar = 0 Or llevar > 3
    Print("You must take 1, 2, or 3 tokens. How many would you like to take ")
    llevar = Val(Input())
  Wend
  
  PrintN("On my turn I will take " + Str(4 - llevar) + " token(s).")
  monton = monton - 4
Wend

PrintN("I got the last token. I win! Better luck next time.")

PrintN(#CRLF$ + "--- terminado, pulsa RETURN---"): Input()
CloseConsole()

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
monton = 12
llevar = 0

DO WHILE monton > 0
    PRINT USING "There are ## tokens remaining. How many would you like to take"; monton; 
    INPUT llevar
    DO WHILE llevar = 0 OR llevar > 3
	    INPUT "You must take 1, 2, or 3 tokens. How many would you like to take"; llevar
    LOOP
    
	PRINT "On my turn I will take"; 4 - llevar; " token(s)."
    monton = monton - 4
LOOP

PRINT
PRINT "I got the last token. I win! Better luck next time."
END

Run BASIC

Works with: Just BASIC
Works with: Liberty BASIC
monton = 12
llevar = 0

while monton > 0
    input "There are "; monton; " tokens remaining. How many would you like to take? "; llevar
    while llevar = 0 or llevar > 3
        input "You must take 1, 2, or 3 tokens. How many would you like to take "; llevar
    wend

    print "On my turn I will take "; 4 - llevar; " token(s)."
    monton = monton - 4
wend

print
print "I got the last token. I win! Better luck next time."
end

S-Basic

$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
    begin
      if tokens <= 3 then 
        taken = tokens
      else
        taken = 4 - taken
    end
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)
    if player = machine then print "I took:";taken
    tokens = tokens - 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!

Tiny BASIC

Works with: TinyBasic
10 LET H = 12
20 PRINT "There are"
30 PRINT H
40 PRINT "tokens remaining. How many would you like to take?"
50 INPUT T
60 IF T > 3 THEN GOTO 170
70 IF T < 1 THEN GOTO 170
80 LET H = H - T
90 IF H = 0 THEN GOTO 190
100 LET T = 4 - T
110 PRINT "I will take"
120 PRINT T
130 PRINT "tokens."
140 LET H = H - T
150 IF H = 0 THEN GOTO 210
160 GOTO 20
170 PRINT "You must take 1, 2, or 3 tokens."
180 GOTO 50
190 PRINT "Congratulations. You got the last token."
200 END
210 PRINT "I got the last token. I win. Better luck next time."
220 END

Tiny Craft Basic

5 cls
10 print "NIM"
20 let h = 12
30 print "There are ", h ," tokens remaining."
40 input "How many would you like to take? ", t
50 if t > 3 then 140
60 if t < 1 then 140
70 let h = h - t
80 if h = 0 then 160
90 let t = 4 - t
100 print "I will take ", t ," tokens."
110 let h = h - t
120 if h = 0 then 180
130 goto 30
140 print "You must take between 1 to 3 tokens."
150 goto 40
160 print "Congratulations. You got the last token."
170 goto 190
180 print "I got the last token. I win. Better luck next time."
190 shell "pause"

True BASIC

Works with: QBasic
Works with: Just BASIC
Works with: Liberty BASIC
LET monton = 12
LET llevar = 0

DO WHILE monton > 0
   PRINT "Quedan"; monton; "fichas. ¿Cuántas te gustaría tomar";
   INPUT llevar
   DO WHILE llevar = 0 Or llevar > 3
      PRINT "Debes tomar 1, 2, o 3 fichas. ¿Cuántas te gustaría tomar";
      INPUT llevar
   LOOP

   PRINT "Es mi turno, tomaré"; 4-llevar; "ficha(s)."
   LET monton = monton - 4
LOOP

PRINT
PRINT "Obtuve la última ficha. ¡Gané! Mejor suerte la próxima vez."
END

Yabasic

monton = 12
llevar = 0

while monton > 0
    print "There are ", monton, " tokens remaining. How many would you like to take? ";
    input "" llevar
    while llevar = 0 or llevar > 3
	    input "You must take 1, 2, or 3 tokens. How many would you like to take? " llevar
    wend
    
	print "On my turn I will take ", 4 - llevar, " token(s)."
    monton = monton - 4
wend

print "\nI got the last token. I win! Better luck next time."
end

BlooP

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

#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++

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#

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.


Clojure

(loop [n 12]
  (print (format "%s remain, take how many?\n> " n)) (flush)
  (let [v (try (Long. (clojure.string/trim (read-line)))
               (catch Exception _ 0))]
    (if (#{1 2 3} v)
      (do (println (format "You took %s, leaving %s, computer takes %s..."
                           v (- n v) (- 4 v)))
          (if (= 4 n)
            (println "Computer wins. 😐")
            (recur (- n 4))))
      (do (println "Please enter 1, 2, or 3...")
          (recur n)))))
Output:

Sample game:

harold@freeside:~/src/clj-nim$ rlwrap clj -M nim.clj 
12 remain, take how many?
3
You took 3, leaving 9, computer takes 1...
8 remain, take how many?
2
You took 2, leaving 6, computer takes 2...
4 remain, take how many?
1
You took 1, leaving 3, computer takes 3...
Computer wins. 😐


Common Lisp

(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

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."

Dyalect

print("There are twelve tokens.")
print("You can take 1, 2, or 3 on your turn.")
print("Whoever takes the last token wins.\n")

var tokens = 12 
while tokens > 0 {
    print("There are \(tokens) remaining.")
    print("How many do you take?")
    var playertake = Integer(readLine())

    if playertake < 1 || playertake > 3 {
        print("1, 2, or 3 only.")
    } else {
        tokens -= playertake
        print("I take \(4 - playertake).")
        tokens -= (4 - playertake)
    }
}

print("I win again.")

EasyLang

[Run it]

Translation of: BASIC256
token = 12
while token > 0
   repeat
      print "There are " & token & " tokens remaining."
      write "How many would you like to take? (1,2 or 3) "
      h = number input
      print h
      until h >= 1 and h <= 3
   .
   sleep 1
   print "On my turn I will take " & 4 - h & " token(s)."
   print ""
   token -= 4
.
print "I got the last token. I win! Better luck next time."

Factor

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 ] 2bi@ ;

: 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!

Fermat

heap:=12;
while heap>0 do
    !!('There are ',heap,' tokens left. How many do you want to take?');
    ?take;
    while take<1 or take>3 or take>heap do
        !!('You cannot take that number. Choose again.');
        ?take;
    od;
    !!('On my turn I will take ',4-take,' tokens.');
    heap:-(4);
od;

!!('I got the last token. Better luck next time!');
Output:
There are  12 tokens left. How many do you want to take?

>take := 4 You cannot take that number. Choose again. >take := 3 On my turn I will take 1 tokens. There are 8 tokens left. How many do you want to take? >take := 2 On my turn I will take 2 tokens. There are 4 tokens left. How many do you want to take? >take := 2 On my turn I will take 2 tokens.

I got the last token. Better luck next time!

Go

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!

Haskell

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!

J

Implementation:

nim=: {{
  prompt tokens=: 12
}}

prompt=: {{
  echo 'tokens: ',":tokens
  if. 1>tokens do.
    echo 'game over'
  else.
    echo 'take 1, 2 or 3 tokens'
  end.
}}

take=: {{
  assert. y e.1 2 3
  assert. 0=#$y
  echo 'tokens: ',":tokens=:tokens-y
  echo 'I take ',(":t=. 4-y),' tokens'
  prompt tokens=:tokens-t
}}

Sample session:

   nim''
tokens: 12
take 1, 2 or 3 tokens
   take 1
tokens: 11
I take 3 tokens
tokens: 8
take 1, 2 or 3 tokens
   take 3
tokens: 5
I take 1 tokens
tokens: 4
take 1, 2 or 3 tokens
   take 2
tokens: 2
I take 2 tokens
tokens: 0
game over

Java

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

Browser Version

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.

jq

Works with: jq

Also works with gojq, the Go implementation of jq.

def play($tokens):
  label $out
  | "There are \($tokens) tokens.  Take at most \([$tokens,3]|min) or enter q to quit.",
     ( foreach inputs as $in ( {$tokens};
         if $in == "q" then break $out
         else .in = $in
         | if $in | test("^[0-9]+$") then .in |= tonumber else .in = null end
         | if .in and .in > 0 and .in < 4
           then  (4 - .in) as $ct
           | (if $ct == 1 then "" else "s" end) as $s
           | .emit = "  Computer takes \($ct) token\($s);"
           | .tokens += -4
           else .emit = "Please enter a number from 1 to \([3, .tokens]|min) inclusive."
           end
	 end;
	   
     .emit,
	 if .tokens == 0
     then "\nComputer wins!", break $out
     elif .tokens < 0 then "\nCongratulations!", break $out
	 else "\(.tokens) tokens remain. How many tokens will you take?"
     end )) ;

play(12)
$ jq -nRr -f nim-game.jq
There are 12 tokens.  Take at most 3 or enter q to quit.
2
  Computer takes 2 tokens;
8 tokens remain. How many tokens will you take?
1
  Computer takes 3 tokens;
4 tokens remain. How many tokens will you take?
4
Please enter a number from 1 to 3 inclusive.
4 tokens remain. How many tokens will you take?
3
  Computer takes 1 token;

Computer wins!

Julia

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

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

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.

Mathematica/Wolfram Language

n = 12;
While[n > 0,
 c = ChoiceDialog["Current amount = " <> ToString[n] <> "\nHow many do you want to pick?", {1 -> 1, 2 -> 2, 3 -> 3}];
 n -= c;
 ChoiceDialog["Current amount = " <> ToString[n] <> "\nComputer takes " <> ToString[4 - c]];
 n -= (4 - c);
 ]
ChoiceDialog["Current amount = " <> ToString[n] <> "\n You lost!"]

MiniScript

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

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!

OCaml

Translation of: Python – with plurals added, loops turned to recursion and string input handled
let rec player_turn () =
  print_string "How many tokens would you like to take? ";
  let n = read_int_opt () |> Option.value ~default:0 in
  if n >= 1 && n <= 3 then n
  else (
    print_endline "Number must be between 1 and 3";
    player_turn ())

let computer_turn tokens = tokens mod 4

let plural_suffix = function 1 -> "" | _ -> "s"

let turn_report prefix taken tokens =
  Printf.printf "%s %d token%s.\n%d token%s remaining.\n%!" prefix taken
    (plural_suffix taken) tokens (plural_suffix tokens)

let rec play_game tokens =
  let player_tokens = player_turn () in
  let tokens = tokens - player_tokens in
  turn_report "You take" player_tokens tokens;
  let computer_tokens = computer_turn tokens in
  let tokens = tokens - computer_tokens in
  turn_report "Computer takes" computer_tokens tokens;
  if tokens = 0 then print_endline "Computer wins!" else play_game tokens

let () = play_game 12
Output:
How many tokens would you like to take? 3
You take 3 tokens.
9 tokens remaining.
Computer takes 1 token.
8 tokens remaining.
How many tokens would you like to take? 3
You take 3 tokens.
5 tokens remaining.
Computer takes 1 token.
4 tokens remaining.
How many tokens would you like to take? 3
You take 3 tokens.
1 token remaining.
Computer takes 1 token.
0 tokens remaining.
Computer wins!

Pascal

Works with: Free Pascal
program Nim;

{$mode objfpc}{$H+}

uses
  sysutils;

const
   maxtokens = 12;
   machine = 0;
   human = 1;

var
  player, tokens, taken : integer;

procedure Welcome;
begin
  writeln('The Game of Nim');
  writeln;
  writeln('This is one of many variants of the classic game of');
  writeln('Nim. We start with',maxtokens,' tokens. On each turn a player');
  writeln('takes between 1 and 3 tokens. The player who takes');
  writeln('the last token wins.');
  writeln;
end;

procedure ShowRemaining(n : integer);
begin
  writeln('Available tokens: ', n);
end;

function getnum(lowlim, toplim : integer) : integer ;
var
  n : integer;
  ok : boolean;
begin
  repeat
    write('You take: ');
    readln(n);
    if (n < lowlim) or (n > toplim) then
      begin
        writeln('Must take between ',lowlim,' and ',toplim);
        write('Try again: ');
        ok := false;
      end
    else
      ok := true;
  until ok;
  getnum := n;
end;

function PlayTurn(player, taken, tokens : integer) : integer;
begin
  if player = human then
      taken := getnum(1,3)
  else   { machine's move this time }
     begin
       if tokens <= 3 then
         taken := tokens     { take all if 3 or less remain }
       else
         taken := 4 - taken; { othewise, follow winning strategy }
     end;
  PlayTurn := taken;
end;

procedure Report(winner : integer);
begin
  if winner = human then
    writeln('You took the last one, so you win. Congratulations!')
  else
    writeln('I took the last one, so I win. Sorry about that.');
end;

begin
  Welcome;
  tokens := maxtokens;
  taken := 0;
  player := human;
  writeln('You go first');
  repeat
    ShowRemaining(tokens);
    taken := PlayTurn(player, taken, tokens);
    if player = machine then writeln('I took: ',taken);
    tokens := tokens - taken;
    if tokens > 0 then player := 1 - player;
  until tokens <= 0;
  report(player);
  writeln('Thanks for playing!');
  readln;
end.
Output:
The Game of Nim

This is one of many variants of the classic game of
Nim. We start with 12 tokens. On each turn a player
takes between 1 and 3 tokens. The player who takes
the last token wins.

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

Pebble

;NIM game example program for x86 DOS
;Compiles with Pebble to com file under 1kb.

program examples\nim

data

	int tokens[12]
	int take[0]

begin

	call intro

	label gameloop

		echo "There are"
		echo [tokens]
		echo " tokens remaining."
		crlf
		echo "How many would you like to take? "
		input [take]

		if [take] > 3 | [take] < 1 then

			echo "You must take between 1 to 3 tokens."

		endif

		if [take] <= 3 & [take] >= 1 then

			[tokens] = [tokens] - [take]

			if [tokens] = 0 then

				bell
				echo "Congratulations. You got the last token."
				pause
				kill

			endif

			[take] = 4 - [take]

			echo "I will take"
			echo [take]
			echo " tokens.
			[tokens] = [tokens] - [take]

			if [tokens] = 0 then

				echo "I got the last token. I win. Better luck next time."
				pause
				kill

			endif

		endif

	goto gameloop

end

sub intro

	cls
	echo "NIM game"
	crlf

ret

Perl

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

Translation of: Raku
without js -- getc
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.

Pike

Translation of: Python
int tokens = 12;

void get_tokens(int cur_tokens) {
	write("How many tokens would you like to take? ");
	int take = (int)Stdio.stdin->gets();

	if (take < 1 || take > 3) {
		write("Number must be between 1 and 3.\n");
		get_tokens(cur_tokens);
	}
	else {
		tokens = cur_tokens - take;
		write("You take " + (string)take + " tokens\n");
		write((string)tokens + " tokens remaing\n\n");
	}
}

void comp_turn(int cur_tokens) {
	int take = cur_tokens % 4;
	tokens = cur_tokens - take;
	write("Computer take " + (string)take + " tokens\n");
	write((string)tokens + " tokens remaing\n\n");
}

int main() {
	write("Pike Nim\n\n");
	while(tokens > 0) {
		get_tokens(tokens);
		comp_turn(tokens);	
	}
	write("Computer wins!\n");
	return 0;
}
Output:
Pike Nim

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

Computer take 2 tokens
8 tokens remaing

How many tokens would you like to take? 6
Number must be between 1 and 3.
How many tokens would you like to take? -2
Number must be between 1 and 3.
How many tokens would you like to take? 1
You take 1 tokens
7 tokens remaing

Computer take 3 tokens
4 tokens remaing

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

Computer take 1 tokens
0 tokens remaing

Computer wins!

Plain English

To run:
Start up.
Play the game of Nim.
Write "The computer wins! Press esc to exit." on the console.
Wait for the escape key.
Shut down.

A piece is a number.

To play the game of Nim:
Put 12 into a piece count.
Loop.
If the piece count is 0, exit.
Write "There are " then the piece count then " pieces remaining." on the console.
Ask the player to take some pieces.
Subtract the pieces from the piece count.
Ask the computer to take some other pieces given the pieces.
Subtract the other pieces from the piece count.
Repeat.

To ask the player to take some pieces:
Write "Would you like to take 1, 2, or 3 pieces? " on the console without advancing.
Read a count from the console.
If the count is not between 1 and 3, repeat.
Format the count and "piece" or "pieces" into a string.
Write "You took " then the string then "." on the console.
Put the count into the pieces.

To ask the computer to take some pieces given some other pieces:
Put 4 minus the other pieces into a count.
Format the count and "piece" or "pieces" into a string.
Write "The computer took " then the string then "." on the console.
Put the count into the pieces.
Output:
There are 12 pieces remaining.
Would you like to take 1, 2, or 3 pieces? apple
Would you like to take 1, 2, or 3 pieces? 4
Would you like to take 1, 2, or 3 pieces? 2
You took 2 pieces.
The computer took 2 pieces.
There are 8 pieces remaining.
Would you like to take 1, 2, or 3 pieces? 3
You took 3 pieces.
The computer took 1 piece.
There are 4 pieces remaining.
Would you like to take 1, 2, or 3 pieces? 1
You took 1 piece.
The computer took 3 pieces.
The computer wins! Press esc to exit.

Prolog

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

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!

Quackery

  [ $ "Take how many tokens? (1-3) "
    input
    trim reverse
    trim reverse
    $->n
    not iff drop again
    dup 1 4 within
    not iff drop again ]             is getmove ( --> n )

  [ 12
    [ say "There are "
      dup echo
      say " tokens." cr cr
      getmove tuck -
      4 rot - dup
      cr say "Computer takes "
      echo
      say "." cr cr
      -
      dup 0 = until ]
    drop
    say "Computer wins." cr ]        is play    ( -->   )
Output:

As a dialogue in the Quackery shell.

/O> play
... 
There are 12 tokens.

Take how many tokens? (1-3) 1

Computer takes 3.

There are 8 tokens.

Take how many tokens? (1-3) 2

Computer takes 2.

There are 4 tokens.

Take how many tokens? (1-3) 3

Computer takes 1.

Computer wins.

Stack empty.

R

## Nim game
##

tokens <- 12

while(tokens > 0) {
  print(paste("Tokens remaining:",tokens))
  playertaken <- 0
  while(playertaken == 0) {
    playeropts <- c(1:min(c(tokens,3)))
    playertaken <- menu(playeropts, title = "Your go, how many tokens will you take? ")
    tokens <- tokens - playertaken
    if(tokens == 0) {print("Well done you won, that shouldn't be possible!")}
  }
  cputaken <- 4 - playertaken
  tokens <- tokens - cputaken
  print(paste("I take",cputaken,"tokens,",tokens,"remain"))
  if(tokens == 0) {print("I win!")}

}
Output:
[1] "Tokens remaining: 12"
Your go, how many tokens will you take?  

1: 1
2: 2
3: 3

Selection: 3
[1] "I take 1 tokens, 8 remain"
[1] "Tokens remaining: 8"
Your go, how many tokens will you take?  

1: 1
2: 2
3: 3

Selection: 3
[1] "I take 1 tokens, 4 remain"
[1] "Tokens remaining: 4"
Your go, how many tokens will you take?  

1: 1
2: 2
3: 3

Selection: 3
[1] "I take 1 tokens, 0 remain"
[1] "I win!"

Racket

#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

(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.

Red

Red [
    date: 2021-10-24
    version: 0.6.4
    summary: "Demonstrate the game of Nim in Red for Rosetta Code"
]

take-tokens: function [
    "Ask the user to take between 1 and 3 tokens."
][
    forever [
        n: trim ask "Would you like to take 1, 2, or 3 tokens (q to quit)? "
        if n = "q" [quit]
        n: try [to-integer n]
        case [
            not integer? n [print "Please enter an integer."]
            any [n < 1 n > 3] [print "Please enter a number between 1 and 3."]
            true [return n]
        ]
    ]
]

tokens: 12
while [tokens > 0][
    print ["There are" tokens "tokens remaining."]
    n: take-tokens
    print ["You took" n "tokens."]
    tokens: tokens - n
    print ["Computer takes" 4 - n "tokens."]
    tokens: subtract tokens subtract 4 n
]
print "Computer wins!"
Output:
There are 12 tokens remaining.
Would you like to take 1, 2, or 3 tokens (q to quit)? 2
You took 2 tokens.
Computer takes 2 tokens.
There are 8 tokens remaining.
Would you like to take 1, 2, or 3 tokens (q to quit)? 3
You took 3 tokens.
Computer takes 1 tokens.
There are 4 tokens remaining.
Would you like to take 1, 2, or 3 tokens (q to quit)? 4
Please enter a number between 1 and 3.
Would you like to take 1, 2, or 3 tokens (q to quit)? apple
Please enter an integer.
Would you like to take 1, 2, or 3 tokens (q to quit)? 1
You took 1 tokens.
Computer takes 3 tokens.
Computer wins!

REXX

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

# Project : CalmoSoft Nim Game
# Date    : 16/04/2020-13:27:07
# Update  : 31/03/2021-19:41:09
# Author  : Gal Zsolt (~ CalmoSoft ~)
# Email   : <calmosoft@gmail.com>

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")
	    setWindowFlags(Qt_SplashScreen | Qt_CustomizeWindowHint) 
	    reSize(620,460)

            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()
     app.Quit()

Necessary image files: Images file

Output:

Nim Game - video

RPL

This task is an opportunity to showcase the use of both persistent variables and local variables, the latter vanishing once the program executed. The computer has been named "HAL" rather than "Player 2" or "Computer" to keep the message length under 16 characters, which is the width of the HP-28 display. To play, initialize the game by entering the word NUNIM, then input your moves followed by the word PLNIM until you will lose. The case for a human win is nevertheless coded to appear as a a fair game.

Works with: Halcyon Calc version 4.2.7
≪  "Tokens = " tokens →STR +
   "1..3 PLNIM?"
≫
'DispN' STO
≪ CLEAR 12 'tokens' STO        // emptying the stack and creating a persistent variable
  DispN
≫
'NUNIM' STO
≪ → move                     // creating a local variable, with value = content of stack level 1:
  ≪ IF { 1 2 3 } move POS 
     THEN 
        "You take " move →STR + 
        'tokens' move STO-    // substracting the value of a local variable from a persistent variable directly 
        IF tokens 0 ≤ 
        THEN "You win!" 
        ELSE 
           4 move - tokens MIN "HAL takes " OVER →STR + 'tokens' ROT STO- 
           IF tokens 0 ≤ THEN DROP "HAL wins!" ELSE DispN END 
        END 
     ELSE move →STR " is illegal" + DispN
     END 
 ≫  ≫
'PLNIM' STO  // 67 words, 4% stack
NUNIM
3 PLNIM
4 PLNIM
2 PLNIM
2 PLNIM
Output:
15: "Tokens = 12"
14: "1..3 PLNIM?"
13: "You take 3"
12: "HAL takes 1"
11: "Tokens = 8"
10: "1..3 PLNIM?"
9:  "4 is illegal"
8:  "Tokens = 8"
7:  "1..3 PLNIM?"
6:  "You take 2"
5:  "HAL takes 2"
4:  "Tokens = 4"
3:  "1..3 PLNIM?"
2:  "You take 2"
1:  "HAL wins!"

Ruby

[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

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!

Scala

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

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!

SNOBOL4

Works with: CSNOBOL4
  &TRIM = 1
  &DUMP = 1

  OUTPUT(.prompt, 9, 'T', '-')

********************************************************************************
* GETCOUNT() - Get the count of tokens to take.
********************************************************************************
  define('GETCOUNT()I')
  :(GETCOUNT.END)
GETCOUNT         OUTPUT = 'Enter a number between 1 and 3, blank line to exit.'
****************************************
* Data input and integrity check loop.
****************************************
GETCOUNT.LOOP    PROMPT = '> '
                 i = trim(INPUT)
*                Abort on nil entry.
                 eq(size(i), 0)                                                 :S(EXIT)
*                Check range.
                 integer(i)                                                     :F(GETCOUNT.INVALID)
                 lt(i, 4)                                                       :F(GETCOUNT.INVALID)
                 gt(i, 0)                                                       :F(GETCOUNT.INVALID)
*                It all checked out.
                 GETCOUNT = i                                                   :(RETURN)
****************************************
* An invalid entry was caught.
****************************************
GETCOUNT.INVALID OUTPUT = 'Invalid number.'                                     :(GETCOUNT.LOOP)
GETCOUNT.END

********************************************************************************
* MAINLINE CODE
********************************************************************************
MAIN      OUTPUT =
          OUTPUT = 'The mysterious game of Nim!'
          OUTPUT = 'Whoever takes the last token of twelve wins.'
          tokens = 12

****************************************
* MAIN LOOP
****************************************
MAIN.LOOP OUTPUT =
          OUTPUT = 'There are ' tokens ' tokens remaining.  How many do you want to take?'

********************
* Player turn.
********************
MAIN.P    ptake = getcount()
          tokens = tokens - ptake
          OUTPUT = 'You selected ' ptake ' tokens leaving ' tokens '.'
          lt(tokens, 0)                                                :S(ERROR)
          gt(tokens, 12)                                               :S(ERROR)
          eq(tokens, 0)                                                :S(MAIN.PWIN)

********************
* Computer turn.
********************
MAIN.C    ctake = 4 - ptake
          tokens = tokens - ctake
          OUTPUT = 'Computer selects ' ctake ' tokens leaving ' tokens '.'
          lt(tokens, 0)                                                    :S(ERROR)
          gt(tokens, 12)                                                   :S(ERROR)
          eq(tokens, 0)                                                    :S(MAIN.CWIN)

          :(MAIN.LOOP)

****************************************
* Player win is impossible.  Joke code.
****************************************
MAIN.PWIN OUTPUT = 'Player wins.  This is impossible.  You must have cheated.'
          OUTPUT = 'Formatting hard drive...'                                  :(ERROR)

****************************************
* Computer win is inevitable.
****************************************
MAIN.CWIN OUTPUT = 'Computer wins.'      :(EXIT)


********************************************************************************
* On a routine exit we turn off the variable dump.
* If we exit through an error (like branching to a non-existent label 'ERROR')
* then this code doesn't happen and variables get dumped and the line of the
* failed check getting printed.
********************************************************************************
EXIT      OUTPUT = 'Bye!'
          &DUMP = 0

END
The mysterious game of Nim!
Whoever takes the last token of twelve wins.

There are 12 tokens remaining.  How many do you want to take?
Enter a number between 1 and 3, blank line to exit.
> 4
Invalid number.
> 0
Invalid number.
> test
Invalid number.
> 3
You selected 3 tokens leaving 9.
Computer selects 1 tokens leaving 8.

There are 8 tokens remaining.  How many do you want to take?
Enter a number between 1 and 3, blank line to exit.
> 2
You selected 2 tokens leaving 6.
Computer selects 2 tokens leaving 4.

There are 4 tokens remaining.  How many do you want to take?
Enter a number between 1 and 3, blank line to exit.
> 1
You selected 1 tokens leaving 3.
Computer selects 3 tokens leaving 0.
Computer wins.
Bye!

Swift

var tokens = 12

while tokens != 0 {
  print("Tokens remaining: \(tokens)\nPlease enter a number between 1 and 3: ", terminator: "")

  guard let input = readLine(), let n = Int(input), n >= 1 && n <= 3 else {
    fatalError("Invalid input")
  }

  tokens -= n

  if tokens == 0 {
    print("You win!")

    break
  }

  print("I'll remove \(4 - n) tokens.")

  tokens -= 4 - n

  if tokens == 0 {
    print("I win!")
  }

  print()
}
Output:
Tokens remaining: 12
Please enter a number between 1 and 3: 3
I'll remove 1 tokens.

Tokens remaining: 8
Please enter a number between 1 and 3: 2
I'll remove 2 tokens.

Tokens remaining: 4
Please enter a number between 1 and 3: 3
I'll remove 1 tokens.
I win!

V (Vlang)

Translation of: Go
import os { input }

fn show_tokens(tokens int) {
    println('Tokens remaining $tokens\n')
}

fn main() {
    mut tokens := 12
    for {
        show_tokens(tokens)
        t := input('  How many tokens 1, 2, or 3? ').int()
        if t !in [1, 2, 3] {
            println('\nMust be a number between 1 and 3, try again.\n')
        } else {
            ct := 4 - t
            mut s := 's'
            if ct == 1 {
                s = ''
            }
            println('  Computer takes $ct token$s \n')
            tokens -= 4
        }
        if tokens == 0 {
            show_tokens(0)
            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 an integer 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!

Wren

Translation of: Go
import "io" for Stdin, Stdout

var showTokens = Fn.new { |tokens| System.print("Tokens remaining %(tokens)\n") }
 
var tokens = 12
while (true) {
    showTokens.call(tokens)
    System.write("  How many tokens 1, 2 or 3? ")
    Stdout.flush()
    var t = Num.fromString(Stdin.readLine())
    if (t.type != Num || !t.isInteger || t < 1 || t > 3) {
        System.print("\nMust be an integer between 1 and 3, try again.\n")
    } else {
        var ct = 4 - t
        var s = (ct != 1) ? "s" : ""
        System.write("  Computer takes %(ct) token%(s)\n\n")
        tokens = tokens - 4
    }
    if (tokens == 0) {
        showTokens.call(0)
        System.print("  Computer wins!")
        break
    }
}
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 an integer 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!

XPL0

Translation of: Go
func    ShowTokens(Tokens);
int     Tokens;
[Text(0, "Tokens remaining: ");
IntOut(0, Tokens);
CrLf(0);  CrLf(0);
];

int     Tokens, T, CT;
[Tokens:= 12;
loop    [ShowTokens(Tokens);
        Text(0, "  How many Tokens (1, 2 or 3)? ");
        T:= IntIn(0);
        if T < 1 or T > 3 then
                Text(0, "^m^jMust be a number between 1 and 3. Try again.^m^j^m^j")
        else    [CT:= 4 - T;
                Text(0, "  Computer takes ");
                IntOut(0, CT);
                Text(0, " token");
                if CT # 1 then ChOut(0, ^s);
                Text(0, ".^m^j^m^j");
                Tokens:= Tokens - 4;
                ];
        if Tokens = 0 then
                [ShowTokens(0);
                Text(0, "  Computer wins!^m^j");
                return;
                ];
        ];
]
Output:
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!

Z80 Assembly

Works with: CP/M 3.1 version YAZE-AG-2.51.2 Z80 emulator
Works with: ZSM4 macro assembler version YAZE-AG-2.51.2 Z80 emulator

Use the /S8 switch on the ZSM4 assembler for 8 significant characters for labels and names

This assembles to 99 bytes of instructions plus 98 bytes of static data for the texts and buffer, accounting for a total of 197 bytes. Not sure whether the 8080 and 8086 versions counted only instruction size or total program size, but the Z80 provides some powerful looping instructions that help to reduce program size.

Please note that I did not bother with conversion from input characters to integers and using comparisons to validate them, nor did I use arithmetic to calculate the computer's move. Instead, I used fixed strings and the cpdr instruction to look up the user's input as well as the computer's response. The CP/M BDOS call ensures that the user can enter a single character only.

	;
	; Nim game using Z80 assembly language
	;
	; Runs under CP/M 3.1 on YAZE-AG-2.51.2 Z80 emulator
	; Assembled with zsm4 on same emulator/OS, uses macro capabilities of said assembler
	; Created with vim under Windows
	;
	; 2023-04-28 Xorph
	;

	;
	; Useful definitions
	;

	bdos	equ 05h		; Call to CP/M BDOS function
	readstr	equ 0ah		; Read string from console
	wrtstr	equ 09h		; Write string to console

	cr	equ 0dh		; ASCII control characters
	lf	equ 0ah

	buflen	equ 01h		; Length of input buffer
	maxtok	equ 12		; Starting number of tokens

	;
	; Macro for BDOS calls
	;

readln 	macro	buf		; Read a line from input
	push	bc
	ld	c,readstr
	ld	de,buf
	call	bdos
	pop	bc
	endm


	;
	; =====================
	; Start of main program
	; =====================
	;

	cseg

	ld	de,nim		; Print title and initialize
	call	print
	ld	c,maxtok	; Register c keeps track of remaining tokens

loop:
	ld	de,tokens	; Print the remaining tokens
	call	print
	ld	b,c		; Use b for loop to print remaining tokens
printtk:
	ld	de,token
	call	print
	djnz	printtk
	
	ld	de,prompt	; Prompt user for input
	call	print
	readln	inputbuf

	ld	a,(bufcont)	; Now check input for validity and compute response
	ld	hl,validinp+2	; Start from end of valid string, so bc gets set to numeric equivalent
	push	bc		; Save token counter, use bc for cpdr
	ld	bc,3
	cpdr			; Use automatic search function
	jr	nz,printerr	; If input character not found, print error

	ld	hl,mymoves	; Get character for response into a
	add	hl,bc		; bc contains index into check string as well as response string
	pop	bc
	ld	a,(hl)
	ld	(outbuf),a	; Put it in output buffer

	ld	de,response	; Print the computer's move
	call	print

	ld	a,c		; Subtract 4 tokens from counter
	sub	4
	ld	c,a

	jr	nz,loop		; If not finished, repeat
	ld	de,lose		; Otherwise, player lost
	call	print

	ret			; Return to CP/M

printerr:			; Print error message and try again
	pop	bc
	ld	de,wronginp
	call	print
	jp	loop

print:				; Use subroutine instead of macro for smaller code
	push	bc
	ld	c,wrtstr
	call	bdos
	pop	bc
	ret

	;
	; ===================
	; End of main program
	; ===================
	;

	;
	; ================
	; Data definitions
	; ================
	;

	dseg

inputbuf:			; Input buffer
	defb	buflen		; Maximum possible length
	defb	00h		; Returned length of actual input
bufcont:
	defs	buflen		; Actual input area
nim:
	defb	'Nim$'		; Dialog texts
prompt:
	defb	cr,lf,'How many will you take (1-3)? $'
response:
	defb	cr,lf,'I take '	; No $ here! Saves one print command
outbuf:
	defb	' $'		; For printing response
tokens:
	defb	cr,lf,cr,lf,'Tokens: $'
token:
	defb	'|$'
lose:
	defb	cr,lf,'You lose!$'
wronginp:
	defb    cr,lf,'Wrong input$'
validinp:
	defb	'123'		; Valid input
mymoves:
	defb	'321'		; Computer's response
Output:
E>nim
Nim

Tokens: ||||||||||||
How many will you take (1-3)? 2
I take 2

Tokens: ||||||||
How many will you take (1-3)? 4
Wrong input

Tokens: ||||||||
How many will you take (1-3)? 3
I take 1

Tokens: ||||
How many will you take (1-3)? 1
I take 3
You lose!
E>