<?php
include_once("computerbattleships.class.php");
include_once("template.class.php");
session_register("BattleShips");
class BattleShipPage extends pcPage
{ function BattleShipPage() // constructor
{ $this->pcPage($_SESSION["pcsession"], "- battleships");
} // end of fn BattleShipPage, constructor
function Game() // overrides parent
{ $game = new ComputerBattleShips();
$game->GameBoard();
} // end of fn Game
function JSInclude() //
{ include_once("bs-fillform.js");
} // end of fn JSInclude
function WelcomePage() // overrides parent
{ $this->Game();
} // end of fn WelcomePage
} // end of defn BattleShipPage
$BS = new BattleShipPage();
$BS->Page();
?>
<?php
include_once("ship.class.php");
include_once("battleshipplayer.class.php");
class BattleShips
{ var $players;
var $gridHeight;
var $gridWidth;
var $cellSize;
var $currentPlayer;
var $otherPlayer;
var $winner;
function BattleShips()
{ $this->gridHeight = 10;
$this->gridWidth = 10;
$this->cellSize = 30;
if ($_GET["newgame"])
{ $this->NewGame();
}
$this->InitialisePlayers();
} // end of fn BattleShips
function NewGame()
{ unset($_SESSION["BattleShips"]);
// toss coin for who starts
srand((double)microtime() * 1000000);
$_SESSION["BattleShips"]["id"] = rand(0, 1);
} // end of fn NewGame
function InitialisePlayers()
{ $this->players[0] = new BattleShipPlayer(0);
$this->players[1] = new BattleShipPlayer(1);
$this->SetPlayerID();
} // end of fn InitialisePlayers
function SetPlayerID()
{ $this->currentPlayer = 0 + $_SESSION["BattleShips"]["id"];
$this->otherPlayer = 1 - $_SESSION["BattleShips"]["id"];
} // end of fn SetPlayerID
function IsAllSet()
{ if (count($this->players) === 2)
{ foreach ($this->players as $player)
{ if (!$player->IsAllSet())
{ return false;
}
}
return true;
}
return false;
} // end of fn IsAllSet
function IsGameOver()
{ if ($this->IsAllSet())
{ foreach ($this->players as $key=>$player)
{ if (!$player->IsAllSunk())
{ $this->winner = $key;
return true;
}
}
}
return false;
} // end of fn IsGameOver
function YourTitle()
{ echo "\t<tr>\n\t\t<td colspan='",
$this->gridWidth + 1,
"'><b><font color='white'>Your Fleet: ",
$this->players[$this->currentPlayer]->name,
"</font></b></td>\n\t</tr>\n";
} // end of fn NewFn
function DisplayYourFleet()
{ $squares = array();
for ($x = 1; $x <= $this->gridWidth; $x++)
{ for ($y = 1; $y <= $this->gridHeight; $y++)
{ $squares[$x][$y] = array();
}
}
foreach ($this->players[$this->otherPlayer]->hits as $count=>$hit)
{ $squares[$hit["col"]][$hit["row"]]["miss"] = true;
if ($count == count($this->players[$this->otherPlayer]->hits) - 1)
{ $squares[$hit["col"]][$hit["row"]]["last"] = true;
}
}
foreach ($this->players[$this->currentPlayer]->ships as $ship)
{ $sunk = $ship->IsSunk();
foreach ($ship->squares as $square)
{ $squares[$square["col"]][$square["row"]]["ship"] = true;
$squares[$square["col"]][$square["row"]]["hit"] = $square["hit"];
$squares[$square["col"]][$square["row"]]["sunk"] = $sunk;
}
}
// now build table of this fleet
echo("\n<table cellspacing='1' cellpadding = '0', border = '0' bgcolor='black'>\n");
$this->YourTitle();
// top row (letters)
echo("\t<tr>\n\t\t<td bgcolor='black'> </td>\n");
for ($x = 1; $x <= $this->gridWidth; $x++)
{ echo "\t\t<td bgcolor='black' align='center'><font color='white' size='-1'><b>",
chr(64 + $x),
"</b></font></td>\n";
}
echo("\t</tr>\n");
// now rows
for ($y = 1; $y <= $this->gridHeight; $y++)
{ echo "\t<tr>\n\t\t<td bgcolor='black'><font color='white' size='-1'><b>",
$y,
"</b></font></td>\n";
for ($x = 1; $x <= $this->gridWidth; $x++)
{ echo "\t\t<td width='$this->cellSize' height='$this->cellSize'>",
"<img height = '$this->cellSize' width='$this->cellSize' src='games/";
if ($squares[$x][$y]["last"]) echo("last-");
if ($squares[$x][$y]["ship"])
{ if ($squares[$x][$y]["hit"])
{ if ($squares[$x][$y]["sunk"])
{ echo("sunk");
} else
{ echo("hit");
}
} else
{ echo("ship");
}
} else
{ if ($squares[$x][$y]["miss"])
{ echo "miss";
} else
{ echo("sea");
}
}
echo(".bmp'");
echo(" /></td>\n");
}
echo("\t</tr>\n");
}
echo("</table>\n");
} // end of fn DisplayYourFleet
function EnemyTitle()
{ echo "\t<tr>\n\t\t<td colspan='",
$this->gridWidth + 1,
"'><b><font color='white'>Enemy Fleet: ",
$this->players[$this->otherPlayer]->name,
"</font></b></td>\n\t</tr>\n";
} // end of fn EnemyTitle
function DisplayEnemyFleet()
{ $squares = array();
for ($x = 1; $x <= $this->gridWidth; $x++)
{ for ($y = 1; $y <= $this->gridHeight; $y++)
{ $squares[$x][$y] = array();
}
}
foreach ($this->players[$this->currentPlayer]->hits as $count=>$hit)
{ $squares[$hit["col"]][$hit["row"]]["miss"] = true;
if ($count == count($this->players[$this->currentPlayer]->hits) - 1)
{ $squares[$hit["col"]][$hit["row"]]["last"] = true;
}
}
foreach ($this->players[$this->otherPlayer]->ships as $ship)
{ $sunk = $ship->IsSunk();
foreach ($ship->squares as $square)
{ $squares[$square["col"]][$square["row"]]["ship"] = true;
if ($square["hit"])
{ $squares[$square["col"]][$square["row"]]["hit"] = true;
$squares[$square["col"]][$square["row"]]["sunk"] = $sunk;
}
}
}
// now build table of this fleet
echo("\n<table cellspacing='1' cellpadding = '0', border = '0' bgcolor='black'>\n");
$this->EnemyTitle();
// top row (letters)
echo("\t<tr>\n\t\t<td bgcolor='black'> </td>\n");
for ($x = 1; $x <=$this->gridWidth; $x++)
{ echo "\t\t<td bgcolor='black' align='center'><font color='white' size='-1'><b>",
chr(64 + $x),
"</b></font></td>\n";
}
echo("\t</tr>\n");
// now rows
for ($y = 1; $y <= $this->gridHeight; $y++)
{ echo "\t<tr>\n\t\t<td bgcolor='black'><font color='white' size='-1'><b>",
$y,
"</b></font></td>\n";
for ($x = 1; $x <= $this->gridWidth; $x++)
{ echo "\t\t<td width='$this->cellSize' height='$this->cellSize'>",
"<img height = '$this->cellSize' width='$this->cellSize' src='games/";
if ($squares[$x][$y]["miss"])
{ if ($squares[$x][$y]["last"]) echo("last-");
if ($squares[$x][$y]["hit"])
{ if ($squares[$x][$y]["sunk"])
{ echo("sunk");
} else
{ echo("hit");
}
} else
{ echo("miss");
}
} else
{ echo("sea");
}
echo(".bmp'");
if (!$squares[$x][$y]["miss"] && $this->PlayerToMove() == $this->currentPlayer)
{ echo " onclick='FillForm($x, $y);'";
}
echo(" /></td>\n");
}
echo("\t</tr>\n");
}
echo("</table>\n");
} // end of fn DisplayEnemyFleet
function SetFleetForm()
{ echo "enter start and end squares for fleet";
echo "\n<form action='battleships.php' method='POST'>",
"\n<table border='1' bordercolor='black'>\n\t",
"<tr>\n\t\t<td><b>Ship</b></td><td><b>Size</b></td>",
"<td><b>Start</b></td><td><b>Finish</d></td>\n\t</tr>\n";
foreach ($this->players[$this->currentPlayer]->ships as $key=>$ship)
{ echo "\t<tr>\n\t\t<td>{$ship->name}</td><td align='center'>{$ship->size}</td>\n",
"\t\t<td><input type='test' name='setstart[$key]' size='4' maxlength='3' value='",
$ship->DisplayStart(),
"' /></td>\n\t\t<td><input type='test' name='setend[$key]' size='4' maxlength='3' value='",
$ship->DisplayEnd(),
"' /></td>\n\t</tr>\n";
}
$this->ExtraSetUpOptions();
echo "<tr><td colspan='4'><input type='submit' value='Set Fleet' />",
" random fleet<input type='checkbox' name='randomfleet' />",
"</td></tr></table>\n</form>\n";
} // end of fn SetFleetForm
function ExtraSetUpOptions()
{
} // end of fn ExtraSetUpOptions
function ProcessExtraSetUpOptions()
{
} // end of fn ProcessExtraSetUpOptions
function ProcessSetFleet()
{ $this->players[$this->currentPlayer]->UnsetFleet();
if ($_POST["randomfleet"])
{ $this->players[$this->currentPlayer]->SetRandomFleet($this->gridWidth, $this->gridHeight);
} else
{ foreach ($this->players[$this->currentPlayer]->ships as $key=>$ship)
{ $fail = false;
// convert to upper case
$_POST["setstart"][$key] = strtoupper($_POST["setstart"][$key]);
$_POST["setend"][$key] = strtoupper($_POST["setend"][$key]);
// split into rows and columns
$start = array("col"=> ord(substr($_POST["setstart"][$key], 0, 1)) - 64,
"row"=> 0 + substr($_POST["setstart"][$key], 1, 2));
$end = array("col"=> ord(substr($_POST["setend"][$key], 0, 1)) - 64,
"row"=> 0 + substr($_POST["setend"][$key], 1, 2));
// check that squares are on the grid
if ($start["col"] < 1 || $start["col"] > $this->gridWidth || $start["row"] < 1
|| $start["row"] > $this->gridHeight)
{ $fail = true;
}
if ($end["col"] < 1 || $end["col"] > $this->gridWidth || $end["row"] < 1
|| $end["row"] > $this->gridHeight)
{ $fail = true;
}
if ($fail) continue;
// check start and end are in line
if ($start["col"] == $end["col"])
{ if (abs($start["row"] - $end["row"]) == $ship->size - 1)
{ // check squares at ends aren't used
if ($start["row"] > $end["row"])
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"], $end["row"] - 1))
{ $fail = true;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"], $start["row"] + 1))
{ $fail = true;
}
for ($x = $end["row"]; $x <= $start["row"]; $x++)
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] + 1, $x))
{ $fail = true;
continue;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] - 1, $x))
{ $fail = true;
continue;
}
}
} else // start less than end
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"], $end["row"] + 1))
{ $fail = true;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"], $start["row"] - 1))
{ $fail = true;
}
for ($x = $start["row"]; $x <= $end["row"] && !$fail; $x++)
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] + 1, $x))
{ $fail = true;
continue;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] - 1, $x))
{ $fail = true;
}
}
}
if (!$fail) $this->players[$this->currentPlayer]->ships[$key]->SetShip($start, $end);
} else
{ continue;
}
} else
{ if ($start["row"] == $end["row"])
{ if (abs($start["col"] - $end["col"]) == $ship->size - 1)
{ // check squares at ends aren't used
if ($start["col"] > $end["col"])
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] - 1, $end["row"]))
{ $fail = true;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($start["col"] + 1, $end["row"]))
{ $fail = true;
}
for ($x = $end["col"]; $x <= $start["col"]; $x++)
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($x, $end["row"] + 1))
{ $fail = true;
continue;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($x, $end["row"] - 1))
{ $fail = true;
continue;
}
}
} else
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($end["col"] + 1, $end["row"]))
{ $fail = true;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($start["col"] - 1, $end["row"]))
{ $fail = true;
}
for ($x = $start["col"]; $x <= $end["col"] && !$fail; $x++)
{ if ($this->players[$this->currentPlayer]->IsSquareUsed($x, $end["row"] + 1))
{ $fail = true;
continue;
}
if ($this->players[$this->currentPlayer]->IsSquareUsed($x, $end["row"] - 1))
{ $fail = true;
continue;
}
}
}
if (!$fail) $this->players[$this->currentPlayer]->ships[$key]->SetShip($start, $end);
}
}
}
}
}
$this->ProcessExtraSetUpOptions();
$this->players[$this->currentPlayer]->StoreToSession();
} // end of fn ProcessSetFleet
function GameBoard()
{ if (!$this->players[$this->currentPlayer]->IsAllSet() && is_array($_POST["setstart"]))
{ $this->ProcessSetFleet();
}
echo "\n<table>\n\t<tr>\n\t\t<td colspan='2'>";
if ($this->players[$this->currentPlayer]->IsAllSet())
{ if ($this->players[$this->otherPlayer]->IsAllSet())
{ if (isset($_POST["missile"])) $this->ProcessHit();
if (isset($_POST["computermissile"])) $this->ProcessComputerHit();
if ($winner = $this->Winner())
{ echo("Game over: won by $winner");
}else
{ if ($this->PlayerToMove() == $this->currentPlayer)
{ $this->MoveForm();
} else
{ $this->WaitEnemyMove();
}
}
echo "\t\t</td>\n\t</tr>\n\t<tr>\n\t\t<td>\n";
$this->DisplayEnemyFleet();
} else
{ echo "waiting for opponent to set up their fleet</td>\n",
"\t</tr>\n\t<tr>\t\t<td></td>\n";
}
} else
{ echo "set up your fleet ...</td>\n\t</tr>\n\t<tr>\n\t\t<td>\n";
$this->SetFleetForm();
echo "\t\t</td>\n";
}
echo "\t\t<td>\n";
$this->DisplayYourFleet();
echo "\t\t</td>\n\t</tr>\n</table>";
echo("<a href='battleships.php?newgame=1'>new game</a><br />\n");
} // end of fn GameBoard
function WaitEnemyMove()
{ echo "waiting for to {$this->players[$this->otherPlayer]->name} move";
} // end of fn WaitEnemyMove
function Winner()
{ foreach ($this->players as $key=>$player)
{ if ($player->IsAllSunk())
{ return $this->players[1 - $key]->name;
}
}
return "";
} // end of fn Winner
function MoveForm()
{ echo "\n<form action='battleships.php' method='POST'>",
"hit square <input type='text' size='4' maxlength='3' name='missile'> ",
"<input type='submit' value='fire missile'></form>\n";
} // end of fn MoveForm
function ProcessHit()
{ $missile = strtoupper($_POST["missile"]);
$col = ord(substr($missile, 0, 1)) - 64;
$row = 0 + substr($missile, 1, 2);
if ($col < 1 || $col > $this->gridWidth || $row < 1 || $row > $this->gridHeight)
{ return false;
}
$this->players[$this->currentPlayer]->MakeHit($col, $row);
$this->players[$this->otherPlayer]->TakeHit($col, $row);
return true;
} // end of fn ProcessHit
function PlayerToMove()
{ if (count($this->players[0]->hits) > count($this->players[1]->hits))
{ return 1;
} else return 0;
} // end of fn PlayerToMove
} // end of class defn BattleShips
?>
<?php
class Ship
{ var $name;
var $size;
var $squares;
function Ship($size)
{ $this->size = $size;
$this->squares = array();
switch($this->size)
{ case 3:
$this->name = "cruiser";
break;
case 2:
$this->name = "submarine";
break;
case 4:
$this->name = "destroyer";
break;
case 5:
$this->name = "aircraft carrier";
break;
default:
$this->name = "unnamed";
}
} // end of fn Ship
function IsSunk()
{ if ($this->IsAllSet())
{ foreach($this->squares as $square)
{ if (!$square["hit"]) return false;
}
return $this->name;
}
return false;
} // end of fn IsSunk
function TakeHit($col, $row)
{ foreach($this->squares as $key=>$square)
{ if ($square["col"] == $col && $square["row"] == $row)
{ $this->squares[$key]["hit"] = true;
return $this->name;
}
}
return false;
} // end of fn TakeHit
function SetShip($from, $to)
{ $this->squares = array();
if ($from["col"] > $to["col"])
{ $x_start = $to["col"];
$x_end = $from["col"];
} else
{ $x_start = $from["col"];
$x_end = $to["col"];
}
if ($from["row"] > $to["row"])
{ $y_start = $to["row"];
$y_end = $from["row"];
} else
{ $y_start = $from["row"];
$y_end = $to["row"];
}
for ($x = $x_start; $x <= $x_end; $x++)
{ for ($y = $y_start; $y <= $y_end; $y++)
{ $this->SetSquare($x, $y);
}
}
} // end of fn SetSquare
function SetSquare($col, $row)
{ $this->squares[] = array("col"=>$col, "row"=>$row);
} // end of fn SetSquare
function IsAllSet()
{ return count($this->squares) === $this->size;
} // end of fn IsAllSet
function IsSquareUsed($col, $row)
{ foreach ($this->squares as $square)
{ if ($square["col"] == $col && $square["row"] == $row) return true;
}
return false;
} // end of fn IsSquareUsed
function IsSquareHit($col, $row)
{ foreach ($this->squares as $square)
{ if ($square["col"] == $col && $square["row"] == $row) return $square["hit"];
}
return false;
} // end of fn IsSquareHit
function DisplayStart()
{ if ($this->IsAllSet())
{ return chr($this->squares[0]["col"] + 64) . $this->squares[0]["row"];
} else return "";
} // end of fn DisplayStart
function DisplayEnd()
{ if ($this->IsAllSet())
{ return chr($this->squares[$this->size - 1]["col"] + 64) . $this->squares[$this->size - 1]["row"];
} else return "";
} // end of fn DisplayEnd
} // end of class defn Ship
?>
<?php
class BattleShipPlayer
{ var $name;
var $id;
var $ships;
var $hits;
var $computer;
function BattleShipPlayer($id, $computer = false, $width = 10, $height = 10)
{ $this->id = $id;
$this->computer = $computer;
$this->ships = array();
$this->hits = array();
$this->UnsetFleet();
$this->GetFromSession();
if ($this->computer)
{ if (!$this->IsAllSet())
{ $this->SetRandomFleet($width, $height);
}
$this->SetName("chessish");
} else
{ if ($_SESSION["pcsession"]["loggedin"])
{ $this->SetName($_SESSION["pcsession"]["player"]["dispname"]);
} else
{ $this->SetName("guest player");
}
}
} // end of fn BattleShipPlayer
function SetRandomFleet($maxW, $maxH)
{ srand((double)microtime() * 1000000);
foreach($this->ships as $key=>$ship)
{ while (!$this->ships[$key]->IsAllSet())
{ $start = array("col"=>rand(1, $maxW), "row"=>rand(1, $maxH));
$fail = false;
if ($this->IsSquareUsed($start["col"], $start["row"])) continue;
// go right or down?
if (rand(0, 1)) // go right
{ $end = array("col"=>$start["col"] + $ship->size - 1, "row"=>$start["row"]);
if ($end["col"] > $maxW) continue;
} else // go down
{ $end = array("col"=>$start["col"], "row"=>$start["row"] + $ship->size - 1);
if ($end["row"] > $maxH) continue;
}
for ($x = $start["col"]; $x <= $end["col"] && !$fail; $x++)
{ for ($y = $start["row"]; $y <= $end["row"] && !$fail; $y++)
{ if ($this->IsSquareUsed($x, $y) || $this->IsSquareUsed($x + 1, $y)
|| $this->IsSquareUsed($x - 1, $y) || $this->IsSquareUsed($x, $y + 1)
|| $this->IsSquareUsed($x, $y - 1))
{ $fail = true;
continue;
}
}
}
if (!$fail) $this->ships[$key]->SetShip($start, $end);
}
}
$this->StoreToSession();
} // end of fn SetRandomFleet
function UnsetFleet()
{ $this->ships = array();
$this->ships[] = new Ship(2);
$this->ships[] = new Ship(3);
$this->ships[] = new Ship(3);
$this->ships[] = new Ship(4);
$this->ships[] = new Ship(5);
} // end of fn UnsetFleet
function SetName($name)
{ return $this->name = $name;
} // end of fn SetName
function IsAllSet()
{ foreach ($this->ships as $ship)
{ if (!$ship->IsAllSet())
{ return false;
}
}
return true;
} // end of fn IsAllSet
function IsAllSunk()
{ if ($this->IsAllSet())
{ foreach($this->ships as $ship)
{ if (!$ship->IsSunk())
{ return false;
}
}
return true;
}
return false;
} // end of fn IsAllSunk
function TakeHit($col, $row)
{ if ($this->IsAllSet())
{ foreach($this->ships as $key=>$ship)
{ if ($hit = $this->ships[$key]->TakeHit($col, $row))
{ $this->StoreToSession();
return $hit;
}
}
}
return false;
} // end of fn TakeHit
function MakeHit($col, $row)
{ $this->hits[] = array("col"=>$col, "row"=>$row);
$this->StoreToSession();
} // end of fn MakeHit
function IsSquareUsed($col, $row)
{ foreach ($this->ships as $ship)
{ if ($ship->IsSquareUsed($col, $row)) return true;
}
return false;
} // end of fn IsSquareUsed
function IsSquareHit($col, $row)
{ foreach ($this->ships as $ship)
{ if ($ship->IsSquareHit($col, $row)) return true;
}
return false;
} // end of fn IsSquareHit
function IsSquareSunk($col, $row)
{ foreach ($this->ships as $ship)
{ if ($ship->IsSquareHit($col, $row) && $ship->IsSunk()) return true;
}
return false;
} // end of fn IsSquareSunk
function GetFromSession()
{ if ($player = $_SESSION["BattleShips"]["player"][$this->id])
{ $this = $player;
return true;
} else return false;
} // end of fn GetFromSession
function StoreToSession()
{ $_SESSION["BattleShips"]["player"][$this->id] = $this;
} // end of fn StoreToSession
function IsInHits($col, $row)
{ foreach ($this->hits as $hit)
{ if ($hit["row"] == $row && $hit["col"] == $col)
{ return true;
}
}
return false;
} // end of fn IsInHits
} // end of class defn BattleShipPlayer
?>