#!/usr/bin/perl
#

#
#A very basic tic-tac-toe program (the computer chooses randomly)
#


use strict;
use CGI;
use Socket;

my ($rounds, $round_temp, $squares, $page, $x, $y, $z, $cell, $player_move, @available_choices, $computer_move, @choices, $round, $winner, $player_move_pretty, $computer_move_pretty);
my ($round_minus_one);  #bug fix (was recording moves for round1 as round2

$page = CGI->new();

print $page->header;
print $page->start_html();

# print table beginnings

print ("<table width=\"90\%\" border=0 cellpadding=15>\n");
print ("<tr valign=middle>\n");

# left cell is tic tac toe table

print ("<td align=center>\n");

#
# find out which round it is so we know how to define $squares
#

unless ($page->param('round')) {
   $round = 0;
}else {
   $round = $page->param('round');
}

#
# set array of tic tac toe squares
#

if ($round > 0) {
  $squares = [
            [
             $page->param('[0][0]'), 
             $page->param('[0][1]'), 
             $page->param('[0][2]')
            ],
            [
             $page->param('[1][0]'), 
             $page->param('[1][1]'), 
             $page->param('[1][2]')
            ],
            [
             $page->param('[2][0]'), 
             $page->param('[2][1]'), 
             $page->param('[2][2]')
            ]
           ];
}else {
   $squares = [
               ['?', '?', '?'],
               ['?', '?', '?'],
               ['?', '?', '?']
              ];
}

#
# set array for determing history of moves (recorded by round)
#

if ($round > 0) {
   $rounds = {
              round1 => {
                         player => $page->param('round1_x'),
                         computer => $page->param('round1_o')
                        },
              round2 => {
                         player => $page->param('round2_x'),
                         computer => $page->param('round2_o')
                        },
              round3 => {
                         player => $page->param('round3_x'),
                         computer => $page->param('round3_o')
                        },
              round4 => {
                         player => $page->param('round4_x'),
                         computer => $page->param('round4_o')
                        },
              round5 => {
                         player => $page->param('round5_x'),
                         computer => $page->param('round5_o')
                        }
             };
}else {
   $rounds = {
               round1 => {
                          player => '?',
                          computer => '?'
                         },
               round2 => {
                          player => '?',
                          computer => '?'
                         },
               round3 => {
                          player => '?',
                          computer => '?'
                         },
               round4 => {
                          player => '?',
                          computer => '?'
                         },
               round5 => {
                          player => '?',
                          computer => '?'
                         }
              };
}
            
#
# increment $round to give it a new hidden value
#

$round = $round + 1;
$round_minus_one = $round - 1;
print ("Round is: $round<br>\n");

##
## get player move using subroutine (subroutine stores it to $squares array)
##

$player_move = $page->param('choice');
if ($player_move) {
   $round_temp = "round" . $round_minus_one;
   player_moves($player_move, $page, $squares);
   $player_move_pretty = make_move_pretty($player_move);
   $rounds->{$round_temp}->{'player'} = $player_move_pretty;

#
# evaluate for winner after player moves
#

   $winner = evaluate_board($squares);
   if ($winner eq "x") {
      print ("<font color='blue'>Player Won!</font><p>\n");
      print_final_table($squares, $page, $winner, $round, $rounds);
   }else {

#
# check to see if player won. if player won, don't do the rest of this


#
# get available choices for computer choices
#

      @available_choices = get_available_choices($squares);

#
# get computer move
#
      $computer_move = get_computer_choice(@available_choices);
      ($x, $y) = split(/:/, $computer_move);  
         #get coordinates for computer move and store in $x and $y
      $squares->[$x][$y] = "o";   ## change square to "o"
      $round_temp = "round" . $round_minus_one;
      $computer_move_pretty = make_move_pretty($computer_move);
      $rounds->{$round_temp}->{'computer'} = $computer_move_pretty;
   
   } #matches else {

} #matches if ($player_move) 


#
# now that we have the array with computer and player choices, see if there is a winner
#
$winner = evaluate_board($squares);
if ($winner eq "o") {  #we already checked for x before
   print ("<font color = 'blue'>Computer Won!</font><p>\n");
   print_final_table($squares, $page, $winner, $round, $rounds);
}

if (($winner ne "o") and ($winner ne "x")) {
   print ("<font color='blue'>No winner yet</font><p>\n"); 

# start form

   print $page->startform(-method=> 'POST');

#print hidden values in form

   print_hidden_values($page, $squares, $rounds);

# print hidden value for $round

   print "<input type='hidden' name = 'round' value='$round'>\n"; 

# print hidden values for saving rounds


# start tic tac toe table

   print ("<table border=1 cellpadding=10>\n<tr>");

#
# look through array elements ($squares) and find x's or o's
# for all squares with no value, print a checkbox with the coordinates
# in the form of [0][0] as its name
#

   foreach $x(0..2) {
      if ($squares->[0][$x] eq "?") {
         print_cell($squares, $page, $x, "0");
      }else {
         print ("<td>" . $squares->[0][$x] . "</td>\n");
      } 
   }

   print ("</tr><tr>\n");
   foreach $x(0..2) {
      if ($squares->[1][$x] eq "?") {
         print_cell($squares, $page, $x, "1");
      }else {
         print ("<td>" . $squares->[1][$x] . "</td>\n");
      }
   }

   print ("</tr><tr>\n");
   foreach $x(0..2) {
      if ($squares->[2][$x] eq "?") {
         print_cell($squares, $page, $x, "2");
      }else {
         print ("<td>" . $squares->[2][$x] . "</td>\n");
      }
   }

   print ("</tr></table>");

#
# print warning about picking multiple squares
#

   print $page->submit();

   print ("<p><font color='red'>Note: if you pick more than one square, your choice will be the upper and leftmost square that you choose!!</font><p>\n");


   print $page->endform();
}

# end table cell

print ("</td>\n");
print ("<td align=middle>\n");

# get printable versions of moves and print choices

if (($player_move) or ($computer_move)) {
   foreach $x(1..$round_minus_one) {
      $round_temp = "round" . $x;
      print ("<p><b>Round $x:</b><br>\n");
      print ("\tplayer: " . $rounds->{$round_temp}->{'player'} . "<br>\n");
      print ("\tcomputer: " . $rounds->{$round_temp}->{'computer'} . "<br>\n");
   }
}else {
   print ("No moves yet.\n");
}

# end table

print ("</td></tr></table>\n");

print $page->end_html();


sub player_moves {
   my $move = $_[0];  ##get move
   my $page = $_[1];  ## import page object
   my $squares = $_[2];  ## import array so we can change square
   my ($x, $y, $z);

   foreach $x(0..2) {
      foreach $y(0..2) {         ##test for each square
         $z = "[$x][$y]";
         if ($move eq $z) {
            $squares->[$x][$y] = "x";   ## define array element for choice
         }
      }
   }
}

sub print_cell {
   my $squares = $_[0];  ##import semi-existant array of squares
   my $page = $_[1];     ##import html stuffs
   my $x = $_[2];        ##import the number that the foreach is on 
   my $row = $_[3];      ##import the row we are on
   my $cell = "[$row][$x]";  ##get square coordinates for use in naming checkbx
   
   print ("<td>");
   print ("<input type='checkbox' name='choice' value='$cell'>\n"); 
   print ("</td>");
}

sub get_available_choices {
   my $squares = $_[0];
   my ($x, $y, $z);
   my @available_choices = ();

   foreach $x(0..2) {
      foreach $y(0..2) {
         unless (($squares->[$x][$y] eq "x") or ($squares->[$x][$y] eq "o")) {
             $z = "$x:$y";    ## return in this form for later use (so we can split it by the colon)
             push (@available_choices, $z);
         }
      }
   }
   return @available_choices;
}

sub get_computer_choice {
   my @available_choices = @_;
   my $length = @available_choices;
   my $number = int(rand() * ($length - 1));
   my $choice = $available_choices[$number];
   return $choice;  ## this will be a coordinate, in the form of $x:$y from $z above
}
   

sub print_hidden_values {
   my $page = $_[0];
   my $squares = $_[1];
   my $rounds = $_[2];
   my ($x, $y, $cell, $round);
   
   #print hidden values for cells
   foreach $x(0..2) {
        foreach $y(0..2) {
           $cell = "[$x][$y]";
           print ("<input type='hidden' name='$cell' value='" . $squares->[$x][$y] . "'>"); 
           print ("\n");
        }
   }
   
   #print hidden values for rounds (history)
   foreach $x(1..5) {
      $round = "round" . $x;
      print ("<input type='hidden' name='$round" . "_x' value ='" . $rounds->{$round}->{'player'} . "'>\n");
      print ("<input type='hidden' name='$round" . "_o' value='" . $rounds->{$round}->{'computer'} . "'>\n");
   }
}


sub evaluate_board {
    my ($squares) = $_[0];
    my ($x, $y, $winner);

    foreach $x (0..2) {
        if (
            ($squares->[$x][0] eq $squares->[$x][1]) and
            ($squares->[$x][1] eq $squares->[$x][2]) 
           ) {
            $winner = $squares->[$x][0];
            return $winner;
        }
    }
    foreach $y (0..2) {
        if (
            ($squares->[0][$y] eq $squares->[1][$y]) and
            ($squares->[1][$y] eq $squares->[2][$y]) 
            ) {
            $winner = $squares->[0][$y];
            return $winner;
        }
    }
    if (
        (($squares->[1][1] eq "x") or ($squares->[1][1] eq "o")) 
        and
         (
          (($squares->[0][0] eq $squares->[1][1]) and
           ($squares->[1][1] eq $squares->[2][2]))
          or
          (($squares->[0][2] eq $squares->[1][1]) and
           ($squares->[1][1] eq $squares->[2][0]))
         )
        ) {
        $winner = $squares->[1][1];
        return $winner;
    }
}

sub print_final_table {
   my $squares = $_[0];
   my $page = $_[1];
   my $winner = $_[2];
   my $round = $_[3];
   my $rounds = $_[4];
   my ($visitor, $visitor_name, $time);

   ## print ending table

   print $page->startform(action=>'tic_tac.cgi',
                          method=>'POST'
                         );

   print_hidden_values($page,$squares,$rounds);

   print ("<input type='hidden' name='round', value='$round'>\n");

   print ("<table border=1 cellpadding=10>\n");
   print ("<tr valign=middle>\n");
   foreach $x(0..2) {             ##print first row
      print ("<td align=center>" . $squares->[0][$x] . "</td>\n");
   }
   print ("</tr><tr valign=middle>\n");
   foreach $x(0..2) {             ##print second row
      print ("<td align=center>" . $squares->[1][$x] . "</td>\n");
   }
   print ("</tr><tr valign=middle>\n");
   foreach $x(0..2) {             ##print third row
      print ("<td align=center>" . $squares->[2][$x] . "</td>\n");
   }
   print ("</tr></table><p>\n");

   print ("<a href=\"http://soya.serve.com/cgi-bin/tic_tac.cgi\">Play Again!</a>");

   print $page->end_html();

   #print log of play

   $visitor = $page->remote_host();
   if ($visitor =~ /\d*\.\d*\.\d*\.\d*/) {
    $visitor_name = gethostbyaddr(inet_aton($visitor), AF_INET);
   }

   $time = localtime(time());

   open (MAIL, "| /usr/sbin/sendmail -t");
   print MAIL "To: author\@example.com\n";
   print MAIL "Subject: tic tac toe results\n";
   print MAIL "\n$visitor, $visitor_name: $time: $winner on round $round";
   close MAIL;
}

sub make_move_pretty {
   my ($move) = $_[0];  #get move (either $player_move or $computer_move
   my (%squares_names, $pretty_move);

   if ($move =~ /:/) {
      $move =~ s/^(\d):(\d)/$1$2/;
   }
   else {
      $move =~ s/^\[(\d)\]\[(\d)\]/$1$2/;
   }

   %squares_names = ("00" => "top left",
                     "01" => "top center",
                     "02" => "top right",
                     "10" => "center left",
                     "11" => "center",
                     "12" => "center right",
                     "20" => "lower left",
                     "21" => "lower center",
                     "22" => "lower right"
                    );

  $pretty_move = $squares_names{$move};
  return $pretty_move;
}


