function StartNewGame() {
global $BoardState, $database;
//Clear old BoardState if it exists
$database->exec("DELETE FROM BoardState WHERE SessionID = '". session_id() . "'");
//Create new empty BoardState
$statement = $database->prepare('INSERT INTO BoardState(SessionID, access) VALUES (:sessionid, :timestamp)');
$statement->bindValue(':sessionid', session_id());
$statement->bindValue(':timestamp', time());
$result = $statement->execute();
$BoardState = array( "B1"=> NULL, "B2"=> NULL, "B3"=> NULL, "B4"=> NULL, "B5"=> NULL, "B6"=> NULL, "B7"=> NULL, "B8"=> NULL, "B9"=> NULL, "W1"=> NULL, "W2"=> NULL, "W3"=> NULL, "W4"=> NULL, "W5"=> NULL, "W6"=> NULL, "W7"=> NULL, "W8"=> NULL, "W9"=> NULL );
unset ($_SESSION['currPlayerMoveFrom']);
unset ($_SESSION['currComputerMoveFrom']);
unset ($_SESSION['currPlayerMoveTo']);
unset ($_SESSION['currComputerMoveTo']);
unset ($_SESSION["winner"]);
unset ($_SESSION['playerMill']);
unset ($_SESSION['computerMill']);
$_SESSION["SetupStage"] = 1;
}
function ContinueGame() {
global $BoardState, $database;
//fetch board state
$statement = $database->prepare('SELECT B1, B2, B3, B4, B5, B6, B7, B8, B9, W1, W2, W3, W4, W5, W6, W7, W8, W9 FROM BoardState WHERE SessionID = :sessionid');
$statement->bindValue(':sessionid', session_id());
$result = $statement->execute();
if (!$result)
die($databse->lastErrorMsg());
$BoardState = $result->fetchArray(SQLITE3_ASSOC);
// If no board state exists for this session then create a new board state.
if ($BoardState == NULL)
StartNewGame();
}
function isSetupStage() {
return (isset($_SESSION["SetupStage"]) && filter_var($_SESSION["SetupStage"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 9))));
}
function getPieceColour($nodeID) {
global $BoardState;
$pieceID = array_search($nodeID, $BoardState);
if ($pieceID)
return ($pieceID[0] == 'B')? "black" : "white";
else
return "vacant";
}
function MovePieceToPos($pieceID, $positionID) {
global $BoardState, $database;
$statement = $database->prepare("UPDATE BoardState SET $pieceID = :positionID, access = :timestamp WHERE SessionID = :sessionid");
$statement->bindValue(':positionID', $positionID);
$statement->bindValue(':timestamp', time());
$statement->bindValue(':sessionid', session_id());
$result = $statement->execute();
if ($result) {
$BoardState[$pieceID] = $positionID;
} else {
echo $databse->lastErrorMsg();
echo "Moving piece: UPDATE BoardState SET $pieceID = $positionID, access = ".time()." WHERE SessionID = ".session_id(). "
";
}
}
function RemovePiece($pieceID) {
global $BoardState, $database;
if (!isset($pieceID)) {
echo "Remove Piece: pieceID not set";
return;
}
$statement = $database->prepare("UPDATE BoardState SET $pieceID = -1, access = :timestamp WHERE SessionID = :sessionid");
$statement->bindValue(':timestamp', time());
$statement->bindValue(':sessionid', session_id());
$result = $statement->execute();
if ($result) {
$BoardState[$pieceID] = -1;
}
else {
echo "Removing Piece: UPDATE BoardState SET $pieceID = -1, access = ".time()." WHERE SessionID = ".session_id(). "
";
echo $databse->lastErrorMsg();
}
}
function isValidSetupMove($positionID) {
return getPieceColour($positionID) == "vacant";
}
function listValidSetupMoves() {
$validMoves = array();
for ($pos = 1; $pos <= 24; $pos++) {
if (getPieceColour($pos) == "vacant")
$validMoves[] = $pos;
}
return $validMoves;
}
function isValidMove($fromPosID, $toPosID) {
return in_array($toPosID, listValidMoves($fromPosID));
}
function listValidMoves($fromPosID) {
global $BoardState, $database;
$validMoves = array();
if (!isset($fromPosID)) {
return $validMoves;
}
$statement = $database->prepare("SELECT Node2 from NineMensPaths WHERE Node1 = :positionID");
$statement->bindValue(':positionID', $fromPosID);
$result = $statement->execute();
if (!$result)
die($databse->lastErrorMsg());
while ($row = $result->fetchArray()) {
if (getPieceColour($row["Node2"]) == "vacant")
$validMoves[] = $row["Node2"];
}
return $validMoves;
}
function countPiecesOnBoard($BW) {
global $BoardState;
$i = 0;
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL && $posID > 0)
$i++;
}
return $i;
}
function listPiecesWithValidMoves($BW) {
global $BoardState;
$results = array();
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL) {
$validMoves = listValidMoves($posID);
if (count($validMoves) > 0)
$results[] = $pieceID;
}
}
return $results;
}
function listValidMovesForAllPieces($BW) {
global $BoardState;
$results = array();
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL) {
$validMoves = listValidMoves($posID);
foreach ($validMoves as $move)
$results[$pieceID][] = $move;
}
}
return $results;
}
function listPiecesThatCanMoveHere($BW, $targetPos) {
global $BoardState;
$results = array();
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL) {
$validMoves = listValidMoves($posID);
foreach ($validMoves as $move)
if ($move == $targetPos)
$results[] = $pieceID;
}
}
return $results;
}
function hasMadeMill($BW) {
//returns a list of places the specified player (B or W) could play on their next move to make a Mill
global $BoardState, $database;
//Get current player positions as comma separated list
$currPieces = "(-1" ;
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL)
$currPieces .= ",".$posID;
}
$currPieces .= ")";
if ($BW == "B")
$lastMove = $_SESSION["currPlayerMoveTo"];
else
$lastMove = $_SESSION["currComputerMoveTo"];
//Get all mills involving the last piece played
$querystring = "SELECT Node1, Node2, Node3 FROM NineMensMills WHERE Node1 = $lastMove AND Node2 IN $currPieces AND Node3 in $currPieces UNION ";
$querystring .= "SELECT Node1, Node2, Node3 FROM NineMensMills WHERE Node1 IN $currPieces AND Node2 = $lastMove AND Node3 in $currPieces UNION ";
$querystring .= "SELECT Node1, Node2, Node3 FROM NineMensMills WHERE Node1 IN $currPieces AND Node2 in $currPieces AND Node3 = $lastMove";
$result = $database->query($querystring);
if (!$result)
die($databse->lastErrorMsg());
if ($row = $result->fetchArray(SQLITE3_ASSOC)) {
//TO-DO check against previous mills
return true;
}
return false;
}
function hasLost($BW) {
global $debug;
$debug .= "checking for $BW loss... ";
if (isSetupStage())
return false;
$piecesWithMoves = listPiecesWithValidMoves($BW);
$countPieces = countPiecesOnBoard($BW);
if (!isset($piecesWithMoves) || count($piecesWithMoves) == 0)
$debug .= "no moves... ";
else
$debug .= count($piecesWithMoves)." moves... ";
$debug .= $countPieces." pieces... ";
if (!isset($piecesWithMoves) || count($piecesWithMoves) == 0 || $countPieces < 3) {
$debug .= "LOSS
";
return true;
} else {
$debug .= "PLAY ON
";
return false;
}
}
function PositionOfPiece($pieceID) {
global $BoardState;
return $BoardState[$pieceID];
}
function PieceAtPosition($posID) {
global $BoardState;
return array_search($posID, $BoardState);
}
//function to see if a position can be clicked on by the player
function PlayerCanClickHere($posID) {
if (isset($_SESSION["winner"])) {
return false;
} elseif ($_SESSION['playerMill'] == "pending") {
if (getPieceColour($posID) == "white")
return true;
else
return false;
} elseif (isSetupStage()) {
return isValidSetupMove($posID);
} elseif (isset($_SESSION['currPlayerMoveFrom']) && !isset($_SESSION['currPlayerMoveTo'])) {
$availableMoves = listValidMoves($_SESSION['currPlayerMoveFrom']);
return (in_array($posID, $availableMoves));
} elseif (getPieceColour($posID) == "black") {
$availableMoves = listValidMoves($posID);
return (count($availableMoves) > 0);
} else {
return false;
}
}
function printArray($array, $sep, $withKeys) {
if (!isset($array)) {
echo "NULL";
} else {
foreach ($array as $key => $value) {
if ($withKeys)
echo $key ." => ";
echo $value . $sep;
}
}
}
?>
function ChecksAndComputerMove() {
if (hasMadeMill("B") && !isset($_SESSION["playerMill"])) {
$_SESSION["playerMill"] = "pending";
} else {
//Check for Player Win
if ( hasLost("W")) {
$_SESSION["winner"] = "Player";
} else {
//Do computer Move
if (isSetupStage())
ComputerSetupMove();
else
ComputerStandardMove();
//check for Computer Mill
if (hasMadeMill("W"))
ComputerMillMove();
//check for Computer win
if (hasLost("B"))
$_SESSION["winner"] = "Computer";
}
}
}
function ComputerSetupMove() {
global $playerCurrPiece;
//Do Computer Move
$pieceID = "W".$_SESSION["SetupStage"];
$moves = listValidSetupMoves();
$playerPossibleMills = PlacesCanMill("B");
$computerPossibleMills = PlacesCanMill("W");
if (count($computerPossibleMills) > 0)
$chosenMove = $computerPossibleMills[0];
elseif (count($playerPossibleMills) > 0)
$chosenMove = $playerPossibleMills[0];
else // if all else fails, pick a random move
$chosenMove = $moves[array_rand($moves)];
MovePieceToPos($pieceID, $chosenMove);
$_SESSION["currComputerMoveTo"] = $chosenMove;
$_SESSION["SetupStage"] ++;
}
function ComputerStandardMove() {
$playerPossibleMills = PlacesCanMill("B");
$computerPossibleMills = PlacesCanMill("W");
//TO-DO - strategy
if (count($computerPossibleMills) > 0) {
$chosenPiece = array_rand($computerPossibleMills);
$i = array_rand($computerPossibleMills[$chosenPiece]);
$chosenMove = $computerPossibleMills[$chosenPiece][$i];
} else {
// if all else fails, pick a random move
$options = listValidMovesForAllPieces("W");
$chosenPiece = array_rand($options);
$i = array_rand($options[$chosenPiece]);
$chosenMove = $options[$chosenPiece][$i];
}
$_SESSION["currComputerMoveFrom"] = PositionOfPiece($chosenPiece);
MovePieceToPos($chosenPiece, $chosenMove);
$_SESSION["currComputerMoveTo"] = $chosenMove;
}
function ComputerMillMove() {
$possibleMills = AboutToMill("B");
if (isset($possibleMills) && count($possibleMills) > 0) {
$i = array_rand($possibleMills);
if ($possibleMills[$i]["NextMove"] == $possibleMills[$i]["Node1"])
$pos = $possibleMills[$i]["Node2"];
else
$pos = $possibleMills[$i]["Node1"];
$pieceID = PieceAtPosition($pos);
} else {
// if all else fails, pick a random move
$pieceID = randomPiece("B");
$pos = PositionOfPiece($pieceID);
}
RemovePiece($pieceID);
$_SESSION["computerMill"] = $pos;
}
function randomPiece($BW) {
global $BoardState;
$currPieces = array();
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL && $posID != -1)
$currPieces[] = $pieceID;
}
return $currPieces[array_rand($currPieces)];
}
function PlacesCanMill($BW) {
global $debug;
//returns a list of moves (PieceID=>PosID) the Player (black) or Computer (white) could play on their next move to make a Mill
$possibleMills = AboutToMill($BW);
$debug .= "count(AboutToMill(".$BW.")) = " . count($possibleMills). "
";
$possibleMillMoves = array();
foreach ($possibleMills as $row) {
if (isSetupStage()) {
$possibleMillMoves[] = $row["NextMove"];
} else {
$debug .= "~~~ Possible Mill at ".$row["NextMove"];
$debug .= " (".$row["Node1"].", ".$row["Node2"]. ", ".$row["Node3"]. "), " ;
$debug .= count(listPiecesThatCanMoveHere($BW, $row["NextMove"])) . " pieces could move there.
";
foreach(listPiecesThatCanMoveHere($BW, $row["NextMove"]) as $piece) {
$pos = PositionOfPiece($piece);
if ($pos != $row["Node1"] && $pos != $row["Node2"] && $pos != $row["Node3"])
$possibleMillMoves[$piece][] = $row["NextMove"];
}
}
}
return $possibleMillMoves;
}
function AboutToMill($BW) {
//returns a list of places the specified player (B or W) could play on their next move to make a Mill
global $BoardState, $database;
//Get current player positions as comma separated list
$currPieces = "(-1" ;
foreach ($BoardState as $pieceID => $posID) {
if ($pieceID[0] == $BW && $posID != NULL)
$currPieces .= ",".$posID;
}
$currPieces .= ")";
//Get places a mill could be made
$querystring = "SELECT Node1 as NextMove, Node1, Node2, Node3 FROM NineMensMills WHERE Node1 NOT IN $currPieces AND Node2 IN $currPieces AND Node3 in $currPieces UNION ";
$querystring .= "SELECT Node2 as NextMove, Node1, Node2, Node3 FROM NineMensMills WHERE Node1 IN $currPieces AND Node2 NOT IN $currPieces AND Node3 in $currPieces UNION ";
$querystring .= "SELECT Node3 as NextMove, Node1, Node2, Node3 FROM NineMensMills WHERE Node1 IN $currPieces AND Node2 in $currPieces AND Node3 NOT IN $currPieces";
$result = $database->query($querystring);
if (!$result)
die($databse->lastErrorMsg());
$possibleMills = array();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$possibleMills[] = $row;
}
//Filter out illegal moves, previous mills, etc
if (isSetupStage()) {
foreach ($possibleMills as $key => $row) {
if (!isValidSetupMove($row["NextMove"]))
unset($possibleMills[$key]);
}
} else {
//TO-DO
}
return $possibleMills;
}
?>