我正在为Tic-Tac-Toe游戏设计我的实施策略。由于这是我的第一个游戏实现,我有点困惑,需要一些通用指针。
现在,Tic-Tac-Toe中的获胜组合总数为8.目前,我计划将这些获胜组合存储在一个阵列中。一旦最终用户进行了至少3次移动,我将通过比较Player对阵此阵列的当前位置来开始检查玩家是否赢得了游戏。但是,我确信这不是检查玩家是否有获胜组合的有效方法。
有人可以建议我如何设计游戏的逻辑吗?
答案 0 :(得分:11)
不要担心效率。我写了一个回溯解决方案,只有549,945个可能的游戏状态。在笔记本电脑上运行这些操作只需不到0.25秒。这是我的逻辑,看看游戏是否结束 - 显然效率不高,但无所谓:
private boolean isWinningMove(int row, int col) {
int piece = board[row][col];
// check current row
boolean w = true;
for (int x = 0; x < 3; x++) { w = w && (board[row][x] == piece); }
if (w) { return true; }
// check current column
w = true;
for (int x = 0; x < 3; x++) { w = w && (board[x][col] == piece); }
if (w) { return true; }
// check 0,0 diagonal
w = true;
for (int x = 0; x < 3; x++) { w = w && (board[x][x] == piece); }
if (w) { return true; }
// check 0,2 diagonal
w = true;
for (int x = 0; x < 3; x++) { w = w && (board[x][2 - x] == piece); }
return w;
}
以下是我的结果,它与维基百科页面上的数据匹配:
Moves Simulated: 549945
Draws=46080 Player1-Wins=131184 Player2-Wins=77904
Perfect Strategy Implies: Always a tie.
Games won in 0 moves? 0
Games won in 1 moves? 0
Games won in 2 moves? 0
Games won in 3 moves? 0
Games won in 4 moves? 0
Games won in 5 moves? 1440
Games won in 6 moves? 5328
Games won in 7 moves? 47952
Games won in 8 moves? 72576
Games won in 9 moves? 81792
答案 1 :(得分:5)
由于井字游戏的状态空间非常小,你可以存储所有可能的最终游戏位置,并使用旋转,但我认为你过度思考它。 / p>
不是为游戏板存储3x3阵列,而是使用7x7阵列,游戏板最内部为3x3。每个方块至少应包含三个值 - 例如PLAYER_1
,PLAYER_2
和NONE
。最初,所有值都应设置为NONE
。然后,在每个玩家的移动之后,检查所选择的正方形周围的所有3个; 2以上,2下,2左,2右,2左上,2右下,2右上,2左下。
为什么7x7阵列?使用7x7阵列,您可以安全地从3x3区域中的任何方向搜索所有方向,而无需if
语句来查看您是否正在离开阵列的边缘。董事会将如下所示:
0 1 2 3 4 5 6 0 * * * * * * * 1 * * * * * * * 2 * * * * * * * 3 * * * * * * * 4 * * * * * * * 5 * * * * * * * 6 * * * * * * *
例如,如果第一个玩家移动到tic-tac-toe板上的0,0,则与在7x7板上移动到2,2相同。当进行移动时,你会在2,2平方左右进行检查,以查看一行中是否有三个具有相同值的正方形
由于3x3板周围的方块带总是具有值NONE
,因此它们永远不会触发获胜条件。
如果其中任何一个都匹配相同的玩家价值(例如第一个玩家的PLAYER_1),则游戏结束并获胜。否则,如果所有方格都被拍摄,那么游戏就是平局。
我过去曾将它用于其他类似的游戏并且效果很好。
答案 2 :(得分:3)
而不是迭代某些东西,我只写了8个组合。
我的评价函数执行以下操作:如果A是移动的一侧&amp;如果在所有组合之一中有两个A元素和一个0(空),那么它就是胜利:
boolean player_can_win(int value) { //value is side's element*2
return board[0] + board[1] + board[2] == value
|| board[3] + board[4] + board[5] == value
|| board[6] + board[7] + board[8] == value
|| board[0] + board[3] + board[6] == value
|| board[1] + board[4] + board[7] == value
|| board[2] + board[5] + board[8] == value
|| board[0] + board[4] + board[8] == value
|| board[2] + board[4] + board[6] == value;
}
答案 3 :(得分:3)
考虑用整数表示董事会。
-1 = X
0 = empty
1 = O
现在,将8种可能性中的每一种加上正方形的值(3个上下,3个左右,2个区域)。
如果总和为3,则O获胜 如果总和为-3,则X胜出
如果总和为2,那么O在其中一个位置有一个获胜的动作 如果总和为-2,那么X在其中一个位置有一个获胜的动作。
AI可以将其作为决策的基础。向前看一步就足以永远不会失败。
如果AI开始游戏,那么最好的动作就是一个角落。如果对手未能占据中锋,则AI获胜。如果他确实占据了中心,那么AI就赢了,或者抽签。
答案 4 :(得分:2)
如果你正在播放广义的NXN tic-tac-toe,那么明确地存储和比较解决方案并不是最有效的,但是因为它就像小板,只有8个这样的组合,所以明确存储像这样的解决方案没有任何问题
更大的问题是,根据存储风格,与解决方案无关的空间可能是个问题。
O - - - O -
X X X vs. X X X
O - O O - O
比较3x3状态数组这些是不同的,因此这种方法需要超过8个结束状态
我认为你保留类似gameState 3x3数组的东西,空白= 0,X = 1,O = 2?
除了那些明确的比较,你可以做类似
的事情win = false
// rows/columns
for i in 0,1,2
if (state[i][0] != BLANK && state[i][0] == state[i][1] == state[i][2]) win = true
#extensible to NxN - all(j == state[i][0] for j in state[i])
if (state[0][i] != BLANK && state[0][i] == state[1][i] == state[2][i]) win = true
#extensible to NxN - all(j == state[0][i] for j in zip(*state)[i])
//diagonals
if (state[0][0] != BLANK && state[0][0] == state[1][1] == state[2][2]) win = true
#extensible to NxN - all(state[j][j] == state[0][0] for j in range(len(state))
if (state [2][0] != BLANK && state[2][0] == state[1][1] == state[0][2]) win = true
如果你想获胜来存储胜利者而不是旗帜,那么将win = BLANK置于顶部,并设置为任何相关正方形的值。不应该是必要的,胜利者显然是最近的举动!
我认为编写井字游戏的那部分你可能会发现最具挑战性,但并不太难,是AI。编写一个不会丢失的AI(总是至少可以强制打平)并不是很困难,但并非完全无足轻重。如果你想要一个能够偶尔丢失的相对优秀的AI,你需要添加一些随机性或其他东西。
答案 5 :(得分:0)
实施Tic Tac Toe游戏可能是就AI而言要解决的最简单问题 和搜索空间。
关键是要使用Minimax,Iterative deepening Depth-first search和Alpha-beta pruning算法来解决问题。
这是我用Python编写的游戏implementation,它只有约200行代码,并具有以Human vs. Human
,Human vs. Computer
和{{1} }。它还可以统计到达/修剪的节点的深度和数量,从而达到最佳移动效果。
我强烈推荐Computer vs. Computer
人工智能course,它提供了有关当前AI主题和解决方案的基础知识。