Skip to content

Instantly share code, notes, and snippets.

@akarelas
Last active November 18, 2017 08:34

Revisions

  1. akarelas revised this gist Nov 18, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions tictactoe.pl
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,12 @@
    #!/usr/bin/env perl

    use v5.22;
    use v5.20;
    use warnings;
    use lib 'local/lib/perl5';

    use List::Util qw/ max all /;
    use List::MoreUtils 'indexes';
    use experimentals;
    use experimental 'signatures';

    my @board = (0) x 9;

  2. akarelas created this gist Nov 18, 2017.
    106 changes: 106 additions & 0 deletions tictactoe.pl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    #!/usr/bin/env perl

    use v5.22;
    use warnings;
    use lib 'local/lib/perl5';

    use List::Util qw/ max all /;
    use List::MoreUtils 'indexes';
    use experimentals;

    my @board = (0) x 9;

    my @winning_rows = (
    [0..2], [3..5], [6..8],
    [0, 3, 6], [1, 4, 7], [2, 5, 8],
    [0, 4, 8], [2, 4, 6],
    );

    sub eqq ($x, $y) {
    if (! defined $x) {
    return ! defined $y;
    }
    defined $y or return !!0;
    ref($x) eq ref($y) or return !!0;
    return $x eq $y;
    }

    sub status (@board) {
    foreach my $row (@winning_rows) {
    my @vals = map $board[$_], @$row;
    if ($vals[2] == $vals[0] and $vals[1] == $vals[0] and $vals[0]) {
    return $vals[0];
    }
    }
    return 0;
    }

    sub display (@board) {
    for (my $i = 0; $i < 9; $i++) {
    my $num = $board[$i];
    print $num || '_';
    print ' ';
    if ($i % 3 == 2) { print "\n"; }
    }
    say '';
    }

    sub best_move ($player, $is_original, @board) {
    my $status = status(@board);
    if ($status) {
    return (undef, ($status == $player) ? 1 : -1);
    }
    if (all {$_} @board) { return (undef, 0); }
    my @indexes = indexes {! $_} @board;
    my @payouts = (-2) x 9;
    foreach my $index (@indexes) {
    my @new_board = @board;
    $new_board[$index] = $player;
    my $other_player = 3 - $player;
    my ($other_best_move, $other_payout) = best_move($other_player, 0, @new_board);
    $payouts[$index] = -$other_payout;
    if (! $is_original and $payouts[$index] == 1) { last; }
    }
    my $max_payout = max(@payouts);
    my @possible_moves = indexes {$_ == $max_payout} @payouts;
    my $move = $possible_moves[$is_original ? (int rand @possible_moves) : 0];
    return wantarray ? ($move, $max_payout) : $move;
    }

    print "Play first? (y/n) ";
    my $who_plays = 2 - !!(scalar(<STDIN>) =~ /\Ay/i);

    until (status(@board) or all {$_} @board) {
    display(@board);
    my $index;
    if ($who_plays == 1) {
    INPUT: while (1) {
    print "Play where? row,column eg 3,2 : ";
    my $ans = <STDIN>;
    my ($y, $x) = $ans =~ /(\d)/g;
    all { /[123]/ } ($x, $y) or next INPUT;
    $index = ($y - 1) * 3 + ($x - 1);
    eqq($board[$index], 0) or next INPUT;
    say '';
    last;
    } continue {
    say "Wrong input, try again";
    }
    }
    else {
    $index = best_move(2, 1, @board);
    }
    $board[$index] = $who_plays;
    $who_plays = 3 - $who_plays;
    }

    my $who_won = status(@board);
    if ($who_won == 1) {
    say 'You won!';
    } elsif ($who_won == 2) {
    say 'I won!';
    } else {
    say 'Tie!';
    }

    display(@board);