Tic-Tac-Toe井字棋多模式C++实现
根据网上的代码,利用C++实现了Tic-Tac-Toe井字棋的人机对弈、机人对弈、机机对弈、人人对弈。
关于 Tic-Tac-Toe的下法,可参考https://xkcd.com/832/给出的手绘图,如下:
// https://xkcd.com/832/ 手绘X最佳下棋方式和O最佳下棋方式
/* 改编自:
https://blog.csdn.net/huqinweI987/article/details/52793048?utm_medium=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
*/
#include<iostream>
using namespace std;
typedef enum TicTacToeState {
TTTS_Default = 0,
TTTS_X = 1,
TTTS_O = 2,
}TTTS;
void Print(TTTS array[3][3]); //打印提示及棋盘
TTTS CheckWin(TTTS array[][3]); //判断是否有胜者
int FindOPos(TTTS net[][3]); //寻找O棋子“最佳”部子位置
int FindXPos(TTTS net[][3]); //寻找X棋子“最佳”部子位置
int main()
{
TTTS array[3][3] = { TTTS_Default };
int index_x, index_y;
int counter;
int num[9];
int iPlayer = 1;
int iOpt = 0;
Print(array); //打印棋盘
cout << " X O " << endl;
cout << "0: Player Computer " << endl; //人机对弈
cout << "1: Computer Player " << endl; //机人对弈
cout << "2: Computer Computer " << endl; //机机对弈
cout << "3: Player Player " << endl; //人人对弈
cout << "Select a mode (0-3): " << endl;
cin >> iPlayer;
iOpt = FindXPos(array); //iOpt 为棋盘上X棋最佳位置
for(counter=0;counter<9;counter++) {
if (counter % 2) {
cout << "Play O input position(1-9) :" << endl;
}
else {
cout << "Play X input position(1-9) :" << endl;
}
if(iPlayer != 3 ) {
if (counter % 2== iPlayer) //人机对弈 & 机人对弈
while (cin >> num[counter])
{
index_x = (num[counter] - 1) / 3;
index_y = (num[counter] - 1) % 3;
if (!((index_x >= 0 && index_x < 3) && (index_y >= 0 && index_y < 3))
|| (array[index_x][index_y] != TTTS_Default))
{
cout << "wrong position,please retry!" << endl;
continue;
}
else
break;
}
else { // 机机对弈 & 人机对弈 & 机人对弈
num[counter] = iOpt;
index_x = (num[counter] - 1) / 3;
index_y = (num[counter] - 1) % 3;
}
}
if( iPlayer == 3 ) { //人人对弈
while (cin >> num[counter])
{
index_x = (num[counter] - 1) / 3;
index_y = (num[counter] - 1) % 3;
if (!((index_x >= 0 && index_x < 3) && (index_y >= 0 && index_y < 3))
|| (array[index_x][index_y] != TTTS_Default))
{
cout << "wrong position,please retry!" << endl;
continue;
}
else
break;
}
}
array[index_x][index_y] = counter % 2 ? TTTS_O : TTTS_X;
Print(array); //打印棋盘
if (counter % 2 == 0) iOpt = FindOPos(array); //找棋盘上最佳下一步棋的位置
if (counter % 2 == 1) iOpt = FindXPos(array); //找棋盘上最佳下一步棋的位置
if (counter<4) continue;
if (CheckWin(array)) break;
if (counter >= 8) cout <<"game over,draw game!" << endl;
}
cout << "\n本轮棋盘落子顺序:";
for(int i = 0; i < counter; i++) { cout << num[i] <<" "; }
cout <<"\n";
}
TTTS CheckWin(TTTS array[][3])
{
int ixo = TTTS_Default;
for (int i = 0; i < 3; i++)
if (array[i][0] == array[i][1] &&
array[i][0] == array[i][2])
ixo += array[i][0];
for (int j = 0; j < 3; j++)
if (array[0][j] == array[1][j] &&
array[0][j] == array[2][j])
ixo += array[0][j];
if (array[0][0] == array[1][1] &&
array[0][0] == array[2][2])
ixo += array[0][0];
if (array[0][2] == array[1][1] &&
array[0][2] == array[2][0])
ixo += array[0][2];
if (ixo == TTTS_O) cout << "game over,O win!!!!!" << endl;
if (ixo == TTTS_X) cout << "game over,X win!!!!!" << endl;
return (TTTS)ixo;
}
// 打印棋盘
void Print(TTTS array[3][3])
{
system("cls");
int i, j;
printf("\n\t\t\tTic-Tac-Toe (井字棋或三连棋)\n");
printf("\n\t规则:两人在九格方盘上分别轮流标记X和O, 先将三个同一记号排成横线、直线、斜线, 即是胜者\n");
printf("\n\t棋盘位置编号\n");
for (i = 0; i < 3; i++) {
printf("\n\t+-+-+-+\n\t|");
for (j = 0; j < 3; j++) {
cout << i * 3 + j + 1 << "|";
}
}
printf("\n\t+-+-+-+\n\n");
printf("\n\n\t当前盘面\n");
for (i = 0; i < 3; i++)
{
printf("\n\t+-+-+-+\n\t|");
for (j = 0; j < 3; j++)
{
if (array[i][j] == TTTS_Default) printf(" ");
if (array[i][j] == TTTS_O) printf("O");
if (array[i][j] == TTTS_X) printf("X");
printf("|");
}
}
printf("\n\t+-+-+-+\n\n");
}
/* FindOPos 改自
https://blog.csdn.net/iteye_4389/article/details/82484665?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
*/
int FindOPos(TTTS net[][3])
{
// int net[3][3];//0 means null;1 means X;2 means O;
int level[3][3] = { -1 };//越大优先级越高
int o2 = 10000;//一个己方活二权值
int x2 = 1000;//一个对方活二权值
int x = 10;//一个对方活一权值
int o = 6;//一个己方活一权值
int nothing = 4;//一个空行权值
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (net[i][j] != 0) level[i][j] = 0;
else {
level[i][j] = 1;
//横竖两条,每人都有
//自己活二,,220
if (((net[0][j] + net[1][j] + net[2][j]) == 4) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == -1)
level[i][j] = level[i][j] + o2;
if (((net[i][0] + net[i][1] + net[i][2]) == 4) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二,110
if (((net[0][j] + net[1][j] + net[2][j]) == 2) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 0)
level[i][j] = level[i][j] + x2;
if (((net[i][0] + net[i][1] + net[i][2]) == 2) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X,100
if (((net[0][j] + net[1][j] + net[2][j]) == 1) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 0)
level[i][j] = level[i][j] + x;
if (((net[i][0] + net[i][1] + net[i][2]) == 1) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O,200
if (((net[0][j] + net[1][j] + net[2][j]) == 2) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 1)
level[i][j] = level[i][j] + o;
if (((net[i][0] + net[i][1] + net[i][2]) == 2) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][j] + net[1][j] + net[2][j]) == 0) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
if (((net[i][0] + net[i][1] + net[i][2]) == 0) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
//分情况
//主对角线
if ((i == 0 && j == 0) || (i == 2 && j == 2) || (i == 1 && j == 1)) {
//己方活二
if (((net[0][0] + net[1][1] + net[2][2]) == 4) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二
if (((net[0][0] + net[1][1] + net[2][2]) == 2) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X
if (((net[0][0] + net[1][1] + net[2][2]) == 1) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O
if (((net[0][0] + net[1][1] + net[2][2]) == 2) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][0] + net[1][1] + net[2][2]) == 0) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
}
//副对角线
if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 1)) {
//己方活二
if (((net[0][2] + net[1][1] + net[2][0]) == 4) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二
if (((net[0][2] + net[1][1] + net[2][0]) == 2) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X
if (((net[0][2] + net[1][1] + net[2][0]) == 1) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O
if (((net[0][2] + net[1][1] + net[2][0]) == 2) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][2] + net[1][1] + net[2][0]) == 0) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
}//the end of for if
}//the end of if
}//the end of for j
}//the end of for j
//寻找最大权值的位置
int maxi = 0, maxj = 0, temp = -1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (level[i][j] > temp)
{
temp = level[i][j];
maxi = i;
maxj = j;
}
//System.out.println("net[i][j]=" + net[i][j]);
//System.out.println("level[i][j]=" + level[i][j]);
}
}
cout <<"建议下棋位置: "<< maxi * 3 + maxj + 1 << " 推荐度为:" << temp << '\n';
return maxi * 3 + maxj + 1;
}
int FindXPos(TTTS net1[][3])
{
// 交换X和O的位置,判断X的最佳位置
TTTS net[3][3] = { TTTS_Default };//0 means null;1 means O;2 means X;
int level[3][3] = { -1 };//越大优先级越高
int o2 = 10000;//一个己方活二权值
int x2 = 1000;//一个对方活二权值
int x = 10;//一个对方活一权值
int o = 6;//一个己方活一权值
int nothing = 4;//一个空行权值
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (net1[i][j] == TTTS_O) net[i][j] = TTTS_X;
if (net1[i][j] == TTTS_X) net[i][j] = TTTS_O;
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (net[i][j] != 0) level[i][j] = 0;
else {
level[i][j] = 1;
//横竖两条,每人都有
//自己活二,,220
if (((net[0][j] + net[1][j] + net[2][j]) == 4) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == -1)
level[i][j] = level[i][j] + o2;
if (((net[i][0] + net[i][1] + net[i][2]) == 4) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二,110
if (((net[0][j] + net[1][j] + net[2][j]) == 2) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 0)
level[i][j] = level[i][j] + x2;
if (((net[i][0] + net[i][1] + net[i][2]) == 2) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X,100
if (((net[0][j] + net[1][j] + net[2][j]) == 1) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 0)
level[i][j] = level[i][j] + x;
if (((net[i][0] + net[i][1] + net[i][2]) == 1) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O,200
if (((net[0][j] + net[1][j] + net[2][j]) == 2) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == 1)
level[i][j] = level[i][j] + o;
if (((net[i][0] + net[i][1] + net[i][2]) == 2) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][j] + net[1][j] + net[2][j]) == 0) && (net[0][j] * net[1][j] * net[2][j]) == 0 && ((net[0][j] - 1) * (net[1][j] - 1) * (net[2][j] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
if (((net[i][0] + net[i][1] + net[i][2]) == 0) && (net[i][0] * net[i][1] * net[i][2]) == 0 && ((net[i][0] - 1) * (net[i][1] - 1) * (net[i][2] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
//分情况
//主对角线
if ((i == 0 && j == 0) || (i == 2 && j == 2) || (i == 1 && j == 1)) {
//己方活二
if (((net[0][0] + net[1][1] + net[2][2]) == 4) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二
if (((net[0][0] + net[1][1] + net[2][2]) == 2) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X
if (((net[0][0] + net[1][1] + net[2][2]) == 1) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O
if (((net[0][0] + net[1][1] + net[2][2]) == 2) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][0] + net[1][1] + net[2][2]) == 0) && (net[0][0] * net[1][1] * net[2][2]) == 0 &&
((net[0][0] - 1) * (net[1][1] - 1) * (net[2][2] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
}
//副对角线
if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 1)) {
//己方活二
if (((net[0][2] + net[1][1] + net[2][0]) == 4) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == -1)
level[i][j] = level[i][j] + o2;
//对方活二
if (((net[0][2] + net[1][1] + net[2][0]) == 2) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 0)
level[i][j] = level[i][j] + x2;
//单个X
if (((net[0][2] + net[1][1] + net[2][0]) == 1) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 0)
level[i][j] = level[i][j] + x;
//单个O
if (((net[0][2] + net[1][1] + net[2][0]) == 2) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == 1)
level[i][j] = level[i][j] + o;
//空行,000
if (((net[0][2] + net[1][1] + net[2][0]) == 0) && (net[0][2] * net[1][1] * net[2][0]) == 0 &&
((net[0][2] - 1) * (net[1][1] - 1) * (net[2][0] - 1)) == -1)
level[i][j] = level[i][j] + nothing;
}//the end of for if
}//the end of if
}//the end of for j
}//the end of for j
//寻找最大权值的位置
int maxi = 0, maxj = 0, temp = -1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (level[i][j] > temp)
{
temp = level[i][j];
maxi = i;
maxj = j;
}
//System.out.println("net[i][j]=" + net[i][j]);
//System.out.println("level[i][j]=" + level[i][j]);
}
}
cout << "建议下棋位置: " << maxi * 3 + maxj + 1 << " 推荐度为:" << temp << '\n';
return maxi * 3 + maxj + 1;
}