#!/usr/local/bin/perl
#
# game of tic-tac-toe for mosiac 2.0//http 1.0.5
#
# Jason Heirtzler
# 2/10/94
#
$host = "http://scv.bu.edu";
$href = "$host:5111";
#
#
$men = 9;
#$men = 16;
#
$giveup = "$host/Games/puzzle";
$gohome = "<P>[<A HREF=$host/Games/>Return to game page</A>]<P>[<A HREF=$host/SCVHomehtml>Return to Home page</A>]";
$newgame = "<p><a href=$host/Games//puzzle>New game?</a>\n$gohome";
if ( $men == 9 ) {
	$blank = 4;
	$endgame = "0,1,2,3,4,5,6,7,8,9";
	@valid = ( "1,3",   "0,2,4",   "1,5",
		   "0,4,6", "1,3,5,7", "2,4,8",
		   "3,7",   "4,6,8",   "5,7" );
}
if ( $men == 16 ) {
	$blank = 0;
	$endgame = "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
	@valid = ("1,4",    "0,5,2",     "1,6,3",     "2,7",
		  "0,5,8",  "1,4,6,9",   "2,5,7,10",  "3,6,11",
		  "4,9,12", "5,8,10,13", "6,9,11,14", "7,10,15",
		  "8,13",   "9,12,14",   "10,13,15",  "11,14" );
}
require 'getopts.pl';
#
&Getopts( 'd' );
#
$done = 0;
$_ = <>;
chop($_);
#
srand(time);
#
# initial board position is random
# called as follows:
#
#       http://lobster.bu.edu:5111/-
#
# for ex: GET /ooooooooo HTTP/1.0
$_ =~ s!GET /(\S+) .*!$1! unless ($opt_d);
#
$turn = -1;
/^(\d+)-.*/ && ( $turn = $1);  $turn++;
/^.*-(.*)/ && ( $move = $1);
#
print "Content-type: text/html\n\n";
#
# Print banner!
#
if (!$opt_d) {
    print "<HTML>\n<TITLE>$men PUZZLE</TITLE>\n";
    print "<H1>$men Puzzle</H1>\n";
    print "</HTML>\n";
}

#
# takes a string of the form "1,2,3" and makes it
# a little harder to understand
#
sub recode {
   local( $arg ) = @_;
   local( @f, $x, @y );

   @f = split( ',', $arg );
   foreach (@f) {
      $x = $_ + 0;
      if ( $x >= 32) { $x = $x & 15; }
      else { $x = $x + int(rand(7))*32 + 32; }
      $x = $x ^6;
      push( @y, $x );
   }
  return(join( ',', @y ));
}

#
# isvalidmove( "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15",
#              "4,1,2,3,0,5,6,7,8,9,10,11,12,13,14,15" );
#
sub isvalidmove
{
    local( $start, $end ) = @_;
    local( @s, @e, $i, $j );

    @s = split(/,/, $start);
    @e = split(/,/, $end);
    #
    for ( $i=0; $i<$men; $i++) {
	if (@s[$i] eq $blank) {
	    @v = split(/,/, @valid[$i]);
	    for ( $j=$#v; $j>=0; $j-- ) {
		#print "cmp ", @e[@v[$j]], " 0\n";
		if (@e[@v[$j]] eq $blank ) {
		    # print "valid\n";
		    return(1);
		}
	    }
	    #print "not valid\n";
	    return(0);
	}
    }
    die "no blank in start string?";
}

#
# randomize the board.  must work backwards from
# the solved board as random combinations of the
# pieces may not be solvable.
#
sub scramble
{
    local( @e, $b, $i, $t, $o );
    #
    @e = split( /,/, $endgame );
    #
    # find blank space (always first one, really)
    #
    for ( $i=length($endgame); $i>=0; $i-- ) {
	$b = $i if ( @e[$i] eq $blank );
    }
    #
    #
    for ( $i=0; $i<500; $i++ ) {
	#
	# get list of valid moves
	@v = split(/,/, @valid[$b]);
	#print "   from $b valid moves: ", join( ',', @v ), "($#v)\n";
	#print "   picking from [0..", $#v, "]\n";
	#
	$z = int(rand($#v)+0.5);
	#print "   taking number $z, ie ", @v[$z], "\n";
	# randomly pick one of them
	$r = @v[$z];
	#
	print "switch $b and $r elts\n" if ($opt_d);
	# now switch $b and $r elements
	$t = @e[$r];
	@e[$r] = @e[$b];
	@e[$b] = $t;
	# blank space has now moved
	$b = $r;
    }
    return(join(',',@e));
}
#
sub showboard
{
    local( $what ) = @_;
    local( @w, $i, $j, $x, $y );
    #
    # find the blank square
    #
    @w = split( /,/, $what );
    for ( $i= $#w; $i>=0; $i-- ) {
	$b = $i if ( @w[$i] eq $blank );
    }
    print "blank is $b\n" if ($opt_d);
    #
    $y = 4 if ($men == 16);
    $y = 3 if ($men == 9);
    #
    for ( $i = 0; $i<$y; $i++ ) {
	for ( $j = 0; $j<$y; $j++ ) {
	    $x = $i*$y+$j;
	    print " n$x " if ($opt_d);
	    #
	    # try switching the blank with this
	    # square.
	    @s = @w;
	    $t = @s[$x];
	    @s[$x] = @s[$b];
	    @s[$b] = $t;
	    #
	    $t = join( ',', @s );
	    if (&isvalidmove( $t, $what)) {
		if ($opt_d) {
		    print "+";
		}
		else {
		    $w = &recode( $t );
		    print "<A HREF=\"$href/$turn-$w\">"
			unless ($done);
		}
	    }
	    else {
		print "-" if ($opt_d);
	    }
	    print "<IMG SRC=\"$host/Games/P/p", @w[$x], ".gif\"></a>\n"
		unless ($opt_d);
	}
	if ($opt_d) { print "\n"; }
	else { print "<br>\n"; }
    }
}
#
#print &isvalidmove( "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15",
#       "2,1,0,3,4,5,6,7,8,9,10,11,12,13,14,15" );
#
if ($move eq "random") {
    $turn = 0;
    $move = &scramble;
}
else {
    $move = &recode($move) unless ($opt_d);
}
#
if ($move eq "$endgame") {
    $done++;
    &showboard($move);
    print "<h2>You did it!!</h2>";
    print "<h2>Solved in $turn moves.</h2>";
    print "$newgame";
    #
#   $MAIL = "/usr/ucb/Mail";
#   $MAIL = "/usr/sbin/Mail" if ( -f "/usr/sbin/Mail" );
    #
#   open( M, "| $MAIL -s puzzle_solved jdh" );
#   print M "9-puzzle solved in $turn moves\n";
#   close( M );
    exit(0);
}
#
#$move = $endgame;
#print "<pre>$move</pre>\n";
&showboard($move);
if ($turn == 0) {
    print "<h2>Ready!</h2>\n";
    print "Click on a piece to move it to the black square.\n";
}
else {
    print "<h2>Moves: $turn</h2>\n";
    print "Click on a piece to move it to the black square.<p>\n";
    print "Give up?  Click <a href=\"$giveup\">here</a>\n"
	unless ($turn == 1);
}
exit(0);
