http://www.perlmonks.org?node_id=358750
Category: Fun Stuff
Author/Contact Info Delirium
Description: A command-line Tic-Tac-Toe bot. See here for my comments on the bot's design.
#!/usr/bin/perl

use strict;
use warnings;

my $board = "123456789";
my @wins = qw/ 123 456 789 147 258 369 159 357 /;

sub board {
    print "\n$_" for ($board =~ /(...)/g);
    if ($_ = shift) { print; exit; }
}

sub move { # Returns 0 for invalid move or piece, 1 for valid
    my $piece = shift; # X or O
    my $move  = shift; # 1 through 9
    return 0 if $piece !~ /^[XO]$/ or $move !~ /^[1-9]$/;
    return 0 unless $board =~ s/$move/$piece/;
    for (0..7) {
        board ("\n$piece wins!\n") if $wins[$_] =~ s/$move/$piece/ && 
+$wins[$_] eq $piece x 3;
    }
    board ("\nTie!\n") if $board !~ /\d/;
    return 1;
}

sub check {
    my $piece = shift; # X or O
    my $move  = shift; # 1 through 9
    return 0 if $piece !~ /^[XO]$/ or $move !~ /^[1-9]$/;
    return grep { /$piece/ && /$move/ && /\d${piece}?\d/ } @wins;
}

sub player {
    my $retval = 0;
    my $move;
    until ( $retval ) {
        print "\nMove : ";
        chomp ($move = <>);
        $retval = move('X', $move);
    }
}

sub bot {
    return if move('O', 5);
    my $move;
    my @open = ($board =~ /(\d)/g);
    for $move (@open) { return move('O',$move) if grep {/$move/ && /O\
+d?O/} @wins; }
    for $move (@open) { return move('O',$move) if grep {/$move/ && /X\
+d?X/} @wins; }
    for (@open) { return move('O',$_) if ( check('O', $_) > 1 ); }
    for $move (@open) {
        if ( my @seq = check('O', $move) ) {
            my ($opposite) = $seq[0] =~ /([^O$move])/;
            return move('O', $move) if ( check('X', $opposite) < 2 );
        }
    }
    move ('O', $open[0]);
}

while (1) {
    board;
    player;
    bot;
}
Replies are listed 'Best First'.
Re: Tic-Tac-Toe bot
by ChuckularOne (Prior) on Jun 03, 2004 at 17:41 UTC
    The only question is... Can it be beaten?