💾 Archived View for thfr.info › cgi-source › tic-tac-toe.cgi captured on 2023-01-29 at 02:32:13.

View Raw

More Information

-=-=-=-=-=-=-

#!/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";
	}
}