/// <summary> /// Checks to see if a square is next to a corner /// </summary> /// <param name="square"></param> /// <param name="board"></param> /// <returns></returns> public bool IsNextToCorner(SimpleSquare square, SimpleBoard board) { int sizeX = board.OccupationArray.GetLength(0); int sizeY = board.OccupationArray.GetLength(1); int posX = square.Column; int posY = square.Row; if (posX == 0 && posY == 1) { return(true); } if (posX == 1 && posY == 0) { return(true); } if (posX == 0 && posY == sizeY - 2) { return(true); } if (posX == 1 && posY == sizeY - 1) { return(true); } if (posX == sizeX - 2 && posY == 0) { return(true); } if (posX == sizeX - 1 && posY == 1) { return(true); } if (posX == sizeX - 2 && posY == sizeY - 1) { return(true); } if (posX == sizeX - 1 && posY == sizeY - 2) { return(true); } return(false); }
public List <Move> Evaluate(List <List <Move> > inputMoveList, TurnState currentTurnState) { moveList = inputMoveList; List <Move> suggestedMoves = new List <Move>(); if (currentTurnState == TurnState.Defender) { SimpleSquare evalSquare = new SimpleSquare(); bool foundWin = false; //Evaluate the if the King's path to the thrones is clear. If so one of the moves will have the King on the throne. moveList[0].ForEach((item) => { evalSquare = item.GetSquare(item.endRow, item.endColumn); if (evalSquare.SquareType == Square.square_type.Corner) { item.scoreKingsCouncil = desireToWin; suggestedMoves.Add(item); foundWin = true; } }); if (foundWin) { return(suggestedMoves); } int numMovesForKing = 0; List <Move> tempMoveList = new List <Move>(); List <Move> kingsMoveList = new List <Move>(); List <Move> winningKingMoveList = new List <Move>(); SimpleSquare kingSquare = new SimpleSquare(); int numberDepth2Wins = 0; int sizeX = moveList[0][0].board.OccupationArray.GetLength(0) - 1; int sizeY = moveList[0][0].board.OccupationArray.GetLength(1) - 1; //Look at all depth 2 moves (generated from move[0]'s) to see if any of these are wins. Don't just iterate over all depth[2] as this would //include depth [1] moves by attacker moving out of the way... //Also Award moves that have the King more free to move moveList[0].ForEach((item) => { try { //Find the King kingSquare = item.FindTheKing(item.board, true); tempMoveList = item.board.GetPossibleMoves(TurnState.Defender, null, 0); //filter the list based on moves of the king kingsMoveList = tempMoveList.Where(move => move.startRow == kingSquare.Row && move.startColumn == kingSquare.Column).ToList(); numMovesForKing = kingsMoveList.Count; //Give a bonus for the king being freed up item.scoreKingsCouncil += (double)numMovesForKing * desireForFreeKing; winningKingMoveList = kingsMoveList.Where(mov => (mov.endColumn == 0 && mov.endRow == 0) || (mov.endColumn == 0 && mov.endRow == sizeY) || (mov.endColumn == sizeX && mov.endRow == 0) || (mov.endColumn == sizeX && mov.endRow == sizeY)).ToList(); if (winningKingMoveList.Count > 0) { numberDepth2Wins++; item.scoreKingsCouncil += desrieToWinDepth2; } } catch (Exception ex) { numberDepth2Wins += 0; } }); //if number of depth 2 wins is zero allow more full analyis if (numberDepth2Wins == 0) { moveList[2].ForEach(item => { kingSquare = item.FindTheKing(item.board, true); Piece king = new Piece(kingSquare.Column, kingSquare.Row, Piece.PieceType.King); kingsMoveList = item.board.GetMovesForPiece(king, item, 3); kingsMoveList = kingsMoveList.Where(mov => (mov.endColumn == 0 && mov.endRow == 0) || (mov.endColumn == 0 && mov.endRow == sizeY) || (mov.endColumn == sizeX && mov.endRow == 0) || (mov.endColumn == sizeX && mov.endRow == sizeY) ).ToList(); if (kingsMoveList.Count > 0) { item.parent.parent.scoreKingsCouncil += desireForKingToBeClearToCorner / (double)moveList[1].Count; } }); } //return the best suggestedMoves.Add(moveList[0].MaxObject((item) => item.scoreKingsCouncil)); } else { return(suggestedMoves); //will be empty. } return(suggestedMoves); }
public List <Move> Evaluate(List <List <Move> > inputMoveList, TurnState currentTurnState) { List <Move> suggestedMoves = new List <Move>(); //Look to have the outer pieces on the maximum number of rows DateTime start = DateTime.Now; DateTime start2 = DateTime.Now; TimeSpan duration = new TimeSpan(); double runTime = 0.0d; double runTime2 = 0.0d; SimpleSquare kingSquare = new SimpleSquare(); List <Move> kingsMoveList = new List <Move>(); int sizeX = inputMoveList[0][0].board.OccupationArray.GetLength(0); int sizeY = inputMoveList[0][0].board.OccupationArray.GetLength(1); int numberMovesDepth0 = 0; int numberOfLosesDepth1 = 0; bool foundwin = false; inputMoveList[0].ForEach(item => { if (item.CheckForAttackerVictory()) { item.scoreAssassin = desireForWinDepth0; numberMovesDepth0++; foundwin = true; } }); //check to see if a move blocks a depth 1 loss if (!foundwin) { inputMoveList[1].ForEach(item => { //If a loss is possible all moves in which the loss can happen should be penalised. SimpleSquare kingSquareWin = item.FindTheKing(item.board, true); if (kingSquareWin.SquareType == Square.square_type.Corner) { numberOfLosesDepth1++; item.parent.scoreAssassin -= desireNotToLoseDepth1; } //if the king can get to a square next to a corner it is also a definte loss effectively at depth 3 //so penalise at depth 1 if (IsNextToCorner(kingSquareWin, item.board)) { numberOfLosesDepth1++; item.parent.scoreAssassin -= desireNotToLoseDepth1; } }); runTime = (DateTime.Now - start).TotalSeconds; start2 = DateTime.Now; //Check to see if can win, but not if can lose on next defender move bool worthLookingDeep = false; if (numberOfLosesDepth1 < 1) { //Check if king is at least surrounded by 2 attackers - if so look for a 2 move combo that might win inputMoveList[0].ForEach(item => { if (item.NumberOfAttackersAroundKing() >= 2) { worthLookingDeep = true; } }); if (worthLookingDeep) { Parallel.ForEach(inputMoveList[2], item => { if (item.CheckForAttackerVictory()) { item.parent.parent.scoreAssassin += desireForWinDepth2 / (double)inputMoveList[1].Count; } }); } } runTime2 = (DateTime.Now - start2).TotalSeconds; runTime = (DateTime.Now - start).TotalSeconds; //look for moves of the king at depth 3 //Look for routes for the king at depth 3 to get to corner sizeX = inputMoveList[0][0].board.OccupationArray.GetLength(0) - 1; sizeY = inputMoveList[0][0].board.OccupationArray.GetLength(1) - 1; Object _lock = new Object(); if (numberOfLosesDepth1 < 1) { inputMoveList[1].ForEach(item => //This could be moveList[2] but would be slow. This only evolves from the defenders last move (i.e. skips the attackers move) { kingSquare = item.FindTheKing(item.board, true); Piece king = new Piece(kingSquare.Column, kingSquare.Row, Piece.PieceType.King); kingsMoveList = item.board.GetMovesForPiece(king, item, 3); // This is very expensive kingsMoveList = kingsMoveList.Where(mov => (mov.endColumn == 0 && mov.endRow == 0) || (mov.endColumn == 0 && mov.endRow == sizeY) || (mov.endColumn == sizeX && mov.endRow == 0) || (mov.endColumn == sizeX && mov.endRow == sizeY) ).ToList(); if (kingsMoveList.Count > 0) { item.parent.scoreAssassin -= desireNotToLoseDepth3 / (double)inputMoveList[1].Count; } }); } } runTime = (DateTime.Now - start).TotalSeconds; suggestedMoves.Add(inputMoveList[0].MaxObject(item => item.scoreAssassin)); return(suggestedMoves); }