TicTacToe
已经有计划地学习机器博弈方面的知识,在CSDN上面留下,自己的心得体会以及实现的Demo,将开启一个分类专栏,大家如果对这方面感兴趣的或正在学习的,欢迎一键三连哦~
最近在学习人机博弈方面的知识,自己动手做了一个小demo,用的是极大极小值搜索,其中的估值函数evel()有点小瑕疵,仅供大家学习参考,有什么不懂得或有什么想法欢迎私信。
TicTacToe.cpp
主函数,调用两个方法。
#include "pch.h"
void map();//绘制地图
void minimaxSearch(int depth);//极大极小搜索
int main()
{
int a = 0;
while (true)
{
printf("1.开始游戏 \n");
printf("2.结束游戏 \n");
scanf_s("%d", &a);
switch (a)
{
case 1:
map();
minimaxSearch(9);
closegraph();
break;
case 2:
break;
}
if (a == 2)
{
break;
}
}
return 0;
}
pch.h
定义头文件,里面还定义了一些常量,方便修改。
#ifndef PCH_H
#define PCH_H
#include<stdio.h>
#include<easyx.h>
#include<stdlib.h>
#include <iostream>
#define XMAX 650
#define YMAX 650
#define step 150
#define left 100
#define top 100
#endif //PCH_H
pch.cpp
里面写了所有的方法。
#include "pch.h"
int array[3][3];
int man_ai = 1;
int abcd = -1;
int eval();
int isfull();
int minSearch(int depth);
int maxSearch(int depth);
int iswin(int x, int y);
minimaxSearch(int depth)
主函数
void minimaxSearch(int depth)
{
for (int i = 0;i < 3;i++)//初始化棋盘
{
for (int j = 0;j < 3;j++)
{
array[i][j] = 0;
}
}
int x, y = 0;//纪录玩家要下的位置
man_ai = 1;//玩家下棋
while (true)
{
if (man_ai == 1)//人类下棋
{
while (true)
{
MOUSEMSG m = GetMouseMsg();
if (m.mkLButton)
{
x = m.x;
y = m.y;
if (x<left || x>(left + 3 * step))//越界
{
continue;
}
if (y<top || y>(top + 3 * step))
{
continue;
}
x = (x - left) / step;//将x,y转换为0,1
y = (y - top) / step;
int xy = x;//置换x,y
x = y;
y = xy;
if (array[x][y] != 0)//如果该位置有棋子,则不下
{
continue;
}
array[x][y] = man_ai;//下棋
if (man_ai == 1)//人类画圆
{
circle(left + step * (2 * y + 1) / 2, top + step * (2 * x + 1) / 2, 50);
}
man_ai = man_ai * (-1);//换电脑下棋
break;
}
}
}
if (iswin(x, y)) {
if (array[x][y] == 1)
{
Sleep(500);
printf("O获胜\n");
}
if (array[x][y] == -1)
{
Sleep(500);
printf("X获胜\n");
}
break;
}
if (isfull())
{
Sleep(500);
printf("***平局****\n");
break;
}
if (man_ai == -1)//电脑下棋
{
maxSearch(depth);//极大值搜索
x = abcd / 3;
y = abcd % 3;
array[x][y] = man_ai;
if (man_ai == -1)
{
line(left + step * y + 20, top + step * x + 20, left + step * (y + 1) - 20, top + step * (x + 1) - 20);
line(left + step * y + 20, top + step * (x + 1) - 20, left + step * (y + 1) - 20, top + step * x + 20);
}
man_ai = man_ai * (-1);
}
if (iswin(x, y)) {
if (array[x][y] == 1)
{
Sleep(500);
printf("O获胜\n");
}
if (array[x][y] == -1)
{
Sleep(500);
printf("X获胜\n");
}
break;
}
if (isfull())
{
Sleep(500);
printf("*****平局*****\n");
break;
}
}
}
map()
绘制棋盘
void map()
{
initgraph(XMAX, YMAX);
line(left, top + step, left + 3 * step, top + step);
line(left, top + 2 * step, left + 3 * step, top + 2 * step);
line(left + step, top, left + step, top + 3 * step);
line(left + 2 * step, top, left + 2 * step, top + 3 * step);
}
maxSearch(int depth)
极大搜索
int maxSearch(int depth)
{
int bestValue = -1000;
if (depth == 0 || isfull())
{
return eval();
}
else
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (array[i][j] == 0)
{
array[i][j] = man_ai;
int max;
max = minSearch(depth - 1);
if (bestValue < max)
{
bestValue = max;
abcd = 3 * i + j;
}
array[i][j] = 0;
}
}
}
}
return bestValue;
}
minSearch(int depth)
极小搜索
int minSearch(int depth)
{
int bestValue = 1000;
if (depth == 0 || isfull())
{
return eval();
}
else
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (array[i][j] == 0)
{
array[i][j] = (-1)*man_ai;
int min;
min = maxSearch(depth - 1);
if (bestValue > min)
{
bestValue = min;
abcd = 3 * i + j;
}
array[i][j] = 0;
}
}
}
}
return bestValue;
}
iswin(int x, int y)
检查是否赢棋
int iswin(int x, int y) //判断是否有人获胜,获胜返回1
{
int a = 0, b = 0;
int o = array[x][y];
for (int i = 0; i < 3; i++)
{
for (int t = 0; t < 3; t++)
{
a = a + array[i][t];
b = b + array[t][i];
}
if (a == 3 * o || b == 3 * o)
{
return 1;
}
a = 0;
b = 0;
}
a = array[0][0] + array[1][1] + array[2][2];
b = array[0][2] + array[1][1] + array[2][0];
if (a == 3 * o || b == 3 * o)
{
return 1;
}
return 0;
}
isfull()
检查棋盘是否已满
int isfull()
{
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 3;j++)
{
if (array[i][j] == 0)
{
return 0;
}
}
}
return 1;
}
eval()
估值函数,使用的函数: E(n) = M(n) - O(n)
其中E(n)为状态n的总价值评价,M(n)为机器胜利的路线总数 , O(n)为人类胜利的路线总数。
int eval()
{
int win = 8;
int lose = 8;
int a = 0, b = 0;
for (a = 0; a < 3; a++)
{
for (b = 0; b < 3; b++)
{
if (array[a][b] == 1)
{
win--;
break;
}
}
for (b = 0; b < 3; b++)
{
if (array[b][a] == 1)
{
win--;
break;
}
}
}
for (a = 0; a < 3; a++)
{
if (array[a][a] == 1)
{
win--;
break;
}
}
for (a = 0; a < 3; a++)
{
if (array[a][2 - a] == 1)
{
win--;
break;
}
}
for (a = 0; a < 3; a++)
{
for (b = 0; b < 3; b++)
{
if (array[a][b] == -1)
{
lose--;
break;
}
}
for (b = 0; b < 3; b++)
{
if (array[b][a] == -1)
{
lose--;
break;
}
}
}
for (a = 0; a < 3; a++)
{
if (array[a][a] == -1)
{
lose--;
break;
}
}
for (a = 0; a < 3; a++)
{
if (array[a][2 - a] == -1)
{
lose--;
break;
}
}
return win - lose;
}
- 欢迎私信交流,希望交到更多志同道合的朋友~