public List <Board> GenerateSafeBoards(bool includeCheckmates) { List <Board> boards = this.GenerateSubBoards(); Board workingBoard = new Board(); for (int k = 0; k < boards.Count; k++) { workingBoard.Copy(boards[k]); foreach (Board b in workingBoard.GenerateSubBoards()) { if (b.GetWinner() == workingBoard.CurrentPlayer) { boards.RemoveAt(k); k--; break; } if (includeCheckmates && BoardEvaluator.HasCheckmate(b, workingBoard.CurrentPlayer)) { boards.RemoveAt(k); k--; break; } } } return(boards); }
// Negamax style alpha beta pruning search private int AlphaBeta(Board b, int depth, int alpha, int beta) { if (depth == 0) { return(-b.Evaluation); } switch (b.GetWinner()) { case PieceColor.White: return((b.CurrentPlayer == PieceColor.White) ? BoardEvaluator.EVAL_WHITE_WIN : -BoardEvaluator.EVAL_WHITE_WIN); case PieceColor.Black: return((b.CurrentPlayer == PieceColor.White) ? BoardEvaluator.EVAL_BLACK_WIN : -BoardEvaluator.EVAL_BLACK_WIN); case PieceColor.Both: return(BoardEvaluator.EVAL_DRAW); case PieceColor.Empty: break; } List <Board> boards = b.GenerateSubBoards(); if (boards.Count == 0) { return(NOMOVES); } positionsEvaluated += boards.Count; BoardEvaluator.SortBoards(ref boards); int current; int best = MINSCORE; int localAlpha = alpha; for (int i = 0; i < boards.Count; i++) { current = -AlphaBeta(boards[i], depth - 1, -beta, -localAlpha); if (current == -NOMOVES) { current = boards[i].Evaluation; } best = Math.Max(current, best); if (best >= beta) { return(beta); } if (best > localAlpha) { localAlpha = best; } } return(best); }
// Finds all unique boards possible after applying a move by the current player public List <Board> GenerateSubBoards() { Dictionary <Board, int> boards = new Dictionary <Board, int>(256); if (this.GetWinner() != PieceColor.Empty) { return(new List <Board>()); } Board b = new Board(this); for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { if (this.GetColorAt(i, j) == PieceColor.Empty) { b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.LowerLeftAntiClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.LowerLeftClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.LowerRightAntiClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.LowerRightClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.UpperLeftAntiClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.UpperLeftClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.UpperRightAntiClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } b.Copy(this); b.ApplyMoveFast(i, j, this.CurrentPlayer, Rotation.UpperRightClockwise); if (!boards.ContainsKey(b)) { b.Evaluation = BoardEvaluator.Evaluate(ref b); boards.Add(new Board(b), 0); } } } } return(new List <Board>(boards.Keys)); }
public override Board Play(Board b) { if (b.CurrentPlayer != this.Color) { throw new InvalidOperationException(); } Debug.Assert(false, b.ToString()); List <Board> boards; if (maxDepth == 2) { boards = b.GenerateSafeBoards(true); } else { boards = b.GenerateSafeBoards(); } Debug.WriteLine("Safe moves: " + boards.Count.ToString()); // if opponent wins on their next move no matter what if (boards.Count == 0) { // if we have a legal move, do it even though it's a loser boards = b.GenerateSubBoards(); if (boards.Count == 0) { return(b); } return(boards[0]); } BoardEvaluator.SortBoards(ref boards); int current; int localAlpha = MINSCORE; Board bestBoard = boards[0]; DateTime startTime = DateTime.Now; positionsEvaluated = 0; for (int i = 0; i < boards.Count; i++) { // Console.Write("+"); current = -AlphaBeta(boards[i], maxDepth, MINSCORE, -localAlpha); if (current == -NOMOVES) { current = boards[i].Evaluation; } if (current > localAlpha) { localAlpha = current; bestBoard = boards[i]; if (current == BoardEvaluator.EVAL_WHITE_WIN) { break; } } } DateTime endTime = DateTime.Now; TimeSpan moveTime = endTime - startTime; //Console.WriteLine(" Score: " + localAlpha.ToString()); //Console.WriteLine("Time: {0}", moveTime.TotalSeconds); //Console.WriteLine("Moves evaluated: {0}", positionsEvaluated); //Console.WriteLine("Moves/sec: {0}", positionsEvaluated / moveTime.TotalSeconds); Debug.Assert(false, bestBoard.ToString()); return(bestBoard); }
public override Board Play(Board b) { if (b.CurrentPlayer != this.Color) { throw new InvalidOperationException(); } List <Board> boards = b.GenerateSafeBoards(true); Debug.WriteLine("Safe moves: " + boards.Count.ToString()); // if opponent wins on their next move no matter what if (boards.Count == 0) { // if we have a legal move, do it even though it's a loser boards = b.GenerateSubBoards(); if (boards.Count == 0) { return(b); } return(boards[0]); } BoardEvaluator.SortBoards(ref boards); int current; int localAlpha = MINSCORE; Board bestBoard = boards[0]; Board bestBoardLastCompletedDepth = boards[0]; int lastCompletedDepth = 1; int lastCompletedDepthScore = 0; startTime = DateTime.Now; for (int depth = 1; depth < 36; depth++) { localAlpha = MINSCORE; int i; for (i = 0; i < boards.Count; i++) { current = -AlphaBeta(boards[i], depth, MINSCORE, -localAlpha); if (current == -TIMEUP) { break; } if (current == -NOMOVES) { current = boards[i].Evaluation; } boards[i].Evaluation = current; if (current > localAlpha) { localAlpha = current; bestBoard = boards[i]; if (current == BoardEvaluator.EVAL_WHITE_WIN) { lastCompletedDepth = depth; lastCompletedDepthScore = current; bestBoardLastCompletedDepth = bestBoard; break; } } } // bail from the loop if we didn't make it // all the way through the search at this depth if (i != boards.Count) { break; } // otherwise save the best move lastCompletedDepthScore = localAlpha; lastCompletedDepth = depth; bestBoardLastCompletedDepth = bestBoard; // re-sort the boards after each completed depth // to increase the number of cutoffs at the next depth BoardEvaluator.SortBoards(ref boards); } Debug.WriteLine(String.Format("Depth: {0} Score: {1}", lastCompletedDepth, lastCompletedDepthScore)); return(bestBoardLastCompletedDepth); }