Algorithm 生成所有唯一Tic Tac趾板的列表
我想生成一个文本文件,包含0=Blank、1=X和2=O结构中的所有Tic-Tac趾板布局。不幸的是,数学不是我的强项,我似乎在任何地方都找不到这样的例子Algorithm 生成所有唯一Tic Tac趾板的列表,algorithm,tic-tac-toe,Algorithm,Tic Tac Toe,我想生成一个文本文件,包含0=Blank、1=X和2=O结构中的所有Tic-Tac趾板布局。不幸的是,数学不是我的强项,我似乎在任何地方都找不到这样的例子 我向你保证这不是家庭作业。我打算通过Minimax计算器运行此数据,以生成包含RGB值的图像,该值表示基于电路板设置的最佳移动。我正在为一个不支持功能(它是事件驱动的)的平台开发Tic-Tac-Toe,因此我将在游戏中将棋盘转换为一个数字,然后在图像中查找像素的RGB,以指示最佳移动方式。这是一个厚颜无耻的解决方案,但它只需要145x145像
我向你保证这不是家庭作业。我打算通过Minimax计算器运行此数据,以生成包含RGB值的图像,该值表示基于电路板设置的最佳移动。我正在为一个不支持功能(它是事件驱动的)的平台开发Tic-Tac-Toe,因此我将在游戏中将棋盘转换为一个数字,然后在图像中查找像素的RGB,以指示最佳移动方式。这是一个厚颜无耻的解决方案,但它只需要145x145像素的图像(145x145=21025,因此每个像素都代表基于电路板的建议移动)就可以了。这也意味着我不必浪费CPU时间,这是另一个优点。因为你需要电路板布局,所以它们只有少数(19683) 你可以用蛮力产生所有这些。每个框只有3种可能。这里有9个盒子,只需把它们全部放进去 编辑:
intc=0;
而(c<262144){
bool-valid=(c&3)<3;
有效&=((c>>2)和3)<3;
有效&=((c>>4)和3)<3;
有效&=((c>>6)和3)<3;
有效&=((c>>8)&3)<3;
有效&=((c>>10)&3)<3;
有效&=((c>>12)&3)<3;
有效&=((c>>14)&3)<3;
有效&=((c>>16)&3)<3;
如果(有效){
int i=c;
int j=0;
而(j<9){
cout=2;
j++;
}
cout你可以简单地用蛮力穿过。每个方块是0、1或2左右…:
for (int i1 = 0; i1 <= 2; i++) {
for (int i2 = 0; i2 <= 2; i++) {
// ...
// lot's of nested for loops
// ...
}
}
魔法就会发生
这是C++的方式。< /P> < P>有9个位置,一个字母有3个字母(x,o,空)。可能组合的总数是3 ^ 9=19683。
for(int i = 0; i < 19683; ++i)
{
int c = i;
for (int j = 0; j < 9; ++j)
{
cout << (c % 3) << " ";
c /= 3;
}
cout << endl;
}
for(int i=0;i<19683;++i)
{
int c=i;
对于(int j=0;j<9;++j)
{
coutMy Minimax for Tic Tac Toe实现生成一个5477个节点的树。每个节点包含一个Tic Tac趾板状态,并满足以下条件:
- 根据Tic Tac Toe规则,棋盘状态是有效的,玩家必须轮流放置X和Os。也就是说,没有像以下这样的棋盘位置:
XXX
XXX
三十
《树的所有叶子》包含了根据Tic Tac Toe规则考虑结束游戏状态的棋盘状态(玩家1胜,玩家2赢或平局)。也就是说没有树的分支:
XOX
OXO
X
|
|
XOX
OXO生成所有可能的游戏板(深度优先搜索效果最好),并在765个游戏板中排除重复的旋转和镜像结果。626个游戏中,91个游戏X赢了,44个游戏O赢了,3个游戏是平局
如果你只在最佳移动中被重置,你可以简单地使用
作为参考。做一个很好的海报
但是tic-tac-toe的所有乐趣都在于实现它。所以我把它留给读者。只有几个提示:
- 电路板上的每个磁贴都有3种状态,因此您可以将电路板编码为基数3中的数字。为了简化数学,我使用基数4(每个磁贴2位,因此我只需要移位)。然后我有一个哈希函数,在所有可能的旋转和镜像(8种情况)下为电路板生成该数字并返回最小值。这样我就可以查找我是否已经玩过那个棋盘了
- 从一个空棋盘开始,在棋盘上的每一个可能的位置上做一个标记,检查棋盘是否已经玩过,标记它已经玩过,检查游戏是否结束,并数一数棋盘,否则轮换玩家
- 第一个X只能设置在3个位置(考虑旋转和镜像),所有后续移动最多有8个选项。与对要播放的绝对磁贴进行编码不同,您只能对空磁贴进行计数并对其进行3位编码
- 使用上面的散列函数,我们可以得到626块板,我们必须在其中移动(您只需反转旋转/镜像以获得数据的实际移动)。可能有一个不太大的相对素数,这样每个板都可以放入一个散列表而不会发生冲突。假设这个数字是696(我知道,不是相对素数)。每个棋盘3位,只需要261字节的数据就可以存储每个可能的游戏的最佳移动
- 因为你玩得很完美,可触及的板的数量又减少了。建立一个用于玩X的数据集和一个用于玩O的数据集,你可以再减少一次
>p>想让它变小吗?只要按照几个基本规则编程:如果第一个O在中间是空闲的。用2个“我的颜色”来连续行。用2个“其他颜色”行中的行,等等。维基百科有8个规则的列表,但我认为我这样做的时候少了。
- 一个完美的井字游戏对手很无聊。你永远不会赢。为什么不让游戏从失败中吸取教训呢?记录所有626个棋盘及其可能的移动。当一个移动导致失败时,将该移动从棋盘上移除。如果棋盘上没有剩余的移动,将导致该移动的移动从所有棋盘上移除(如果删除了最后一步,则递归)。你的游戏永远不会以同样的方式输掉两次。同样,对于赢得比赛的招式,你会将对手的招式从可能的招式列表中删除,如果没有剩余招式,你会将上一个招式标记为肯定的胜利。这样,如果你能强行赢得比赛,你将从现在开始一直强制赢得比赛。玩X能让它以91种方式输掉吗?玩O你能玩g吗让它松开所有44个方向
与早期的解决方案类似,但在Python中更易于阅读和使用
for i in range(3**9):
c = i
for j in range(9):
if j % 3 == 0:
print("")
print(str(c % 3) + " ", end='')
c //= 3
print("")
总的可能移动不是3^9,因为它包括许多不允许的Tic Tac Toe移动。
(X's-O's)或(O's-X's)必须始终等于1。
如前所述,可能的移动总数为5477
皮思
place(0);
for(int i = 0; i < 19683; ++i)
{
int c = i;
for (int j = 0; j < 9; ++j)
{
cout << (c % 3) << " ";
c /= 3;
}
cout << endl;
}
for i in range(3**9):
c = i
for j in range(9):
if j % 3 == 0:
print("")
print(str(c % 3) + " ", end='')
c //= 3
print("")
import numpy as np
StatesMatrix = np.zeros((3**9,9))
for i in range(3**9):
c = i
for j in range(9):
StatesMatrix[i][j] = c % 3
c //= 3
StatesMatrix1 = np.zeros((5814,9))
k = 0
for i in range(0,StatesMatrix.shape[0]):
if (np. count_nonzero(StatesMatrix[i] == 1) - np. count_nonzero(StatesMatrix[i] == 2)) == 1 or (np. count_nonzero(StatesMatrix[i] == 2) - np. count_nonzero(StatesMatrix[i] == 1))== 1:
StatesMatrix1[k] = StatesMatrix[i]
k = k + 1
print(StatesMatrix1)
print(k)