gpt4 book ai didi

c# - 在四排 (connect4) 游戏中实现和使用 MinMax

转载 作者:太空宇宙 更新时间:2023-11-03 23:17:24 25 4
gpt4 key购买 nike

我正在尝试为四连胜(或 connect4 或 connect four)游戏实现 MinMax 算法。

我想我明白了,它应该构建一棵达到一定深度的可能棋盘树,评估它们并返回它们的分数,然后我们只取这些分数的最大值。

因此,aiChooseCol() 通过调用 MinMax() 检查每个可能列的得分,并返回得分最高的列。

现在我不确定,这是调用 MinMax() 的正确方法吗?

检查 temp = Math.Max(temp, 1000); 是否正确?

我还没有制作启发式函数,但这至少应该识别一个获胜列并选择它,但目前它只是选择左边的第一个空闲列......我不知道我在做什么错了。

private int AiChooseCol()
{
int best = -1000;
int col=0;
for (int i = 0; i < m_Board.Cols; i++)
{
if (m_Board.CheckIfColHasRoom(i))
{
m_Board.FillSignInBoardAccordingToCol(i, m_Sign);
int t = MinMax(5, m_Board, board.GetOtherPlayerSign(m_Sign));
if (t > best)
{
best = t;
col = i;
}
m_Board.RemoveTopCoinFromCol(i);
}

}
return col;
}


private int MinMax(int Depth, board Board, char PlayerSign)
{
int temp=0;
if (Depth <= 0)
{
// return from heurisitic function
return temp;
}
char otherPlayerSign = board.GetOtherPlayerSign(PlayerSign);

char checkBoard = Board.CheckBoardForWin();
if (checkBoard == PlayerSign)
{
return 1000;
}
else if (checkBoard == otherPlayerSign)
{
return -1000;
}
else if (!Board.CheckIfBoardIsNotFull())
{
return 0; // tie
}


if (PlayerSign == m_Sign) // maximizing Player is myself
{
temp = -1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Max(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
else
{
temp = 1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Min(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
return temp;
}

一些注意事项:

FillSignInBoardAccordingToCol() 如果成功则返回一个 bool 值。

board 类型有一个 char[,] 数组,其中包含实际的棋盘和玩家的标志。

此代码在 AI Player 类中。

最佳答案

所以我决定编写自己的 MinMax Connect 4。我使用深度来确定输赢的值(value),以便让您更接近获胜或阻止损失的移动将优先。我还决定,如果不止一个具有相同的启发式,我将随机选择移动。最后,我将深度扩展到 6,因为这是从一开始就找到可能的获胜路径所需的步数。

private static void Main(string[] args)
{
var board = new Board(8,7);
var random = new Random();

while (true)
{
Console.WriteLine("Pick a column 1 -8");
int move;
if (!int.TryParse(Console.ReadLine(), out move) || move < 1 || move > 8)
{
Console.WriteLine("Must enter a number 1-8.");
continue;
}

if (!board.DropCoin(1, move-1))
{
Console.WriteLine("That column is full, pick another one");
continue;
}

if (board.Winner == 1)
{
Console.WriteLine(board);
Console.WriteLine("You win!");
break;
}

if (board.IsFull)
{
Console.WriteLine(board);
Console.WriteLine("Tie!");
break;
}

var moves = new List<Tuple<int, int>>();
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(2, i))
continue;
moves.Add(Tuple.Create(i, MinMax(6, board, false)));
board.RemoveTopCoin(i);
}

int maxMoveScore = moves.Max(t => t.Item2);
var bestMoves = moves.Where(t => t.Item2 == maxMoveScore).ToList();
board.DropCoin(2, bestMoves[random.Next(0,bestMoves.Count)].Item1);
Console.WriteLine(board);

if (board.Winner == 2)
{
Console.WriteLine("You lost!");
break;
}

if (board.IsFull)
{
Console.WriteLine("Tie!");
break;
}
}

Console.WriteLine("DONE");
Console.ReadKey();
}

private static int MinMax(int depth, Board board, bool maximizingPlayer)
{
if (depth <= 0)
return 0;

var winner = board.Winner;
if (winner == 2)
return depth;
if (winner == 1)
return -depth;
if (board.IsFull)
return 0;


int bestValue = maximizingPlayer ? -1 : 1;
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(maximizingPlayer ? 2 : 1, i))
continue;
int v = MinMax(depth - 1, board, !maximizingPlayer);
bestValue = maximizingPlayer ? Math.Max(bestValue, v) : Math.Min(bestValue, v);
board.RemoveTopCoin(i);
}

return bestValue;
}

public class Board
{
private readonly int?[,] _board;

private int? _winner;

private bool _changed;

public Board(int cols, int rows)
{
Columns = cols;
Rows = rows;
_board = new int?[cols, rows];
}

public int Columns { get; }
public int Rows { get; }

public bool ColumnFree(int column)
{
return !_board[column, 0].HasValue;
}

public bool DropCoin(int playerId, int column)
{
int row = 0;
while (row < Rows && !_board[column,row].HasValue)
{
row++;
}

if (row == 0)
return false;
_board[column, row - 1] = playerId;
_changed = true;
return true;
}

public bool RemoveTopCoin(int column)
{
int row = 0;
while (row < Rows && !_board[column, row].HasValue)
{
row++;
}

if (row == Rows)
return false;
_board[column, row] = null;
_changed = true;
return true;
}

public int? Winner
{
get
{
if (!_changed)
return _winner;

_changed = false;
for (int i = 0; i < Columns; i++)
{
for (int j = 0; j < Rows; j++)
{
if (!_board[i, j].HasValue)
continue;

bool horizontal = i + 3 < Columns;
bool vertical = j + 3 < Rows;

if (!horizontal && !vertical)
continue;

bool forwardDiagonal = horizontal && vertical;
bool backwardDiagonal = vertical && i - 3 >= 0;

for (int k = 1; k < 4; k++)
{
horizontal = horizontal && _board[i, j] == _board[i + k, j];
vertical = vertical && _board[i, j] == _board[i, j + k];
forwardDiagonal = forwardDiagonal && _board[i, j] == _board[i + k, j + k];
backwardDiagonal = backwardDiagonal && _board[i, j] == _board[i - k, j + k];
if (!horizontal && !vertical && !forwardDiagonal && !backwardDiagonal)
break;
}

if (horizontal || vertical || forwardDiagonal || backwardDiagonal)
{
_winner = _board[i, j];
return _winner;
}
}
}

_winner = null;
return _winner;
}
}

public bool IsFull
{
get
{
for (int i = 0; i < Columns; i++)
{
if (!_board[i, 0].HasValue)
return false;
}

return true;
}
}

public override string ToString()
{
var builder = new StringBuilder();
for (int j = 0; j < Rows; j++)
{
builder.Append('|');
for (int i = 0; i < Columns; i++)
{
builder.Append(_board[i, j].HasValue ? _board[i,j].Value.ToString() : " ").Append('|');
}
builder.AppendLine();
}

return builder.ToString();
}
}

关于c# - 在四排 (connect4) 游戏中实现和使用 MinMax,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36792847/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com