我尝试用不同的棋盘大小和棋子来制作井字游戏。
我有评估功能,它取决于开放路径。例如,如果我们有
O--X O--- --O
我们得到10 ^ 2(对于垂直第一列)+ 10 ^ 1(垂直第二列)+ 10 ^ 1(对角线)+ 10 ^ 1(对于水平第二行)+ 10 ^ 1(对于最后一个水平行) )。
为了获得最好的动作,我使用了函数:
public Move FindBestMove(Board board, int depth, Game.Player currentTurn, Board.Piece currentPiece, Move move1 = null)
{
if (depth <= 0 || board.AreEmptyPlaces() == false)
{
move1.Score = board.Score;
if (_log)
{
Console.WriteLine("\n" + new String('\t', 4 - depth) +
string.Format("bestScore = {0}, player = {1}, status = {2}", board.Score,
currentTurn, move1.EvaluateResult + "\n"));
}
return move1;
}
List<Move> allMoves = board.GetAllMoves(currentPiece);
Move bestMove = null;
foreach (Move move in allMoves)
{
Board newBoard = (Board)board.Clone();
newBoard.MakeMove(move);
Board newBoardForOpponent = (Board)board.Clone();
Move moveForOppeonent = new Move { Piece = move.Piece == Board.Piece.O ? Board.Piece.X : Board.Piece.O, Position = move.Position, Score = move.Score };
newBoardForOpponent.MakeMove(moveForOppeonent);
IEvaluate evaluateOpenPathForOpponent = new EvaluateOpenPath(newBoardForOpponent.BoardSize, newBoardForOpponent.pieces, currentPiece == Board.Piece.O ? Board.Piece.X : Board.Piece.O, newBoardForOpponent.ToWin);
IEvaluate evaluateOpenPath = new EvaluateOpenPath(newBoard.BoardSize, newBoard.pieces, currentPiece, newBoard.ToWin);
EvaluateResult opponentResult = evaluateOpenPathForOpponent.EvaluateOpponent();
EvaluateResult playerResult = evaluateOpenPath.Evaluate();
if (currentTurn == Game.Player.Computer)
{
newBoard.Score += (playerResult.Score) + (opponentResult.Status == EvaluateResult.EvaluateStatus.Won ? opponentResult.Score : 0);
}
else
{
newBoard.Score += (playerResult.Score) + (opponentResult.Status == EvaluateResult.EvaluateStatus.Lost ? opponentResult.Score : 0);
}
if (currentTurn == Game.Player.Computer && (_initialDepth == depth || _initialDepth - 1 == depth) &&
//(playerResult.Score == 0 && opponentResult.Score == 0) &&
(opponentResult.Status == EvaluateResult.EvaluateStatus.Lost ||
playerResult.Status == EvaluateResult.EvaluateStatus.Won))
{
//bestMove = BestMoveChagneStatus(bestMove, move, playerResult, opponentResult);
bestMove = BestMoveChagneStatus(bestMove, move, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.LostOrWon;
break;
}
if (_log)
{
Console.WriteLine(
new String('\t', 4 - depth) +
"gracz = {1}, pozycja = {2},wynik = {0}, glebokosc = {3}, status = {4}, (bestmove = {5})",
newBoard.Score, move.Piece, move.Position, depth, move.EvaluateResult, bestMove);
}
Move findBestMove = FindBestMove(newBoard, depth - 1, (currentTurn == Game.Player.Computer ? Game.Player.Human : Game.Player.Computer), (currentPiece == Board.Piece.O ? Board.Piece.X : Board.Piece.O), move);
if (findBestMove != null)
{
if (bestMove == null)
{
bestMove = findBestMove;
}
else
{
if (currentTurn == Game.Player.Computer &&
//(playerResult.Score == 0 && opponentResult.Score == 0) &&
(opponentResult.Status == EvaluateResult.EvaluateStatus.Lost ||
playerResult.Status == EvaluateResult.EvaluateStatus.Won))
{
//bestMove = BestMoveChagneStatus(bestMove, move, playerResult, opponentResult);
bestMove = BestMoveChagneStatus(bestMove, move, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.LostOrWon;
break;
}
if (bestMove.EvaluateResult == EvaluateResult.EvaluateStatus.None && findBestMove.EvaluateResult != EvaluateResult.EvaluateStatus.None)
{
bestMove = BestMoveChagneStatus(bestMove, findBestMove, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.Status;
}
else if (bestMove.EvaluateResult == EvaluateResult.EvaluateStatus.Lost &&
findBestMove.EvaluateResult == EvaluateResult.EvaluateStatus.Won)
{
bestMove = BestMoveChagneStatus(bestMove, findBestMove, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.Status;
}
else if (findBestMove.Score > bestMove.Score && findBestMove.EvaluateResult == EvaluateResult.EvaluateStatus.Won)
{
bestMove = BestMoveChagneStatus(bestMove, findBestMove, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.Score;
}
else if (findBestMove.Score == bestMove.Score && Random.NextDouble() > 0.00 && findBestMove.EvaluateResult == EvaluateResult.EvaluateStatus.Won)
{
bestMove = BestMoveChagneStatus(bestMove, findBestMove, playerResult, opponentResult);
bestMove.Source = Move.SourceEnum.Score;
}
}
}
}
return bestMove;
}
private static Move BestMoveChagneStatus(Move bestMove, Move move, EvaluateResult playerResult,
EvaluateResult opponentResult)
{
bestMove = move;
if (playerResult.Status != EvaluateResult.EvaluateStatus.None)
{
bestMove.EvaluateResult = playerResult.Status;
}
else if (opponentResult.Status != EvaluateResult.EvaluateStatus.None)
{
bestMove.EvaluateResult = opponentResult.Status;
}
else
{
bestMove.EvaluateResult = EvaluateResult.EvaluateStatus.None;
}
return bestMove;
}
程序找到移动,但并不总是最好的。特别是当对手有2次获胜机会时,他不会看到动作。而且当算法获胜时,他首先会阻挡对手。例如:
XO- XO- ---
如果计算机是O,他将首先阻止X,但不应该阻止。
请告诉我这项功能有哪些改进?也许有一些我没看到的错误:(评价函数工作正常我写单元测试进行测试。