public static MovementState CreateMovementState(MovementTypes type, Vector3 hoz, Vector3 left) { MovementState toCreate = null; switch (type) { case MovementTypes.AI: throw new NotImplementedException(); break; case MovementTypes.Null: toCreate = new NullMove(); break; case MovementTypes.OneAxis: toCreate = new HorizontalAxisMove(DEFAULT_SPEED, hoz); break; case MovementTypes.TwoAxis: toCreate = new TwoAxisMove(DEFAULT_SPEED, hoz, left); break; default: //Only reached if a new type is added, but there is also no corresponding case throw new NotImplementedException(); } return(toCreate); }
public void NullMoveTest() { IPosition current = new Position(new Coordinate(1, 1), Business.Enums.Direction.North); IPosition expected = new Position(new Coordinate(1, 1), Business.Enums.Direction.North); IMove nullMove = new NullMove(); IPosition output = nullMove.Move(current); Assert.AreEqual(expected.Coordinate.X, output.Coordinate.X); Assert.AreEqual(expected.Coordinate.Y, output.Coordinate.Y); Assert.AreEqual(expected.Direction, output.Direction); }
/// <summary> /// AlphaBeta algorithm.Calculates best line in given depth /// </summary> /// <param name="alpha">Lowest value</param> /// <param name="beta">highest value</param> /// <param name="ply"></param> /// <param name="depth"></param> /// <param name="pv">Holds principal variation</param> /// <param name="nullmove"></param> /// <param name="nodeCount">Holds value of calculated moves</param> /// <returns>Returning value is the score of best line</returns> int AlphaBeta(int alpha, int beta, int ply, int depth, List <Move> pv, NullMove nullmove, ref int nodeCount) { //if time out or exit requested after 1st iteration,so leave thinking. if ((!HaveTime() || Exit) && iterationPly > 1) { return(0); } nodeCount++; var moves = Board.GenerateMoves(); if (!moves.Any()) { return(-Board.GetCheckMateOrStaleMateScore(ply)); } if (ply <= 0) { return(QuiescenceSearch(alpha, beta, ref nodeCount)); } var localpv = new List <Move>(); var pvSearch = false; #region Null Move Prunning if (nullmove == NullMove.Enabled && !Board.IsInCheck()) { int R = 2; Board.ToggleSide(); int score = -AlphaBeta(-beta, -beta + 1, ply - 1 - R, depth + 1, localpv, NullMove.Disabled, ref nodeCount); Board.ToggleSide(); if (score >= beta) { return(score); } } #endregion var sortedMoves = SortMoves(moves, depth); foreach (var move in sortedMoves) { Board.MakeMove(move); int score; if (Board.threeFoldRepetetion.IsThreeFoldRepetetion) { score = Board.Draw; } else { #region Late Move Reduction if (!Board.IsInCheck()) { score = -AlphaBeta(-alpha - 1, -alpha, ply - 2, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } else { score = alpha + 1; } #endregion if (score > alpha) { if (pvSearch) { score = -AlphaBeta(-alpha - 1, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); if (score > alpha && score < beta) { score = -AlphaBeta(-beta, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } } else { score = -AlphaBeta(-beta, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } } } Board.TakeBackMove(move); if (score >= beta) { killerMoves.Add(move, depth); return(beta);//beta cut-off } if (score > alpha) { historyMoves.AddMove(move); pvSearch = true; alpha = score; pv.Clear(); pv.Add(move); pv.AddRange(localpv); } } return(alpha); }
/// <summary> /// AlphaBeta algorithm.Calculates best line in given depth /// </summary> /// <param name="alpha">Lowest value</param> /// <param name="beta">highest value</param> /// <param name="ply"></param> /// <param name="depth"></param> /// <param name="pv">Holds principal variation</param> /// <param name="nullmove"></param> /// <param name="nodeCount">Holds value of calculated moves</param> /// <returns>Returning value is the score of best line</returns> int AlphaBeta(int alpha, int beta, int ply, int depth, List<Move> pv, NullMove nullmove, ref int nodeCount) { //if time out or exit requested after 1st iteration,so leave thinking. if ((!HaveTime() || Exit) && iterationPly > 1) return 0; nodeCount++; var moves = Board.GenerateMoves(); if (moves.Count == 0) return -Board.IsCheckMateOrStaleMate(ply); if (ply <= 0) return QuiescenceSearch(alpha, beta, ref nodeCount); var localpv = new List<Move>(); var pvSearch = false; #region Null Move Prunning if (nullmove == NullMove.Enabled && !Board.IsInCheck()) { int R = 2; Board.ToggleSide(); int score = -AlphaBeta(-beta, -beta + 1, ply - 1 - R, depth + 1, localpv, NullMove.Disabled, ref nodeCount); Board.ToggleSide(); if (score >= beta) return score; } #endregion var sortedMoves = SortMoves(moves, depth); foreach (var move in sortedMoves) { Board.MakeMove(move); int score; if (Board.threeFoldRepetetion.IsThreeFoldRepetetion) score = Board.Draw; else { #region Late Move Reduction if (!Board.IsInCheck()) { score = -AlphaBeta(-alpha - 1, -alpha, ply - 2, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } else score = alpha + 1; #endregion if (score > alpha) { if (pvSearch) { score = -AlphaBeta(-alpha - 1, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); if (score > alpha && score < beta) { score = -AlphaBeta(-beta, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } } else { score = -AlphaBeta(-beta, -alpha, ply - 1, depth + 1, localpv, NullMove.Enabled, ref nodeCount); } } } Board.TakeBackMove(move); if (score >= beta) { killerMoves.Add(move, depth); return beta;//beta cut-off } if (score > alpha) { historyMoves.AddMove(move); pvSearch = true; alpha = score; #region Collect principal variation pv.Clear(); pv.Add(move); pv.AddRange(localpv); #endregion } } return alpha; }
/// <summary> /// Recursively carries out a full width alpha beta search untill the bottom is reached. /// From then a Quiescent search is carried out to avoid horrison effects. /// </summary> /// <param name="alpha">This is the best score that can be forced by some means. Anything worth less than this is of no use, because there is a strategy that is known to result in a score of alpha.</param> /// <param name="beta">Beta is the worst thing that the opponent has to endure. If the search finds something that returns a score of beta or better, it's too good, so the side to move is not going to get a chance to use this strategy.</param> /// <param name="remainingDepth">Remaining depth to search before bottom is reached.</param> /// <param name="allowNullMove">Is a null move allowed at this search depth.</param> /// <param name="allowTranspotitionTable">Is it allowed to use the transpotition table to probe for scores.</param> /// <returns>The score of a board.</returns> private int AlphaBetaSearch(int alpha, int beta, int remainingDepth, bool allowNullMove, bool allowTranspotitionTable) { if (m_searchRollback) { return(beta); } //At interval check if time is up and rollback if so. if (m_nodesVisited == m_nextRollbackCheck) { if (AbortingSearch()) { m_alphaBetaTable.Close(); m_quiescentTable.Close(); m_searchRollback = true; return(beta); } m_nextRollbackCheck += ROLLBACK_INTERVAL_COUNT; } ++m_nodesVisited; int score = 0; Move pvMove = null; AlphaBetaFlag alphaBetaFlag = AlphaBetaFlag.AlphaScore; if (m_board.State.NonHitAndPawnMovesPlayed >= 100) { return(0); } if (m_board.BoardHistoryFrequency() >= 3) { return(0); } //don't allow transposition table before both players has passed the above repetetion draw checks. if (allowTranspotitionTable && (m_searchDepth - remainingDepth) > 0) { if (m_alphaBetaTable.ProbeScore(m_board.BoardHash(false), alpha, beta, remainingDepth, ref score)) { if (Math.Abs(score) != Math.Abs(m_evaluator.MateValue)) //don't probe a mate value as this actuall might be a mate far down in the tree, and we want to find the mate at lowest depth. { return(score); } } } if (remainingDepth == 0) { score = QuiescentSearch(alpha, beta); if (allowTranspotitionTable) { m_alphaBetaTable.RecordHash(m_board.BoardHash(false), AlphaBetaFlag.ExactScore, remainingDepth, score, pvMove); } return(score); } if (allowNullMove) { //Carry out a null move which is a move where nothing is actually moved. This makes the opponent move //twice in a row. The idea is then to search to a reduced depth and if nothing good come out of this //(for the opponent) the move is considered garbage and we cut it off. NullMove nullMove = new NullMove(m_board, m_evaluator); if (nullMove.Execute()) { int remDepth = (remainingDepth > NULL_REDUCTION) ? remainingDepth - 1 - NULL_REDUCTION : 0; score = -AlphaBetaSearch(-beta, -beta + 1, remDepth, false, false); nullMove.UnExecute(); if (score >= beta) { return(beta); } } } MoveOrganizer currentMoves = new MoveOrganizer(m_alphaBetaTable.ProbePvMove(m_board.BoardHash(false))); m_board.GeneratePseudoLegalMoves(currentMoves); currentMoves.Sort(m_captureMoveCompare); bool validMoveFound = false; foreach (Move move in currentMoves) { if (move.Execute(m_board)) { validMoveFound = true; if (pvMove == null) { score = -AlphaBetaSearch(-beta, -alpha, remainingDepth - 1, true, allowTranspotitionTable); } else { score = -AlphaBetaSearch(-alpha - 1, -alpha, remainingDepth - 1, true, false); if ((score > alpha) && (score < beta)) { score = -AlphaBetaSearch(-beta, -alpha, remainingDepth - 1, true, allowTranspotitionTable); } } move.UnExecute(m_board); if (score >= beta) { if (allowTranspotitionTable) { m_alphaBetaTable.RecordHash(m_board.BoardHash(false), AlphaBetaFlag.BetaScore, remainingDepth, beta, pvMove); } return(beta); } if (score > alpha) { alpha = score; pvMove = move; alphaBetaFlag = AlphaBetaFlag.ExactScore; } } } if (!validMoveFound) { if (m_board.ColorToPlayIsCheck()) { alpha = m_evaluator.MateValue; //Checkmate } else { alpha = 0; //Stalemate } } if (allowTranspotitionTable) { m_alphaBetaTable.RecordHash(m_board.BoardHash(false), alphaBetaFlag, remainingDepth, alpha, pvMove); } return(alpha); }