8年前关闭。
我正在使用 C#.NET 构建一个战舰游戏。它应该使用相当简单的评分机制。没有沉船,如果玩家或计算机得分 17,则他们获胜。如果你击中了,你可以再转一圈。 AI 随机攻击直到命中,此时它会向每个方向攻击一块瓷砖,直到找到趋势,然后继续直线攻击,直到找到死胡同(未被占用的空间或边缘的边缘)如果在计算机攻击的相反方向上有没有被击中的空间,它就会攻击这些空间。它不会瞄准它已经击中的空间或遵循已经遵循的模式。
到目前为止,这是我的 AI。
int shipCounter = 0, trend = 0;
static Random rnd = new Random();
bool gameOver = false, playerTurn = false;
int[] score = { 0, 0 };
struct gameData
{
public bool occupied, hit, marked;
}
gameData[,,] data;
public void computerMove()
{
Point target = seekTarget();
try
{
if (data[1, target.X, target.Y].hit)
computerMove();
else
{
data[1, target.X, target.Y].hit = true;
if (data[1, target.X, target.Y].occupied)
{
attacking = true;
score[0]++;
computerMove();
}
}
playerTurn = true;
}
catch (IndexOutOfRangeException)
{ computerMove(); }
}
public Point seekTarget()
{
Point origin = new Point(-1, -1);
//find a point that's been hit.
int x = 0, y = 0;
while (x < gridSize && y < gridSize)
{
if (data[1, x, y].hit && data[1, x, y].occupied && !data[1, x, y].marked)
{
origin = new Point(x, y);
break;
}
x++;
if (x == gridSize && y != gridSize)
{
x = 0;
y++;
}
}
return findTargets(origin);
}
public Point findTargets(Point origin)
{
Point[] lim = { origin, origin, origin, origin };
Point[] possibleTargets = { origin, origin, origin, origin };
//Find the edges.
while (lim[0].X >= -1 && ((!data[1, lim[0].X, lim[0].Y].hit && !data[1, lim[0].X, lim[0].Y].occupied) || (data[1, lim[0].X, lim[0].Y].hit && data[1, lim[0].X, lim[0].Y].occupied)))
{
lim[0].X--;
if (lim[0].X == -1)
break;
}
while (lim[1].Y >= -1 && ((!data[1, lim[0].X, lim[0].Y].hit && !data[1, lim[0].X, lim[0].Y].occupied) || (data[1, lim[0].X, lim[0].Y].hit && data[1, lim[0].X, lim[0].Y].occupied)))
{
lim[1].Y--;
if (lim[1].Y == -1)
break;
}
while (lim[2].X <= gridSize && ((!data[1, lim[0].X, lim[0].Y].hit && !data[1, lim[0].X, lim[0].Y].occupied) || (data[1, lim[0].X, lim[0].Y].hit && data[1, lim[0].X, lim[0].Y].occupied)))
{
lim[2].X++;
if (lim[2].X == gridSize)
break;
}
while (lim[3].Y <= gridSize && ((!data[1, lim[0].X, lim[0].Y].hit && !data[1, lim[0].X, lim[0].Y].occupied) || (data[1, lim[0].X, lim[0].Y].hit && data[1, lim[0].X, lim[0].Y].occupied)))
{
lim[3].Y++;
if (lim[3].Y == gridSize)
break;
}
//Cell targeting AI
}
return new Point(rnd.Next(10), rnd.Next(10));
}
由于我无法弄清楚出了什么问题,它变得非常困惑。如果我引用
findTargets
函数并让计算机随机攻击,它工作正常。计算机和玩家交易轮流,计算机点击注册。但是,启用
findTargets
后,玩家可以进行一次攻击,而计算机永远不会轮到它。然后它不会恢复到玩家回合,即使玩家的攻击十字准线仍然可见。如果有人可以提供帮助,将不胜感激。抱歉没有包含 Paint
或 mouseDown
方法,它们超出了字符限制。没有
findTargets
的 UI(玩家和电脑交易轮流)。带有
findTargets
的 UI(计算机不能轮流,玩家只能轮流)。在此先感谢您的帮助。
编辑: 我已经隔离了这个问题,它似乎无法摆脱
findTargets
中的 while 循环。即使我通过在 origin
为 (-1, -1)
时阻止它循环来解决问题,它也会在第一次点击时陷入循环。编辑 2: 它正在击中第一个循环,并无限循环。出于某种原因,它根本没有增加
lim[0].X
。当我在循环中插入一个消息框以显示一些数据时,它显示两次,然后不再出现,即使它仍在循环中。有人知道为什么吗? 最佳答案
您正在使用面向对象的语言 - 在我看来就像 Java。
因此,为了更容易编码、更容易理解、更容易维护、更容易增强您的代码,请尝试使用一些实际对象。
例如,您绝对应该有一个 Ship 类,绝对应该有一个 Grid 类,可能是一个 Shot 类,等等。您的 Ship 类绝对应该“插入”到您的 Grid 类中。您的 Grid 类不应分配潜在位置的整个网格,而应仅分配有效的 Hit 区域,因为 Ship 实例已插入其中。每个没有 Ship 实例居住的位置显然都是一个未命中,所以用一个方法处理所有不包含船的位置 -
Grid 类将完成所有工作——它可以有一个 addShipHorizontal(Ship, x, y) 和一个 addShipVertical(Ship, x, y)。它肯定应该有一个返回 null 或 Ship 的 hitTest(x, y)。它应该维护一个 Ship 实例的集合,比如 ArrayList,它将在 hitTest(x, y) 方法中迭代。
Ship 应该有一个 PointCount 和一个 Points 集合,当船被传递到 addShipH() 或 addShipV() 方法时,它们会被设置。 Ship 还应该有一个 hitTest(x, y) 方法,如果船居住在指定的 x, y 上,该方法将返回 true。 hitTest(x, y) 将遍历船舶的 Points 集合以寻找匹配项。
当需要拍摄时,在网格上选择您的位置并对其进行 HitTest - 所选位置是否包含 Ship 引用,是的,然后执行 ship.hit(location) 并返回一个新的 Hit() - 否则返回一个新小姐();
将其分解为您实际考虑模拟的对象 - 这称为域模型。然后为每个对象类提供适当的方法,以便实际游戏只是域模型类之间的编排。
不要编写游戏代码——相反,先编写类,然后编写类的方法——当你构建类时,游戏将通过类之间的方法通过它们的交互产生。
从顶部开始,您需要应用程序顶部的哪个类的 2 个实例?答案 - 玩家。 Player 类管理什么?一个网格和一个船舶列表。网格管理什么?船舶及其位置的列表,以及射击的 HitTest 。 Ship 维护什么?它在网格上的位置以及它所在的哪些位置已经/没有被击中。
你会发现如果你用 OO 风格来做,它将是代码的 1/4,并且具有两倍的灵活性。祝你好运!
关于c# - 战舰AI——彻底迷失,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16659061/