#!/usr/bin/perl

#############################
# eMineSweeper              #
######################################################
# By: Po-Han Lin 			             #
# pohanl@hotmail.com       			     #
# http://edepot.com         			     #
#                           			     #
# This script freely distributable and installable   #
# on the condition that the entire script is intact. #
# You may NOT modify it with the exception of the    #
# "domain name line" and "location of perl line"     #
# to make it work on your server. 		     #
# (credit info located here and at the footer when   #
# this script is executed must not be modifed or     #
# removed)                  			     # 
#                           			     #
######################################################
use strict;


# This is the only line you need to modify...
# Change the line to reflect the domain and location where you
# put this script on your server.

my($theurl)="http://YourDomainName/cgi-bin/minesweeper.pl";


##########################################################################
################## Do Not Modify Anything Below This Line ################
##########################################################################

my($markedbomb,$time_start,$Row,$Col,$theRow,$theCol,@Mine,@Sweep,$end,$total,$temp,$y,$x,$count,$in,@in,%in);

my($i, $loc, $key, $val);
if ($ENV{'REQUEST_METHOD'} eq "POST") {
  read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
}
@in = split(/&/,$in);
  
foreach $i (0 .. $#in) {
   $in[$i] =~ s/\+/ /g;
   ($key, $val) = split(/=/,$in[$i],2); # splits on the first =.
   $key =~ s/%(..)/pack("c",hex($1))/ge;
   $val =~ s/%(..)/pack("c",hex($1))/ge;
   $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator
   $in{$key} .= $val;
}
my(%colorCodes)=(1,"blue",2,"darkgreen",3,"red",4,"darkblue",5,"brown",6,"green",7,"black",8,"gray","X","red");
my(%buttonSymbols)=(0,".",1,"",2,"*",3,"?",4," ");

print "Content-type: text/html\n\n";
if ($in{'TS'}) {
   $time_start=$in{'TS'};
}

print "<html><head><title>eMineSweeper</title></head>"; 
print "<body><center><font size=4 face=Verdana><b>eMineSweeper</b>"; 

if (!defined $in{'G'}) {$in{'G'}=1;}

  if ($in{'best'}) {
      &showTimes();
      exit;
  }

if ($in{'G'} eq "1") { 
  $total=$in{'RS'}*$in{'CS'}; 
  $time_start=time(); 
  $in{'GO'}=0;
  if (($in{'RS'}<9)){ $in{'RS'}=9; }
  if (($in{'RS'}>24)){ $in{'RS'}=24; }
  if (($in{'CS'}<9)){ $in{'CS'}=9; }
  if (($in{'CS'}>30)){ $in{'CS'}=30; }
  if ($in{'TotalMines'}<10) {$in{'TotalMines'}=10;}
  if ($in{'TotalMines'}>$in{'CS'}*$in{'RS'}) {$in{'TotalMines'}=($in{'CS'}-1)*($in{'RS'}-1); }

  $count=0; 
  while ($count<$in{'TotalMines'}) { 
    $Row=1+int(rand($in{'RS'})); 
    $Col=1+int (rand($in{'CS'})); 
    if ($Mine[$Row][$Col] ne "9") { 
      $Mine[$Row][$Col]="9"; 
      $count++; 
    } 
  } 

  for ($Row=1;$Row<=$in{'RS'};$Row++) { 
    for ($Col=1;$Col<=$in{'CS'};$Col++) { 
      $Sweep[$Row][$Col]="0"; 
      $count=0;
      for ($y=-1; $y<=1; $y++) { 
         for ($x=-1; $x<=1; $x++) { 
             if ($Mine[$Row+$y][$Col+$x] eq "9") { $count++; } 
         } 
      } 
      if ($Mine[$Row][$Col] ne "9") {
        $Mine[$Row][$Col]=$count; 
      }
    }
  }
} else { 
  $total=$in{'RS'}*$in{'CS'}; 
  $markedbomb=0;
  my($tempMines);
  $tempMines=$in{'Map'};
  $Col=1;
  $Row=1;
  my($theSubmit);
  while ($tempMines =~ /M([\d|\+|X]+)S([\d]+)/g) {
    $Mine[$Row][$Col]=$1;
    $Sweep[$Row][$Col]=$2;
    if ($2==1) {--$total;}
    elsif ($2==2) {++$markedbomb;}
    if ($1 eq "X") {++$markedbomb;}
    $temp="s".($Row*($in{'CS'}+1)+$Col); 
    if ($in{$temp}) {
	$theRow=$Row;
        $theCol=$Col;
	$theSubmit=$in{$temp};
    }
    $Col++;
    if ($Col == $in{'CS'}+1) {
	++$Row;
	$Col=1;
    }
  }
  $end=0; 
         if ($theSubmit && (! defined $in{'GO'})) { 

	    if ($in{'TP'} eq "Unmark"){ 
		if ($theSubmit eq "*" ||$theSubmit eq "?") {
		  $Sweep[$theRow][$theCol]=0;
		  if ($theSubmit eq "*") {
		    $markedbomb--;
		  }
		}
	    }elsif ($in{'TP'} eq "Mark Mine"){ 
		if ($theSubmit eq "." ||$theSubmit eq "?") {
		$Sweep[$theRow][$theCol]=2;
		$markedbomb++;
		}
	    }elsif ($in{'TP'} eq "Mark ?"){ 
		if ($theSubmit eq "." ||$theSubmit eq "*") {
		  $Sweep[$theRow][$theCol]=3;
		  if ($theSubmit eq "*") {
		    $markedbomb--;
		  }
		}
	    }else { 
		if ($theSubmit eq "."|| $theSubmit eq "?" ) {
              		--$total;
			if ($Mine[$theRow][$theCol] ne "9") { 
                  		$Sweep[$theRow][$theCol]=1; 
				if ($Mine[$theRow][$theCol] eq "0") {
    				  &clearArea($theRow,$theCol);
				}
              		} else { $end=1; }
		}
	    }
         } 
  if ($end==1) { 
     $time_start=time()-$time_start;
     $in{'GO'}=1;
     for ($y=1;$y<=$in{'RS'};$y++) { 
        for ($x=1;$x<=$in{'CS'};$x++) { 
	   if ($Mine[$y][$x] eq "9") {
		if ($Sweep[$y][$x]==2) {
		}else {
		   $Sweep[$y][$x]=1;
		}
	   } else {
		if ($Sweep[$y][$x]==2) {
		   $Sweep[$y][$x]=1;
		   $Mine[$y][$x]="X";
		}
	   }
	   if ($Sweep[$y][$x]==0) {$Sweep[$y][$x]=4;}
        } 
     } 
 } 
  if (($total==$in{'TotalMines'})&&($end!=1)&&(! defined $in{'GO'})) { 
     $time_start=time()-$time_start; 
     $in{'GO'}=2;

     for ($y=1;$y<=$in{'RS'};$y++) { 
        for ($x=1;$x<=$in{'CS'};$x++) { 
	   if (($Mine[$y][$x] eq "9")&&($Sweep[$y][$x]!=2)) {
		$Sweep[$y][$x]=2; 
		++$markedbomb;
	   }
        } 
     }
#####

  } 
} 
print "<table><tr><td valign=top>";
print "<table><tr><td width=33% bgcolor=black align=center><font color=red><b>";
print $in{'TotalMines'}-$markedbomb;
print "</b></font></td><td width=33% bgcolor=yellow align=center>";
if ($end==1) {&newGameButton(1,$in{'RS'},$in{'CS'},$in{'TotalMines'},":(");}
elsif ($end!=1 && $total==$in{'TotalMines'}) {&newGameButton(1,$in{'RS'},$in{'CS'},$in{'TotalMines'},"B)");}
else { &newGameButton(1,$in{'RS'},$in{'CS'},$in{'TotalMines'},":)"); }

print"</td><td bgcolor=black align=center width=33%><font color=red><b>";
if ($in{'GO'}) { print $time_start;}
else { print time()-$time_start;}

print "</b></font></td></tr><tr><td colspan=3>";
print "<form method=\"post\" action=\"$theurl\">"; 
print "<input type=hidden name=TS value=$time_start>"; 
print "<input type=hidden name=TotalMines value=$in{'TotalMines'}>"; 
print "<input type=hidden name=RS value=$in{'RS'}>";
print "<input type=hidden name=CS value=$in{'CS'}>"; 
print "<input type=hidden name=G value=0>"; 
if ($in{'GO'}) { print "<input type=hidden name=GO value=".$in{'GO'}.">"; }

print "<p><table bgcolor=\"gray\"  >"; 
for ($Row=1; $Row<=$in{'RS'}; $Row++) { 
   print "<tr bgcolor=\"lightgrey\">"; 
   for ($Col=1; $Col<=$in{'CS'}; $Col++) { 
	if (($end==1)&&($Row==$theRow)&&($Col==$theCol)){
	     print "<td width=16 bgcolor=\"red\" height=15 align=center valign=middle>"; 
	} else {
	      print "<td width=16 height=15 align=center valign=middle>"; 
	}

      if ($Sweep[$Row][$Col]==1) { 
          if (($Mine[$Row][$Col] eq "+")||($Mine[$Row][$Col] eq "0")) { 
             print "&nbsp;"; 
          } else { 
             if ($Mine[$Row][$Col] eq "9") { 
                 print "<b>*</b>"; 
             } else { 
		print "<font color=\"";
		print $colorCodes{$Mine[$Row][$Col]};
		print "\"><b>$Mine[$Row][$Col]</b></font>";
             } 
          } 
      } else {
        print "<input type=submit name=s".($Row*($in{'CS'}+1)+$Col)." value=\"";
	print $buttonSymbols{$Sweep[$Row][$Col]};
	print "\">"; 
      } 
      print "</td>"; 
   } 
   print "</tr>"; 
} 
print "</table>";
print "<input type=hidden name=submit value=ok>"; 
print "<select name=TP>";
print "<option selected>Sweep<option>Mark Mine<option>Mark ?<option>Unmark";
print "</select>";
if ($in{'GO'}==1) {
   print "<font color=red><b>Kaboom!</b></font>";
 } elsif ($in{'GO'}==2) {
   print "<font color=green><b>All Detected!</b></font>";
 }
print "<input type=hidden name=Map value=\"";
print &generateString();
print "\"></td></tr></table></td><td valign=top>";

print "<table cellpadding=5 border=1 bgcolor=\"gray\"><tr bgcolor=yellow><td><b>Information</b></td></tr><tr bgcolor=lightgrey><td>";
print "<input type=submit name=\"best\" value=\"Best Times...\">";
print "</form>";
print "</td></tr><tr bgcolor=yellow><td align=center><b>New Game</b></td></tr><tr bgcolor=lightgrey><td>";
&newGameButton("1","9","9","10","Beginner");
&newGameButton("1","16","16","40","Intermediate");
&newGameButton("1","16","30","99","Expert");

print"<hr>";

&newGameButton("0",$in{'RS'},$in{'CS'},$in{'TotalMines'},"Custom");

print "</td></tr></table></td></tr></table>";
print "<p><center><font size=-2>&copy;Copyright 2001, <a href=\"mailto:pohanl\@hotmail.com\">Po-Han Lin</a> - All rights reserved <a href=\"http://www.edepot.com\">edepot.com</a></font></center></body></html>
";

sub showTimes {
    print "<html><head><title>eMineSweeper</title></head>"; 
    print "<body><center><table width=60% border=1 bgcolor=gray>";
    print "<tr bgcolor=yellow><td align=\"center\"><b>Fastest eMineSweepers</b></td></tr><tr bgcolor=lightgrey><td><center>";
    print "Like this program?  Help support my efforts by registering.  In addition, support for high scores is available in the registered version ";
    print "only.  Scores will be stored at an external server.  Your ";
    print "registration fee will go towards paying for the upkeep and ";
    print "maintenance of this server.  To register, Click:";
    print "<A HREF=\"https://secure.paypal.x.com/xclick/business=pohanl%40hotmail.com&undefined_quantity=1&item_name=eMineSweeper+Registration&amount=15&return=http%3A//www.edepot.com/phl.html\" target=\"_blank\"><IMG SRC=\"http://images.paypal.com/images/x-click-but6.gif\" BORDER=\"0\" ALT=\"Make payments with PayPal - it's fast, free and secure!\"></A><br>";
    &continueButton("OK","0");
    print "</center></td></tr>";
    print "</table>";
    print "</center></body></html>";
}


sub generateString {
  my($theString)="";
  for ($Row=1;$Row<=$in{'RS'};$Row++) { 
    for ($Col=1;$Col<=$in{'CS'};$Col++) { 
      $theString .= "M".$Mine[$Row][$Col];
      $theString .= "S".$Sweep[$Row][$Col];
    } 
  } 
  return $theString;	
}
sub clearArea {
  my($theRow,$theCol)=@_;
  my(@markforclear);
  my($tmpi,$tmpj);
  $Mine[$theRow][$theCol]="+";
      for ($tmpi=-1; $tmpi<=1; $tmpi++) { 
         for ($tmpj=-1; $tmpj<=1; $tmpj++) { 
		if (defined $Mine[$theRow+$tmpi][$theCol+$tmpj]) {
	  		if ($Sweep[$theRow+$tmpi][$theCol+$tmpj]!=1) {
	       		   if ($Sweep[$theRow+$tmpi][$theCol+$tmpj]!=2) {
               		      $Sweep[$theRow+$tmpi][$theCol+$tmpj]=1;
				--$total;
		  	   }
			}
		  	if ($Mine[$theRow+$tmpi][$theCol+$tmpj] eq "0") {
			   &clearArea($theRow+$tmpi,$theCol+$tmpj);
		  	}
		}	
         } 
      } 
}

sub newGameButton {
  my($hidden,$rows,$cols,$mines,$label)=@_;
  print "<form action=\"$theurl\" method=\"post\"> ";
  if (!$hidden) {
    print "Height:<input type=text name=RS value=\"$rows\" size=2><br>
    Width:<input type=text name=CS value=\"$cols\" size=2><br> 
    Mines:<input type=text name=TotalMines value=\"$mines\" size=2><br>"; 
  } else {
    print "<input type=hidden name=RS value=\"$rows\" size=2>
    <input type=hidden name=CS value=\"$cols\" size=2> 
    <input type=hidden name=TotalMines value=\"$mines\" size=2>";
  }
  print "<input type=hidden name=G value=1>
  <input type=submit name=submit value=\"$label\"> 
  </form> ";
}

sub continueButton {
  my($label,$condition)=@_;
  print "<form action=\"$theurl\" method=\"post\"> ";
    print "<input type=hidden name=G value=\"$condition\">"; 
    print "<input type=hidden name=GO value=\"$in{'GO'}\">"; 
    print "<input type=hidden name=TS value=\"$time_start\">"; 
    print "<input type=hidden name=RS value=\"$in{'RS'}\">"; 
    print "<input type=hidden name=CS value=\"$in{'CS'}\">"; 
    print "<input type=hidden name=TotalMines value=\"$in{'TotalMines'}\">"; 
    print "<input type=hidden name=Map value=\"$in{'Map'}\">"; 
    print"<input type=submit name=submit value=\"$label\"> 
    </form> ";
}