aboutsummaryrefslogtreecommitdiff
path: root/challenge-104/e-choroba/perl/ch-2.pl
blob: 3ee08a74c41143ddf092714722a6e3bac1068d43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

# Run "dot -Tpng ch-2.dot" to generate a graph of all the possible
# transitions between states. Ending in 0 means a victory; 0 is
# reachable from 1, 2, and 3, hence their green colour. 4 on the other
# hand can only reach the green nodes, so you can't win if you get
# there. And so on.

{   package Game::Nim;
    use Types::Standard qw( Int Enum Bool );
    use Moo;

    has turn => (is      => 'rw',
                 isa     => Enum[qw[ me you ]],
                 default => sub { qw( me you )[int rand 2] });

    has remainder => (is      => 'rwp',
                      isa     => Int,
                      default => sub { 12 });

    has done => (is      => 'rwp',
                 isa     => Bool,
                 default => 0);

    sub _my_turn {
        my ($self) = @_;
        my $r = $self->remainder;
        my $pick = 0;
        $pick = ($r % 4) || 1 + int rand 3;
        say 'Picking ', $pick;
        $self->_set_remainder($self->remainder - $pick);
    }

    sub _your_turn {
        my ($self) = @_;
        my $pick = '0E0';
        until (0 < $pick && $pick < 4 && $pick <= $self->remainder) {
            say 'Invalid choice.' unless '0E0' eq $pick;
            print 'How many do you want to pick? ';
            chomp( $pick = <> );
            $pick =~ s/[^0-9]//g;
        }
        $self->_set_remainder($self->remainder - $pick);
    }

    sub play {
        my ($self) = @_;
        return if $self->done;

        say "Remaining: ", $self->remainder;

        if ($self->turn eq 'me') {
            $self->_my_turn;

        } else {
            $self->_your_turn;
        }

        if (0 == $self->remainder) {
            say 'Winner: ', $self->turn;
            say 'Congratulations!' if 'you' eq $self->turn;
            $self->_set_done(1);
        }

        $self->turn({ me => 'you', you => 'me' }->{ $self->turn });
    }
}

my $game = 'Game::Nim'->new;
$game->play until $game->done;