TL;DR

On with TASK #2 from the Perl Weekly Challenge #104. Enjoy!

The challenge

Write a script to simulate the NIM Game.

It is played between 2 players. For the purpose of this task, let assume you play against the machine.

There are 3 simple rules to follow:

  1. You have 12 tokens
  2. Each player can pick 1, 2 or 3 tokens at a time
  3. The player who picks the last token wins the game

The questions

Wow… an interactive game, right?

Should the computer play a perfect game if possible?

Should this game be generalizable to different number of tokens and items that can be taken?

Should we be patient with wrong inputs?

The solution

Here is my solution…

#!/usr/bin/env perl
use 5.024;
use warnings;
use experimental qw< postderef signatures >;
no warnings qw< experimental::postderef experimental::signatures >;

$|++;

sub input ($description, @allowed) {
   my $input;
   while (! (defined($input) && grep { $input eq $_ } @allowed)) {
      say $description;
      print {*STDOUT} 'your choice > ';
      chomp($input = <STDIN>);
   }
   return $input;
}

sub nim_game {
   my $player = input(<<'END', 0, 1);
Which player should start?
0. me (computer)
1. you (human)
END

   my $tokens = 12;
   while ($tokens > 0) {
      my $grab;
      if ($player) {
         $grab = input(<<'END', 1, 2, 3);
How many tokens do you want to take? (1, 2, or 3)
END
      }
      else {
         $grab = $tokens % 4 || 1 + int(rand 3);
         say "I take $grab", $grab == 1 ? ' token' : ' tokens';
      }
      $tokens -= $grab;
      say $tokens, ($tokens == 1 ? ' token ' : ' tokens '), 'left';
      $player = 1 - $player;
   }

   say $player ? 'I win!' : 'You win!';
}

nim_game();

The game initially asks the human player who should go first. In this setup, the one moving first is guaranteed to lose if the other player adopts the right strategy.

The computer player tries to adopt the right strategy if possible, otherwise it draws a random move.

The input function waits for one of the allowed inputs to be put by the user, re-iterating the question if needed. There’s no exit loop if the user decides to be a troll 🤓

Stay safe, have fun and… let the computer go first 😉!