private void SetupGame() { _myGame.ResetBoard(); _myAgent = GetAgent(); _myPlayer = PlayerSelectComboBox.SelectedItem.ToString() == BoardStates.white.ToString() ? BoardStates.black : BoardStates.white; _boardPanels = new PiecePanel[OthelloGame.BOARD_SIZE, OthelloGame.BOARD_SIZE]; int tileSize = ((Size.Width > Size.Height) ? Size.Height - 45 : Size.Width - 45) / OthelloGame.BOARD_SIZE; for (int i = 0; i < OthelloGame.BOARD_SIZE; i++) { for (int j = 0; j < OthelloGame.BOARD_SIZE; j++) { var newPanel = new PiecePanel(new int[] { i, j }) { Size = new Size(tileSize, tileSize), Location = new Point(tileSize * i, tileSize * j) }; newPanel.MouseClick += new MouseEventHandler(OthelloPeice_Click); Controls.Add(newPanel); _boardPanels[i, j] = newPanel; Color panelcolor = Color.Red; if (BoardColorDictionary.BoardStateColors.TryGetValue(_myGame.GetBoard()[i, j], out panelcolor)) { _boardPanels[i, j].ReColor(panelcolor); } } } if (_myGame.WhosTurn != _myPlayer) { _myGame.MakeMove(_myAgent.MakeMove(_myGame, ~_myPlayer)); } }
public override double EvaluateBoard(OthelloGame game, BoardStates player) { ///Based of features of the board that humans have identified. ///Hints of evaluation from any source I could find ///idealy these could me optimized using a genetic algorithm, ///but that is a different project double value = 0; int empty = game.GetPieceCount(BoardStates.empty); if (game.GameComplete) { return(CompleteEval(player, game)); } //plane funct //value += coinDiffSlope * (game.GetPieceCount(player) - game.GetPieceCount(~player)) + (empty * coinTimeSlope) + coinDiffOffset; //value += cornerDiffSlope * (game.GetCornerCount(player) - game.GetCornerCount(~player)) + (empty * cornerTimeSlope) + cornerDiffOffset; //value += nearCornerDiffSlope * (game.GetAdjCornerCount(player) - game.GetAdjCornerCount(~player)) + (empty * nearCornerTimeSlope) + nearCornerDiffOffset; //value += avalibleMoveDiffSlope * (game.GetPossiblePlayList(player).Count() - game.GetPossiblePlayList(~player).Count()) + (empty * avalibleMoveTimeSlope) + avalibleMoveDiffOffset; //value += nonTurnableCoinDiffSlope * (game.GetSafePeiceCountEstimation(player) - game.GetSafePeiceCountEstimation(~player)) + (empty * nonTurnableTimeSlope) + nonTurnableCoinDiffOffset; //value += controlledCornerDiffSlope * (game.GetControlledCorners(player) - game.GetControlledCorners(~player)) + (empty * controlledCornerTimeSlope) + controlledCornerDiffOffset; //power funct value += coinDiffSlope * Math.Pow(game.GetPieceCount(player) - game.GetPieceCount(~player) + empty - coinDiffOffset, coinTimeSlope); value += cornerDiffSlope * Math.Pow(game.GetCornerCount(player) - game.GetCornerCount(~player) + empty - cornerDiffOffset, cornerTimeSlope); value += nearCornerDiffSlope * Math.Pow(game.GetAdjCornerCount(player) - game.GetAdjCornerCount(~player) + empty - nearCornerDiffOffset, nearCornerTimeSlope); value += avalibleMoveDiffSlope * Math.Pow(game.GetPossiblePlayList(player).Count() - game.GetPossiblePlayList(~player).Count() + empty - avalibleMoveDiffOffset, avalibleMoveTimeSlope); value += nonTurnableCoinDiffSlope * Math.Pow(game.GetSafePeiceCountEstimation(player) - game.GetSafePeiceCountEstimation(~player) + empty - nonTurnableCoinDiffOffset, nonTurnableTimeSlope); value += controlledCornerDiffSlope * Math.Pow(game.GetControlledCorners(player) - game.GetControlledCorners(~player) + empty - controlledCornerDiffOffset, controlledCornerTimeSlope); return(value); }
private void OthelloPeice_Click(object sender, MouseEventArgs e) { BoardStates player = e.Button == MouseButtons.Left ? BoardStates.black : BoardStates.white; try { PiecePanel thisPanel = (PiecePanel)sender; if (player != _myGame.WhosTurn) { if (player == BoardStates.white) { BlackMoveLabel.Visible = true; _twoSecondTimer.Elapsed += new System.Timers.ElapsedEventHandler(BlackMoveLabel_VisibilityFalse); _twoSecondTimer.Enabled = true; } else if (player == BoardStates.black) { WhiteMoveLabel.Visible = true; _twoSecondTimer.Elapsed += new System.Timers.ElapsedEventHandler(WhiteMoveLabel_VisibilityFalse); _twoSecondTimer.Enabled = true; } } _myGame.MakeMove(player, new byte[] { (byte)thisPanel.location[0], (byte)thisPanel.location[1] }); RefreshControls(); } catch { throw new NotSupportedException("OthelloPeice_Click is not to be used with a control other than a PiecePanel"); } GameCompletionProgressBar.Value = _myGame.GetMovesMade(); }
public override byte[] MakeMove(OthelloGame game, BoardStates player) { byte[] bestMove = new byte[] { byte.MaxValue, byte.MaxValue }; List <byte[]> moves = game.GetPossiblePlayList(); double bestScore = int.MinValue + 1; if (game.GetPieceCount(BoardStates.empty) > 58)//first two moves, don't compute { return(OpeningMove(player, game)); } else if (moves.Count == 1) //don't compute if there is only 1 move { return(moves[0]); } foreach (byte[] move in moves) { OthelloGame testGame = game.DeepCopy(); testGame.MakeMove(move); double thisScore = EvaluateBoard(testGame, player); if (thisScore > bestScore) { bestScore = thisScore; bestMove = move; } } if ((bestMove[0] == byte.MaxValue || bestMove[1] == byte.MaxValue) && moves.Count > 0) {//All moves are valued at -inf, return one of em return(moves[0]); } return(bestMove); }
public int GetControlledCorners(BoardStates player) {//If control corner & two adjacent "X" peices byte[][][] corners = new byte[4][][] { new byte[3][] { new byte[] { 0, 0 }, new byte[] { 0, 1 }, new byte[] { 1, 0 } }, new byte[3][] { new byte[] { BOARD_SIZE - 1, BOARD_SIZE - 1 }, new byte[] { BOARD_SIZE - 1, BOARD_SIZE - 2 }, new byte[] { BOARD_SIZE - 2, BOARD_SIZE - 1 } }, new byte[3][] { new byte[] { 0, BOARD_SIZE - 1 }, new byte[] { 0, BOARD_SIZE - 2 }, new byte[] { 1, BOARD_SIZE - 1 } }, new byte[3][] { new byte[] { BOARD_SIZE - 1, 0 }, new byte[] { BOARD_SIZE - 2, 0 }, new byte[] { BOARD_SIZE - 1, 1 } } }; int cornerCount = 0; foreach (byte[][] corner in corners) { bool controlled = true; foreach (byte[] location in corner) { controlled &= Board[location[0], location[1]] == player; } if (controlled) { cornerCount++; } } return(cornerCount); }
private bool ProcessMove() { var hit = GameBoard !.DropBomb((int)ClickY !, (int)ClickX !); var state = new BoardState(GameSession !, GameBoard.WhiteToMove); GameSession !.BoardStates.Add(state); List <BoardTile> boardTiles = new(); var s = GameBoard.BoardHistory.Last(); for (int y = 0; y < s.Board[0].GetLength(0); y++) { for (int x = 0; x < s.Board[0].GetLength(1); x++) { boardTiles.Add( new BoardTile(state, x, y, s.Board[(int)GameBoard.BoardType.WhiteShips][y, x], s.Board[(int)GameBoard.BoardType.BlackShips][y, x], s.Board[(int)GameBoard.BoardType.WhiteHits][y, x], s.Board[(int)GameBoard.BoardType.BlackHits][y, x])); } } _db.BoardTiles.AddRange(boardTiles); _db.SaveChanges(); return(hit != false); }
public bool MakeMove(BoardStates player, byte[] location) { bool moveMade = false; List <byte[]> takenPeices; bool valid = ValidMove(player, location, out takenPeices); if (valid) { Board[location[0], location[1]] = player; for (int i = 0; i < takenPeices.Count(); i++) { Board[takenPeices[i][0], takenPeices[i][1]] = player; } BoardStates opponent = ~player; if (PlayerHasMove(opponent)) { WhosTurn = opponent;//only switch whos turn it is if other player has moves avalible } BoardHistory.Add(GetBoardCopy(Board)); moveMade = true; } else { int debugLocation = 0;//to stop debugger on invalid move } GameOver(); return(moveMade); }
private byte[] PredictBestMove(int depth, OthelloGame game, BoardStates player) { byte[] bestMove = new byte[] { byte.MaxValue, byte.MaxValue }; List <byte[]> moves = game.GetPossiblePlayList(); double bestScore = int.MinValue + 1; if (game.GetPieceCount(BoardStates.empty) > 58)//first two moves, don't compute { return(OpeningMove(player, game)); } else if (moves.Count == 1) //don't compute if there is only 1 move { return(moves[0]); } foreach (byte[] move in moves) { OthelloGame testGame = game.DeepCopy(); testGame.MakeMove(move); double thisScore = MinimaxAlphaBeta(testGame, depth - 1, double.MinValue, double.MaxValue, player); if (thisScore > bestScore) { bestScore = thisScore; bestMove = move; } } return(bestMove); }
private double HeuristicEval(BoardStates player, OthelloGame game) { //Based of features of the board that humans have identified. //Hints of evaluation from any source I could find //idealy these could me optimized using a genetic algorithm, //but that is a different project const int searchableDepthOverride = 2; //override min-max in favor of complete evaluation const int endGame = 20; //<20 moves is endgame const int midGame = 40; // 20 moves in is midgame double value = 0; int empty = game.GetPieceCount(BoardStates.empty); if (game.GameComplete) { return(CompleteEval(player, game)); } else if (empty < searchableDepthOverride) { return(MinimaxAlphaBeta(game, searchableDepthOverride, int.MinValue, int.MaxValue, player)); } value += coinDiffWeight * Math.Pow((game.GetPieceCount(player) - game.GetPieceCount(~player) + empty - coinDiffOffset), coinDiffPower); value += cornerDiffWeight * Math.Pow((game.GetCornerCount(player) - game.GetCornerCount(~player) + empty - cornerDiffOffset), cornerDiffPower); value += nearCornerDiffWeight * Math.Pow((game.GetAdjCornerCount(player) - game.GetAdjCornerCount(~player) + empty - nearCornerDiffOffset), nearCornerDiffPower); value += avalibleMoveDiffWeight * Math.Pow((game.GetPossiblePlayList(player).Count() - game.GetPossiblePlayList(~player).Count() + empty - avalibleMoveDiffOffset), avalibleMoveDiffPower); value += nonTurnableCoinDiffWeight * Math.Pow((game.GetSafePeiceCountEstimation(player) - game.GetSafePeiceCountEstimation(~player) + empty - nonTurnableCoinDiffOffset), nonTurnableCoinDiffPower); value += ControlledCornerDiffWeight * Math.Pow((game.GetControlledCorners(player) - game.GetControlledCorners(~player) + empty - ControlledCornerDiffOffset), ControlledCornerDiffPower); return(value); }
public static BoardStates GetCurrentLeader(OthelloGame game) { BoardStates leader = BoardStates.empty; leader = game.GetPieceCount(BoardStates.white) > game.GetPieceCount(BoardStates.black) ? BoardStates.white : BoardStates.black; return(leader); }
//*************************Static Methods************************** public static BoardStates OpposingPlayer(BoardStates player) { if (player == BoardStates.empty) { return(BoardStates.empty); } return(~player); }
public static void TestMinMax(OthelloGame _myGame, int minimaxDepth = 3) { const int testCount = 100; object wonGamesLock = new object(); int wonGames = 0; object tieGamesLock = new object(); int tieGames = 0; var stopwatch = Stopwatch.StartNew(); //Parallel.For(0, testCount, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },index => //{ for (int index = 0; index < testCount; index++) {//non-parallel for loop to debug BoardStates player = (index % 2 == 0) ? BoardStates.black : BoardStates.white; OthelloGame testGame = new OthelloGame(); MinMaxAgent othelloAgent = new MinMaxAgent(2); RandomAgent randAgent = new RandomAgent(); while (!testGame.GameComplete) { if (testGame.WhosTurn == player) { testGame.MakeMove(othelloAgent.MakeMove(testGame, player)); } else { testGame.MakeMove(randAgent.MakeMove(testGame, ~player)); } } if (testGame.GameComplete)//just gotta check { if (testGame.FinalWinner == player) { lock (wonGamesLock) { wonGames++; } } else if (testGame.FinalWinner == BoardStates.empty) { lock (tieGamesLock) { tieGames++; } } Console.WriteLine("Finished Game " + index + ", " + testGame.FinalWinner.ToString() + " won " + testGame.GetPieceCount(testGame.FinalWinner) + " to " + testGame.GetPieceCount(OthelloGame.OpposingPlayer(testGame.FinalWinner)));; } else { throw new Exception("MiniMax Testing didn't complete a game"); } } //}); stopwatch.Stop(); Console.WriteLine("Won " + wonGames + " / " + testCount + " games, " + ((double)wonGames / testCount) * 100 + " %"); Console.WriteLine("Tied " + tieGames + " / " + testCount + " games, " + ((double)tieGames / testCount) * 100 + " %"); Console.WriteLine("Lost " + (testCount - wonGames - tieGames) + " / " + testCount + " games, " + ((double)(testCount - wonGames - tieGames) / testCount) * 100 + " %"); Console.WriteLine("Elapsed time for games : {0}", stopwatch.Elapsed); }
public double Evaluate(IChromosome chromosome) {//Play n games vs a random (to be Neural Net), % win is Fitness FloatingPointChromosome myChromosome = (FloatingPointChromosome)chromosome; double[] genes = myChromosome.ToFloatingPoints(); double fitness = 0; double wonCount = 0; object wonCountLock = new object(); for (int index = 0; index < TEST_COUNT; index++) { //Parallel.For(0, TEST_COUNT, new ParallelOptions() { MaxDegreeOfParallelism = 2}, // (index) => { BoardStates player = (index % 2 == 0) ? BoardStates.black : BoardStates.white; OthelloGame othelloGame = new OthelloGame(); IEvaluationAgent heurAgent = new HeuristicAgent(genes); while (!othelloGame.GameComplete) { if (othelloGame.WhosTurn == player) { othelloGame.MakeMove(heurAgent.MakeMove(othelloGame, player)); } else { othelloGame.MakeMove(opposingAgent.MakeMove(othelloGame, ~player)); } } if (othelloGame.GameComplete)//just gotta check { if (othelloGame.FinalWinner == player) { lock (wonCountLock) { wonCount++; } } else if (othelloGame.FinalWinner == BoardStates.empty) { lock (wonCountLock) { wonCount += .5; } } } else { throw new Exception("EvaluationFitness didn't complete a game"); } // }); } fitness = (double)wonCount / TEST_COUNT; //System.Diagnostics.Debug.WriteLine("Fitness: " + fitness); return(fitness); }
//************************Potential Feature Functions****************** public int GetCornerCount(BoardStates player) { int count = 0; count += Convert.ToInt32(Board[0, 0] == player); count += Convert.ToInt32(Board[0, BOARD_SIZE - 1] == player); count += Convert.ToInt32(Board[BOARD_SIZE - 1, 0] == player); count += Convert.ToInt32(Board[BOARD_SIZE - 1, BOARD_SIZE - 1] == player); return(count); }
private static int CompleteEval(BoardStates player, OthelloGame game) { if (game.FinalWinner == player) { return(int.MaxValue); } else { return(int.MinValue); } }
public bool[] GetPlayableStateList(BoardStates player) { bool[] bstates = new bool[BOARD_SIZE * BOARD_SIZE]; for (byte i = 0; i < BOARD_SIZE; i++) { for (byte j = 0; j < BOARD_SIZE; j++) { bstates[i + j] = ValidMove(player, new byte[] { i, j }) ? true : false; } } return(bstates); }
private static byte[] OpeningMove(BoardStates player, OthelloGame game) {//avoid computation for first move - only one symmetric option //randomly select perpendicular or diagonal for second move - parallel //has been shown to be much worse //SPECIFIC TO 8x8 BOARDS byte[][] firstMoves = new byte[4][] { new byte[] { 2, 3 }, new byte[] { 3, 2 }, new byte[] { 4, 5 }, new byte[] { 5, 4 } }; if (game.GetPieceCount(BoardStates.empty) == 60) { Random rndGen = new Random(); int rand = (int)Math.Ceiling(rndGen.NextDouble() * 4); switch (rand) { case 1: return(firstMoves[0]); case 2: return(firstMoves[1]); case 3: return(firstMoves[2]); case 4: return(firstMoves[3]); default: throw new Exception("OpeningMove has faulted with random number generation"); } } if (game.GetPieceCount(BoardStates.empty) == 59) { List <byte[]> moves = game.GetPossiblePlayList(); Random rndGen = new Random(); byte rand = (byte)Math.Ceiling(rndGen.NextDouble() * 2); switch (rand) { case 1: //diagonal return(moves[0]); case 2: //perpendicular return(moves[0]); default: throw new Exception("Opening move has faulted with random number generation"); } } return(new byte[] { byte.MaxValue, byte.MaxValue }); }
protected static BoardStates[,] GetBoardCopy(BoardStates[,] board) { BoardStates[,] boardCopy = new BoardStates[BOARD_SIZE, BOARD_SIZE]; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { boardCopy[i, j] = board[i, j]; } } return(boardCopy); }
private static int CompleteEval(BoardStates player, OthelloGame game) { ///Returns complete worth of board, -inf for loss, +inf for win if (game.FinalWinner == player) { return(int.MaxValue); } else { return(int.MinValue); } }
public int GetPieceCount(BoardStates bstate) { int count = 0; foreach (BoardStates piece in Board) { if (piece == bstate) { count++; } } return(count); }
protected bool[] GetStateList(BoardStates bstate) /// /// /// { bool[] bstates = new bool[BOARD_SIZE * BOARD_SIZE]; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { bstates[i + j] = (Board[i, j] == bstate) ? true : false; } } return(bstates); }
public List <byte[]> GetPossiblePlayList(BoardStates player) { List <byte[]> possiblePlays = new List <byte[]>(); for (byte i = 0; i < BOARD_SIZE; i++) { for (byte j = 0; j < BOARD_SIZE; j++) { if (ValidMove(player, new byte[] { i, j })) { possiblePlays.Add(new byte[] { i, j }); } } } return(possiblePlays); }
public override byte[] MakeMove(OthelloGame game, BoardStates player) { List <byte[]> possibleMoves = game.GetPossiblePlayList(player); if (possibleMoves.Count == 0) { return new byte[] { byte.MaxValue, byte.MaxValue } } ; Random rndGenerator = new Random(); int rnd = (int)Math.Floor(rndGenerator.NextDouble() * possibleMoves.Count); return(possibleMoves[rnd]); } }
//**************************Private Methods**************************** protected bool[,] GetStateArray(BoardStates bstate) /// ///Returns bool array of bstate peices the size of the board, ///With 1 meaning a bstate peice is there, 0 meaning it is not /// { bool[,] bstates = new bool[BOARD_SIZE, BOARD_SIZE]; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { bstates[i, j] = (Board[i, j] == bstate) ? true : false; } } return(bstates); }
public bool PlayerHasMove(BoardStates player) { bool hasMove = false; for (byte i = 0; i < BOARD_SIZE; i++) { for (byte j = 0; j < BOARD_SIZE; j++) { if (ValidMove(player, new byte[] { i, j })) { hasMove = true; return(hasMove); } } } return(hasMove); }
public bool ValidMove(BoardStates player, byte[] location, bool playerTurn = false) { bool valid = true; valid &= !GameComplete; valid &= OnBoard(location); if (!valid) { return(valid); } valid &= Board[location[0], location[1]] == BoardStates.empty; if (playerTurn) { valid &= WhosTurn == player; } List <byte[]> takenPeices = TakesPieces(player, location); valid &= takenPeices.Count() > 0; return(valid); }
private List <byte[]> TakesPieces(BoardStates player, byte[] location) { List <byte[]> taken = new List <byte[]>();//array of all pieces to be flipped byte minX = location[0] > 0 ? (byte)(location[0] - 1) : (byte)0; byte minY = location[1] > 0 ? (byte)(location[1] - 1) : (byte)0; byte maxX = location[0] + 2 < BOARD_SIZE ? (byte)(location[0] + 1) : (byte)(BOARD_SIZE - 1); byte maxY = location[1] + 2 < BOARD_SIZE ? (byte)(location[1] + 1) : (byte)(BOARD_SIZE - 1); for (byte x = minX; x <= maxX; x++) { for (byte y = minY; y <= maxY; y++) { // int subtakenCount = 0; BoardStates opposingPlayer = ~player; //store to save some computing time if (Board[x, y] == opposingPlayer && (x != location[0] || y != location[1])) { sbyte[] direction = new sbyte[] { (sbyte)(x - location[0]), (sbyte)(y - location[1]) }; byte[] searchedLocation = new byte[] { x, y }; List <byte[]> subTaken = new List <byte[]>(); while (OnBoard(searchedLocation) && Board[searchedLocation[0], searchedLocation[1]] == opposingPlayer) { subTaken.Add(searchedLocation); searchedLocation = new byte[] { (byte)(searchedLocation[0] + direction[0]), (byte)(searchedLocation[1] + direction[1]) }; } if (OnBoard(searchedLocation) && Board[searchedLocation[0], searchedLocation[1]] == player) { taken = taken.Concat(subTaken).ToList(); } } } } return(taken); }
public override byte[] MakeMove(OthelloGame game, BoardStates player) { List <byte[]> moves = game.GetPossiblePlayList(player); double bestScore = double.MinValue; byte[] bestMove = new byte[] { byte.MaxValue, byte.MaxValue }; foreach (byte[] move in moves) { OthelloGame testGame = game.DeepCopy(); testGame.MakeMove(move); double thisScore = EvaluateBoard(testGame, player); if (thisScore > bestScore) { bestScore = thisScore; bestMove = move; } } return(bestMove); }
public void checkGameState() { BoardStates boardStates = EvaluateBoard(); if (boardStates == BoardStates.XWin) { winText.text = "X Wins!"; endGame(); return; } else if (boardStates == BoardStates.OWin) { winText.text = "O Wins!"; Instance.endGame(); return; } else if (boardStates == TurnManager.BoardStates.Tie) { winText.text = "Its a Tie"; endGame(); return; } }
private void SaveState() { var state = new BoardState(GameSession !, GameBoard !.WhiteToMove); GameSession !.BoardStates.Add(state); List <BoardTile> boardTiles = new(); var s = GameBoard.BoardHistory.Last(); for (int y = 0; y < s.Board[0].GetLength(0); y++) { for (int x = 0; x < s.Board[0].GetLength(1); x++) { boardTiles.Add( new BoardTile(state, x, y, s.Board[(int)GameBoard.BoardType.WhiteShips][y, x], s.Board[(int)GameBoard.BoardType.BlackShips][y, x], s.Board[(int)GameBoard.BoardType.WhiteHits][y, x], s.Board[(int)GameBoard.BoardType.BlackHits][y, x])); } } _db.BoardTiles.AddRange(boardTiles); _db.SaveChanges(); }