#!/usr/bin/perl use strict; use warnings; use CGI; my $gem_header = "20 text/gemini\r\n"; my @positions = ( 'ul', 'u', 'ur', 'l', 'c', 'r', 'dl', 'd', 'dr', ); my @valid_vals = ( ' ', 'x', 'o' ); my %fields = map { $_ => ' ' } @positions; my @win_combos = ( [ 'ul', 'u', 'ur', ], [ 'l', 'c', 'r', ], [ 'dl', 'd', 'dr', ], [ 'ul', 'l', 'dl', ], [ 'u', 'c', 'd', ], [ 'ur', 'r', 'dr', ], [ 'ul', 'c', 'dr', ], [ 'ur', 'c', 'dl', ], ); my %print_positions = ( 'ul' => 'top left', 'u' => 'top center', 'ur' => 'top right', 'l' => 'left', 'c' => 'center', 'r' => 'right', 'dl' => 'bottom left', 'd' => 'bottom center', 'dr' => 'bottom right', ); my $q = CGI->new($ENV{'QUERY_STRING'}); sub print_fields { print "```\n"; print "\n"; print "$fields{'ul'}|$fields{'u'}|$fields{'ur'}\n"; print "-----\n"; print "$fields{'l'}|$fields{'c'}|$fields{'r'}\n"; print "-----\n"; print "$fields{'dl'}|$fields{'d'}|$fields{'dr'}\n"; print "```\n"; } sub has_won { my $player = shift; foreach my $combo (@win_combos) { my $combo_count = 0; foreach my $field (@{$combo}) { if ( $fields{$field} eq $player ) { $combo_count++; } } if ( $combo_count == 3 ) { return 1; } } return 0; } print $gem_header; my %params = $q->Vars; if ( defined($q) ) { foreach my $p ( keys %params ) { if ( exists ( $fields{$p} ) ) { $fields{$p} = $params{$p}; } } } # sanitize so that only ' ', 'x', or 'o' can be assigned foreach my $pos (@positions) { my $valid = 0; foreach (@valid_vals) { if ( $_ eq $fields{$pos} ) { $valid = 1; } } $fields{$pos} = ' ' unless ($valid); } # check if player has won if ( has_won('x') ) { print "# You won!\n\n"; print_fields; print "=> tic-tac-toe.cgi Restart?\n"; exit; } # server move - pick a random one of the available fields my @candidate_moves = grep { $fields{$_} eq ' ' } keys %fields; my $server_move = $candidate_moves[ rand @candidate_moves ]; if (defined($server_move)) { $fields{$server_move} = 'o'; } # check if server has won if ( has_won('o') ) { print "# You lost!\n\n"; print_fields; print "=> tic-tac-toe.cgi Restart?\n"; exit; } print "# Tic-Tac-Toe\n"; print_fields; # build the string containing previous moves my $prev_moves = ''; foreach my $pos (@positions) { if ( $fields{$pos} ne ' ' ) { # can only be 'x' or 'o', see above $prev_moves .= "$pos=$fields{$pos}&"; } } foreach my $pos (@positions) { if ( $fields{$pos} eq ' ' ) { print "=> tic-tac-toe.cgi?$prev_moves$pos=x $print_positions{$pos}\n"; } }