Nim game

From Rosetta Code
Revision as of 03:26, 11 April 2019 by rosettacode>Gerard Schildberger (added "games" and "puzzles" category to this task.)


Nim game is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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 player goes first, and the computer always wins. The game should enforce the rules.

AsciiDots

<lang AsciiDots> %$MXTRL .-$"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

</lang>

Output:
Nim Dots v0.5 by Prof_Apex

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!

C++

Translation of: Go

<lang cpp>#include <iostream>

  1. 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;
       }
   }

}</lang>

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!

Common Lisp

<lang 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!") </lang>

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!

Go

<lang 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
       }
   }

}</lang>

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!

Kotlin

Translation of: Go

<lang scala>// 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
       }
   }

}</lang>

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!

Python

<lang Python> 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!") </lang>

Output:
Py Nim 0.5 by Prof_Apex

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!