如何通过最大数量的井字游戏可能性
How to go through the maximum amount of Tic Tac Toe possibilities?
我想知道有多少种Tic Tac Toe的可能性,所以我在网上搜索了一下,发现了一个数学定理,说Tic Tac Toe有255168种可能的游戏。
网站:http://www.se16.info/hgb/tictactoe.htm
所以我想,我可以写一个程序看看计算机能多快地完成每一种可能性,然后我写了这段代码:
#include <iostream>
#include <time.h>
#include <windows.h>
#include <stdio.h>
using namespace std;
typedef int TTTField[9];
bool checkIfWon(TTTField j){
if(j[0]==1&&j[1]==1&&j[2]==1) return true;
if(j[0]==2&&j[1]==2&&j[2]==2) return true;
if(j[3]==1&&j[4]==1&&j[5]==1) return true;
if(j[3]==2&&j[4]==2&&j[5]==2) return true;
if(j[6]==1&&j[7]==1&&j[8]==1) return true;
if(j[6]==2&&j[7]==2&&j[8]==2) return true;
if(j[0]==1&&j[3]==1&&j[6]==1) return true;
if(j[0]==2&&j[3]==2&&j[6]==2) return true;
if(j[1]==1&&j[4]==1&&j[7]==1) return true;
if(j[1]==2&&j[4]==2&&j[7]==2) return true;
if(j[2]==1&&j[5]==1&&j[8]==1) return true;
if(j[2]==2&&j[5]==2&&j[8]==2) return true;
if(j[0]==1&&j[4]==1&&j[8]==1) return true;
if(j[0]==2&&j[4]==2&&j[8]==2) return true;
if(j[2]==1&&j[4]==1&&j[6]==1) return true;
if(j[2]==2&&j[4]==2&&j[6]==2) return true;
return false;
}
bool checkIfItsOver(TTTField j){
for(int i=0;i<9;i++){
if(j[i]==0){
return false;
}
}
return true;
}
bool checkListOfFields(TTTField game, TTTField listOfFields[], int amountAdded){
int i,j;
for(j=0;j<amountAdded;j++){
int temporaryField=0;
for(i=0;i<9;i++){
if(game[i]==listOfFields[j][i]) temporaryField++;
}
if(temporaryField==9)return true;
}
return false;
}
void clearField(TTTField game){
int i;
for(i=0;i<9;i++) game[i]=0;
}
void addlistOfFields(TTTField game, TTTField listOfFields[], int amountAdded){
for(int i=0;i<9;i++) listOfFields[amountAdded][i]=game[i];
}
int main(){
TTTField listOfFields[50000];
TTTField temporaryField;
int amountAdded=0,randA,round=1,roundCounter=0,amountPassed=0,amountOfWins=0,amountOfDraws=0,winWith5=0,winWith6=0,winWith7=0,winWith8=0,winWith9=0,roundAmountFinished=0;
for(int i=0;roundCounter<100000;i++){
clearField(temporaryField);
roundAmountFinished=0;
do{
do{
randA=rand()%9;
}while(temporaryField[randA]!=0);
temporaryField[randA]=round;
if(checkIfWon(temporaryField)){
break;
}
if(checkIfItsOver(temporaryField)){
break;
}
round=round==1?2:1;
roundAmountFinished++;
}while(1);
if(!checkListOfFields(temporaryField,listOfFields,amountAdded)){
addlistOfFields(temporaryField,listOfFields,amountAdded);
amountAdded++;
if(checkIfWon(temporaryField)){
amountOfWins++;
}
if(checkIfItsOver(temporaryField)){
amountOfDraws++;
}
switch(roundAmountFinished){
case 4:
winWith5++;
break;
case 5:
winWith6++;
break;
case 6:
winWith7++;
break;
case 7:
winWith8++;
break;
case 8:
winWith9++;
break;
}
}
if(amountPassed==amountAdded){
roundCounter++;
}else roundCounter=0;
amountPassed=amountAdded;
}
system("cls");
printf("Total: %d, roundCounter: %dnWins with 5 rounds:%dnWins with 6 rounds:%dnWins with 7 rounds:%dnWins with 8 rounds:%dnWins with 9 rounds:%dnamountOfWins: %d, amountOfDraws: %d",amountAdded,roundCounter,winWith5,winWith6,winWith7,winWith8,winWith9,amountOfWins,amountOfDraws);
return 0;
}
但是它返回给我的总数是:1916,这和网站上的不一样,我不知道我的代码有什么问题
关于代码的一些信息:
- 该字段是一个整数数组,有9个索引,其中1表示叉,2表示圆,0表示空字段。
- 它生成一个从0到9的随机值(如果它之前没有被选中),然后它放一个1或2(取决于它是谁)总是检查是否有人赢了或游戏已经导致平局。
- 完成游戏后,它将检查该可能性是否已经在列表中,如果是,它将不做任何事情并继续进行另一个。
- 当它通过100k的可能性而不添加一个到列表中时,它将完成。
问题在哪里?
我刚刚注意到,checkListOfFields
计数相同的板相同的游戏,而这不是完全真的。你在计算棋盘的结束位置的数量,而不是游戏,这(虽然有趣)是完全不同的事情。
考虑以下两个游戏:
X| | X|O| X|O|X
----- ----- -----
| | | | | |
----- ----- -----
| | | | | |
| |X |O|X X|O|X
----- ----- -----
| | | | | |
----- ----- -----
| | | | | |
你的checkListOfFields
函数检测到这些是相同的游戏,并丢弃一个。因此,也会丢弃在之后的所有潜在移动集的一个副本。
我可能会递归地写这个问题。您的方法将获取一个棋盘状态,添加一个棋子,检查它是否完成(满或赢),如果没有,使用新的棋盘状态再次调用该方法。每次满或赢时,增加一些全局计数器。当该方法返回时,将您的作品移动到新的位置。
我大概会这么做:
recurseBoard(vector<vector<square> >& board, int pieceType) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
// If there's a piece there already, skip
if (board[i][j] != 0) continue;
// add the piece
board[i][j] = pieceType;
// if it's full or win, increment counter
if (victory(board)) count++;
else (recurseBoard(board), otherPieceType);
// Clear the piece you just added
board[i][j] = 0;
}
}
}
如果我是你,我会首先为平方值创建一个enum
,而不是传递和比较数字:
enum square {X, O, EMPTY};
那么你就可以把棋盘保持为2d向量:
vector<vector<square> > board (3, vector<square>(3, EMPTY));
然后通过递归找到可能的游戏数量:
int find_games(vector<vector<square> >& board, square move) {
if(game_over(board)) return 1;
int num_moves = 0;
for(int x = 0; x < board.size(); x++) {
for(int y = 0; y < board[x].size(); y++) {
if(board[x][y] != EMPTY) continue;
board[x][y] = move; //test if player made a move here...
num_moves += find_games(board, (move == X) ? Y : X);
board[x][y] = EMPTY; //set space back to empty
}
}
return number_moves;
}
相关文章:
- 在C++游戏中与库存系统作斗争
- 换位表导致测试失败(但在游戏中运行良好)
- Craps游戏问题,忽略if语句
- 矢量下标超出SFML游戏中的范围
- 我是 c++ 的新手.学习基本知识后,我想做井字游戏.对于印刷板,我在下面写代码,但它显示错误
- 我在贪吃蛇游戏中收到了错误代码 -1073741571
- 我应该在简单的策略游戏中为各个派系使用类吗 - C++
- 游戏体验和升级
- 我的代码运行良好,但在游戏循环中中断
- 如何使用 SFML 在贪吃蛇游戏中定义游戏结束?
- 我可以使用任何好的逻辑来阻止计算机将 O 放在井字游戏中的现有 X 上
- 将鼠标和键盘输入发送到 unity3d 游戏 (Rust)
- 在猜谜游戏 c++ 中不计算尝试次数
- 在C++不适用于猜数字游戏的情况下再次播放选项
- 在为我的基于文本的 RPG 游戏制作库存时遇到困难
- 如何降低生产者获得锁的可能性,而消费者在使用std::condition_variable时无法获得锁?
- 在定义字符数组(井字游戏)的 for 循环中应用输入限制
- Frank Luna 在他的书"使用 DirectX12 进行 3D 游戏编程"的介绍中盒子示例的问题
- 如何在Linux上正确发布C++软件(游戏)
- 如何通过最大数量的井字游戏可能性