Ste*_*ine 7 c# recursion tic-tac-toe
我可以看到这个问题(或类似的问题)已被问过几次,我已经搜索了很多谷歌,所以我可以试着理解它,但我绝对被卡住了.
我的任务是使用递归函数,使用"goodness"变量来确定哪个是计算机可以做出的最佳移动,我甚至有一个文档可以帮助解决这个问题,但对于我的生活,我只是不喜欢理解它.
如果有人可能需要一些时间来帮助我或分解我真正需要做的事情,我会非常感激,我将链接到目前为止我的代码,但这是一项任务,所以指导比直接答案更可取.我已经看过MinMax解决方案了,这肯定在我的掌握之上,我对编程非常陌生(特别是在C#只有几个月的经验)所以就这么简单!
以下是我想要遵循的建议解决方案:
http://erwnerve.tripod.com/prog/recursion/tictctoe.htm
public partial class Form1 : Form
{
public static string[,] Board = new string[3, 3] { { "1", "2", "3" }, { "4", "5", "6" }, { "7", "8", "9" } };
public bool Winner = false;
public string WinState;
private void Reset()
{
WinState = "";
Winner = false;
Board[0, 0] = "1";
Board[0, 1] = "2";
Board[0, 2] = "3";
Board[1, 0] = "4";
Board[1, 1] = "5";
Board[1, 2] = "6";
Board[2, 0] = "7";
Board[2, 1] = "8";
Board[2, 2] = "9";
btn1.Text = "";
btn2.Text = "";
btn3.Text = "";
btn4.Text = "";
btn5.Text = "";
btn6.Text = "";
btn7.Text = "";
btn8.Text = "";
btn9.Text = "";
}
private void checkWinner()
{
// Top Row
if (Board[0, 0].Equals(Board[0, 1]) && Board[0, 1].Equals(Board[0, 2]))
{
Winner = true;
WinState = Board[0, 0];
}
// Middle Row
if (Board[1, 0].Equals(Board[1, 1]) && Board[1, 1].Equals(Board[1, 2]))
{
Winner = true;
WinState = Board[1, 0];
}
// Bottom Row
if (Board[2, 0].Equals(Board[2, 1]) && Board[2, 1].Equals(Board[2, 2]))
{
Winner = true;
WinState = Board[2, 0];
}
// Left column
if (Board[0, 0].Equals(Board[1, 0]) && Board[1, 0].Equals(Board[2, 0]))
{
Winner = true;
WinState = Board[0, 0];
}
// Middle column
if (Board[0, 1].Equals(Board[1, 1]) && Board[1, 1].Equals(Board[2, 1]))
{
Winner = true;
WinState = Board[0, 1];
}
// Right column
if (Board[0, 2].Equals(Board[1, 2]) && Board[1, 2].Equals(Board[2, 2]))
{
Winner = true;
WinState = Board[0, 2];
}
// Diagonal 1
if (Board[0, 0].Equals(Board[1, 1]) && Board[1, 1].Equals(Board[2, 2]))
{
Winner = true;
WinState = Board[0, 0];
}
// Diagonal 2
if (Board[2, 0].Equals(Board[1, 1]) && Board[1, 1].Equals(Board[0, 2]))
{
Winner = true;
WinState = Board[2, 0];
}
if (Winner == true)
{
if (WinState == "X")
{
MessageBox.Show("Congratulations you win!");
Reset();
}
else if (WinState == "O")
{
MessageBox.Show("Sorry you lose!");
Reset();
}
}
}
private void btn1_Click(object sender, EventArgs e)
{
btn1.Text = "X";
Board[0, 0] = "X";
checkWinner();
}
private void btn2_Click(object sender, EventArgs e)
{
btn2.Text = "X";
Board[0, 1] = "X";
checkWinner();
}
private void btn3_Click(object sender, EventArgs e)
{
btn3.Text = "X";
Board[0, 2] = "X";
checkWinner();
}
private void btn4_Click(object sender, EventArgs e)
{
btn4.Text = "X";
Board[1, 0] = "X";
checkWinner();
}
private void btn5_Click(object sender, EventArgs e)
{
btn5.Text = "X";
Board[1, 1] = "X";
checkWinner();
}
private void btn6_Click(object sender, EventArgs e)
{
btn6.Text = "X";
Board[1, 2] = "X";
checkWinner();
}
private void btn7_Click(object sender, EventArgs e)
{
btn7.Text = "X";
Board[2, 0] = "X";
checkWinner();
}
private void btn8_Click(object sender, EventArgs e)
{
btn8.Text = "X";
Board[2, 1] = "X";
checkWinner();
}
private void btn9_Click(object sender, EventArgs e)
{
btn9.Text = "X";
Board[2, 2] = "X";
checkWinner();
}
}
Run Code Online (Sandbox Code Playgroud)
Bra*_*yce 11
不要因为阅读该文档而不理解递归感到太糟糕.它在解释递归方面做得不是很好.(这是一个艰难的概念 - 我可能也不会这么做).最终,你要做的就是尽量让你的程序做你想做的事.我将尝试从这个角度来解释它.
递归很有用,因为它允许我们在解决方案中编码(一次)一个步骤,然后使用刚刚计算的结果作为输入重复该步骤.尝试从你的角度看你的问题,而不是一些任意的善意算法.你可能很难理解论文中的算法.
尝试这样思考:在游戏开始时玩家1进行游戏.你的程序必须为玩家2选择一个移动.但玩家2必须考虑游戏的其余部分(每个可能的移动).
您可以将其改为:
当前玩家为2,为当前玩家的所有剩余选择赋予权重.
当前玩家为1,为当前玩家的所有剩余选择赋予权重.
当前玩家为2,为当前玩家的所有剩余选择赋予权重.
当前玩家为1,为当前玩家的所有剩余选择赋予权重.
当前玩家为2,为当前玩家的所有剩余选择赋予权重.
当前玩家为1,为当前玩家的所有剩余选择赋予权重.
当前玩家为2,为当前玩家的所有剩余选择赋予权重.
当前玩家为1,为当前玩家的所有剩余选择赋予权重.
您可以将其改为:给予当前玩家,切换玩家并为当前玩家的所有可能选择赋予权重.
重复直到不再有可能的选择
您可以将其改为:给定当前播放器,切换播放器和CheckGoodness()重复直到无法再进行选择
所以,回到你的写作.作者使用1和-1的玩家.为什么?因为当你越来越深地传递动作时,你必须交换玩家,并且当你下降这样的等级时切换玩家很容易(我在这里只讨论玩家:
public int CheckGoodness(bool playerID)
{
playerID = -playerID;
if (!endConditionMet)
{
goodness = CheckGoodness(playerID);
}
return goodness;
}
Run Code Online (Sandbox Code Playgroud)
与玩家一起,你必须传递代表剩余所有可能移动状态的东西.问题是,如果您传递的内容作为参考传递,您所做的任何更改都将反映在原始数据中.确保没有发生.这可能就是@CodeInChaos建议你克隆的原因.
请注意,在递归中,您必须确保始终有办法结束调用序列.您必须修改您所依赖的最终条件.在这种情况下,您的可能移动数量正在下降.否则你永远打电话,内存不足.
编辑:添加的板类说明.
从大局出发考虑一下.类是现实世界事物(例如对象)的表示.一件事具有描述它的属性.这些是班级的数据.事也行动.这些是方法.我听过的一个类的另一个定义是类是对该数据的数据和操作.
想想游戏中的对象.2名球员和一名董事会.没什么别的.
玩家可以移动,并且具有唯一标识符(在这种情况下为"X"或"O"),并且可以是人或AI.我现在想不出任何其他事情(重要的),但通常会有更多的东西可以存在,但不会真正影响程序(如眼睛颜色).这也是您可以使用继承的地方.你有一个带有抽象移动方法的玩家类.从播放器继承的人类,使用覆盖移动方法接受来自UI的输入,从播放器继承的计算机/ AI类,并通过计算具有良好评级的移动来覆盖移动方法.
董事会有数据:
董事会的行动可能是:
你可以有一个静态的GoodNess类(可能需要一个更好的名字),没有数据,只有一个方法(或者这可能是板类上的另一种方法:
AI可以在移动之前调用Goodness GetBestMove方法.
递归将与GetBestMove方法隔离.
请注意,这些都不是一成不变的.类是由您认为应该在其中定义的.这完全取决于你如何成为解决问题的最佳方法.如果您仍然遇到问题,请使用您尝试过的代码更新您的问题.在开始布置代码时,绘制图表确实很有帮助.
祝你好运,希望这会有所帮助,我会尝试更好地监控StackOverflow通知.
归档时间: |
|
查看次数: |
7222 次 |
最近记录: |