我正在用AI做一个tic tac toe游戏。人工智能很好,除非它必须以垂直方式获胜。所有其他方式(水平和对角线)确实有效。
我已经做了很多调试,一步一步,没有找到解决方案。我以为你们可以帮助我找到问题,帮助我解决问题!
int findTwoPions(Boolean?[,] jeu)
{
// La méthode qui selon moi est à modifier car c'est celle ci qui décide la position que doit prendre l'IA quand elle peu gagner
int somme = 0;
int compteurX = 0;
int compteur0 = 0;
//Diagonale descendante
for (int i = 0; i < 3; i++)
{
if ((jeu[0, 0] == false || jeu[1, 1] == false || jeu[2, 2] == false) && (jeu[0, 0] == true || jeu[1, 1] == true || jeu[2, 2] == true))
{
somme += 0;
}
else
{
if (jeu[i, i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, i] == true)
{
compteur0 = 0;
compteurX++;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
compteurX = 0;
compteur0 = 0;
//Diagonale montante
for (int i = 0; i < 3; i++)
{
if ((jeu[0, 2] == false || jeu[1, 1] == false || jeu[2, 0] == false) && (jeu[0, 2] == true || jeu[1, 1] == true || jeu[2, 0] == true))
{
}
else
{
if (jeu[i, 2 - i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, 2 - i] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
//En ligne
for (int i = 0; i < 3; i++)
{
compteurX = 0;
compteur0 = 0;
if ((jeu[0, i] == false || jeu[1, i] == false || jeu[2, i] == false) && (jeu[0, i] == true || jeu[1, i] == true || jeu[2, i] == true))
{
somme += 0;
}
else
{
//Verticale
for (int j = 0; j < 3; j++)
{
if (jeu[j, i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[j, i] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
compteurX = 0;
compteur0 = 0;
if ((jeu[i, 0] == false || jeu[i, 1] == false || jeu[i, 2] == false) && (jeu[i, 0] == true || jeu[i, 1] == true || jeu[i, 2] == true))
{
return somme += 0;
} // Voir les valeurs i j pcque c'est faux
else
{
//Horizontale
for (int j = 0; j < 3; j++)
{
if (jeu[i, j] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, j] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
}
return somme;
}
}
}
我认为问题是当我为'somme'添加一个值或者通过我的tic tac toe运行的方式。如果您需要进一步的代码请告诉我,谢谢!
更新:
我的AIRoutine.cs
public Boolean?[][] IAPlay(Boolean?[][] jeu, int profondeur)
{
int max = -10000;
int tmp, tmp2 = 0, tmpSomme = -10000; // -10000
int tmpBefore = 0;
int maxi = 0, maxj = 0;
int somme = 0;
int biggestSomme = 0;
setTab(jeu); // convertit le tableau[][] en tableau[,]
for (int i = 0; i < 3; i++) // parcours toutes les cases vides du tableau
{
for (int j = 0; j < 3; j++)
{
//Si une case est vide, on joue le coup de l'IA sur cette case et on simule le jeu complet
if (tab[i, j] == null)
{
tab[i, j] = false; // On simule le coup de l'IA
somme = findTwoPions(tab);
tmp = Max(tab, profondeur - 1);
if (tmpBefore < tmp && biggestSomme > somme)
{
tmpSomme = somme + tmpBefore;
}
else if (tmpBefore > tmp && biggestSomme < somme)
{
tmpSomme = somme + tmpBefore;
}
else
{
tmpSomme = tmp + somme;
}
if (somme > biggestSomme)
{
biggestSomme = somme;
tmpBefore = tmp;
}
//|| ((tmp == max) && (r.Next(1, 100) % 2 == 0))
if (tmpSomme >= max)
{
max = tmpSomme;
tmp2 = somme;
maxi = i;
maxj = j;
}
tab[i, j] = null;
}
}
}
tab[maxi, maxj] = false;
return getTab(jeu);
}
让我们用可读和维护的方式:让我们提取一个方法WinningLines
,我们枚举所有获胜组合(我已经假设jue
是2d数组 - bool?[3, 3]
):
using System.Linq;
...
private static IEnumerable<bool?[]> WinningLines(bool?[,] field) {
// Verticals
for (int column = 0; column < 3; ++column)
yield return new bool?[] {field[0, column], field[1, column], field[2, column]};
// Horizontals
for (int row = 0; row < 3; ++row)
yield return new bool?[] {field[row, 0], field[row, 1], field[row, 2]};
// Diagonals
yield return new bool?[] {field[0, 0], field[1, 1], field[2, 2]};
yield return new bool?[] {field[0, 2], field[1, 1], field[2, 0]};
}
现在让我们查询(在Linq的帮助下):
// Do we have any winning combinations for the 1st Player (all 3 true in WinningLines):
bool hasFirstWon = WinningLines(jeu).Any(line => line.All(cell => cell == true));
// Do we have any winning combinations for the 2nd Player (all 3 false in WinningLines):
bool hasSecondWon = WinningLines(jeu).Any(line => line.All(cell => cell == false));
或者如果你使用somme
:
int somme =
WinningLines(jeu).Any(line => line.All(cell => cell == true)) ?
1500 // 1st wins
: WinningLines(jeu).Any(line => line.All(cell => cell == false)) ?
-1600 // 2nd wins
: 0; // no-one wins
编辑:现在让我们实现int findTwoPions(Boolean?[,] jeu)
方法的(简单)版本。首先让我们拥有
private static bool FirstIsOnMove(bool?[,] field) {
int count = 0;
foreach (var item in field)
if (item == true)
count += 1;
else if (item == true)
count -= 1;
return count == 0;
}
而方法本身就是
// This method rates the position in a [-1600..1500] range
// [1st player has lost..1st player has won]
int findTwoPions(Boolean?[,] jeu) {
// Edge cases: win or lose
if (WinningLines(jeu).Any(line => line.All(cell => cell == true)))
return 1500; // 1st has won
else if (WinningLines(jeu).Any(line => line.All(cell => cell == false)))
return -1600; // 1st has lost
//TODO: add more heuristics (depending who is on move)
// Example: if palayer is on move and can win by its next move?
// Say, we have positions like
// X.. XXO
// OX. Or X.O
// .O. ...
if (FirstIsOnMove(jeu)) {
if (WinningLines(jeu)
.Any(line => line.Sum(item => item == true ? 1 : item == false ? -1 : 0) == 2))
return 1200; // 1st is going to win (unless it makes a blind)
}
else {
if (WinningLines(jeu)
.Any(line => line.Sum(item => item == true ? 1 : item == false ? -1 : 0) == -2))
return -1200; // 2st is going to win (unless it makes a blind)
}
// Neutral position - neither 1st not 2nd have any advantages
return 0;
}