Skip to content

Instantly share code, notes, and snippets.

@slior
Created December 6, 2020 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slior/604501df6fde21baffea7899dfed071e to your computer and use it in GitHub Desktop.
Save slior/604501df6fde21baffea7899dfed071e to your computer and use it in GitHub Desktop.
Mancala - Adding AI facility to game
const PLAYER = {
one : {
toString : () => "ONE"
, theOtherOne : () => PLAYER.two
, number : 1
, ai : () => PLAYER.one._aiPlayer
, _aiPlayer : None
}
, two : {
toString : () => "TWO"
, theOtherOne : () => PLAYER.one
, number : 2
, ai : () => PLAYER.two._aiPlayer
, _aiPlayer : None
}
}
class MancalaGame
{
constructor(gameSize,cnvsELID,_updatePlayerCallback,_showMsgCallback,requestedAIPlayers)
{
...
this._setupAIPlayersIfRequested(requestedAIPlayers);
...
}
_setupAIPlayersIfRequested(requestedAIPlayers)
{
dbg("Setting AI Players...");
PLAYER.one._aiPlayer = maybe(determineAIPlayer(requestedAIPlayers.p1))
PLAYER.two._aiPlayer = maybe(determineAIPlayer(requestedAIPlayers.p2))
dbg("AI Players: P1: " + PLAYER.one._aiPlayer + ", P2: " + PLAYER.two._aiPlayer);
function determineAIPlayer(requestedAI)
{
return requestedAI ? new SimpleAIPlayer() : null;
}
}
start()
{
this._makeNextMoveIfCurrentPlayerIsAI();
}
handleCellClick(boardCell)
{
...
this._makeNextMoveIfCurrentPlayerIsAI()
}
_makeNextMoveIfCurrentPlayerIsAI()
{
if (!this.gameDone)
{
this.player.ai().ifPresent(aiPlayer => {
let aiMove = aiPlayer.nextMove(this.board,this.player.number)
setTimeout(() => { this._makeMove(aiMove)}, 200) //artifical wait, so we can "see" the ai playing
})
}
}
}
const P2_PARAM_NAME = "p2";
const P1_PARAM_NAME = "p1";
function setup()
{
game = new main.MancalaGame(resolveGameSize(),'cnvsMain',updateCurrentPlayer,showMsg, resolveRequestedAI());
game.start();
}
function resolveRequestedAI()
{
let params = new URLSearchParams(window.location.search);
let p2 = params.has(P2_PARAM_NAME) ? params.get(P2_PARAM_NAME) : "";
let p1 = params.has(P1_PARAM_NAME) ? params.get(P1_PARAM_NAME) : "";
return { p1 : p1, p2 : p2}
}
class SimpleAIPlayer
{
constructor()
{
}
/**
* Given a board and side to play, return the cell to play
* @param {Board} board The current board to play
* @param {number} side The side to player, either 1 or 2
*
* @returns The board cell to play
*/
nextMove(board,side)
{
requires(board != null, "Board can't be null for calculating next move")
requires(side == 1 || side == 2,"Side must be either 1 or 2")
//Simple heuristic: choose the cell with the largest number of stones.
var maxStoneCell = side == 1 ? 1 : board.totalCellCount()-1;
switch (side)
{
case 1 : board.forAllPlayer1Cells(c => { if (board.stonesIn(c) > board.stonesIn(maxStoneCell)) maxStoneCell = c })
case 2 : board.forAllPlayer2Cells(c => { if (board.stonesIn(c) > board.stonesIn(maxStoneCell)) maxStoneCell = c })
}
dbg("Playing cell: " + maxStoneCell + " with " + board.stonesIn(maxStoneCell) + " for player " + side);
return maxStoneCell;
}
}
module.exports = {
SimpleAIPlayer
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment