#define _CRT_SECURE_NO_WARNINGS 1
//编写前的准备
/*
* 安装Easyx图形库
* 了解井字棋规则
* 对数组、循环、函数知识回顾
//作用:
initgraph 创建一个窗口
loadimage 加载图片到指定位置
GetMouseMsg(); 获取用户鼠标信息
*/
#include<stdio.h>
#include<graphics.h>//用于画图,Easyx图形库
#include<time.h>//用于生成随机数
//用于播放后台音乐
#include<windows.h>
#pragma comment(lib,"Winmm.lib")
enum { AI = -1, Man = 1 };//枚举------>标记棋子
int map[3][3];//设计地图
IMAGE imgMan;//定义一个IMAGE类型的变量用于存放用户输入的标志
IMAGE imgAI;//定义一个IMAGE类型的变量用于存放电脑输入的标志
//棋子胜利有8种情况,3个格子,每个格子有x、y两个坐标
/*********************************************************************************************************/
int Key[8][3][2] = {
0,0, 0,1, 0,2,//第一行
1,0, 1,1, 1,2,//第二行
2,0, 2,1, 2,2,//第三行
0,0, 1,0, 2,0,//第一列
0,1, 1,1, 2,1,//第二列
0,2, 1,2, 2,2,//第三列
0,0, 1,1, 2,2,//正对角线
0,2, 1,1, 2,0//反对角线
};
/*********************************************************************************************************/
int find(int value) {
for (int i = 0; i < 8; i++) {//step1:对8种制胜的情况进行遍历
int s = 0;//用于记录3个位置的标记情况
for (int j = 0; j < 3; j++) {//step2:对每种情况中的3个可能位置进行遍历
int H = Key[i][j][0];//行坐标
int L = Key[i][j][1];//列坐标
s += map[H][L];
}
if (s == value) {//判断结果
return i;
}
} return -1;
}
/*********************************************************************************************************/
void gameInit() {
//创建游戏窗口并设计大小
initgraph(654,654);//宽度和高度
//构建背景
loadimage(0,"S_game4.png");
loadimage(&imgMan, "Man.png");
loadimage(&imgAI, "AI.png");
//初始化棋盘
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
map[i][j] = 0;
}
}
srand(time(NULL));
}
/*********************************************************************************************************/
//用户下棋
void manGo(MOUSEMSG*msg) {
int H = msg->y / 218; //行
int L = msg->x /218; //列
//判断用户所选位置是否有棋子
if (map[H][L] == 0) {
map[H][L] = Man;//将该位置标记为用户使用
//设置坐标,将标记呈现在所在行列
int x = L * 218 +10;
int y = H * 218 +10;
//使用putimage画图
putimage(x,y,&imgMan);
}
}
/*********************************************************************************************************/
//AI下棋
void aiGo() {
int step = 0;
int H, L;
/*********************************************************************************************************
* 判断哪些位置已经被选择,并记录总共所走的步数
* 遍历数组map的9个位置,确定哪些位置已经被占用
/*********************************************************************************************************/
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (map[i][j]) {
step++;
}
}
}
/*********************************************************************************************************
* 如果step=0,说明棋盘中没有位置被选中,只需要等待用户选择即可
* 井字棋最佳位置时中心位置,其次是四个顶角位置
/*********************************************************************************************************/
if (step == 1) {
//判断中间位置是否有棋子
if (map[1][1] == 0) {
H = 1;
L = 1;
}//将棋子位置放在中间
else {
H = 0;
L = 2;
}//将棋子位置放在四个顶角之一的位置
}
/*********************************************************************************************************
* 当step=2时,对可能出现的情况进行分析
/**********************************************************************************************************/
else {
int i = find(-2);
//当返回值后,i<0,证明没有找到使得AI一举获胜的情况
if (i < 0) {
i = find(2);//对用户情况的判断
}
if (i >= 0)//说明用户有获胜的可能
{
//在第i条路径上的空白位置落子(每条路径有三个位置)
for (int j = 0; j < 3; j++) {
int H1 = Key[i][j][0];//确定获胜路径中的横坐标
int L1 = Key[i][j][1];//确定获胜路径中的纵坐标
if (map[H1][L1] == 0) {//将棋子放在获胜路径中的空位置,实现阻止用户获胜
H = H1;
L = L1;
break;//已经找到位置,终止循环
}
}
}
/*********************************************************************************************************/
else//用户不能一举获胜的情况,棋子位置随意
{
while (1) {
H = rand() % 3;//产生小于3的随机数,赋给行坐标
L = rand() % 3;//产生小于3的随机数,赋给列坐标
if (map[H][L] == 0) {
break;//棋子填入空位置,终止循环
}
}
}
}
putimage(L * 218 + 15, H* 218 + 15, &imgAI);//将标记放在AI所选位置
map[H][L] = AI;//将-1给当前坐标,表明该位置已经被占用
}
/*********************************************************************************************************/
//定义布尔型函数,检查结果
bool check() {
int i = find(3);
//用户获胜
Sleep(250);//保证每次操作都有间歇期
if (i >= 0)
{
loadimage(0, "WIN2.png");
system("pause");
//对地图进行初始化,实现新游戏
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
map[i][j] = 0;
}
}
loadimage(0, "S_game4.png");//地图重加载
return true;
}
/*********************************************************************************************************/
//AI获胜
i = find(-3);
Sleep(250);//保证每次操作都有间歇期
if(i>=0){
loadimage(0, "Defeat.png");
system("pause");
//对地图进行初始化,实现新游戏
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
map[i][j] = 0;
}
}
loadimage(0, "S_game4.png");//地图重加载
return true;
}
/*********************************************************************************************************/
//平局情况 地图上面没有空余位置
int count = 0;//用于统计map数组中是否含有0
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (map[i][j] == 0) {
count++;
}
}
}
if (count == 0)//count=0说明棋盘中没有空余位置
{
loadimage(0, "Ping.png");
system("pause");
//对地图进行初始化,实现新游戏
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
map[i][j] = 0;
}
}
loadimage(0, "S_game4.png");//地图重加载
return true;
}
return false;
}
/*********************************************************************************************************/
int main(void) {
//初始化
gameInit();//用于构建游戏所需要的条件
//游戏的主循环
//设置游戏背景音乐
mciSendString("open 井字游戏.mp3 alias bkmusic", NULL, 0, NULL);
mciSendString("play bkmusic repeat", NULL, 0, NULL);//循环播放音乐
while (1) {
//开始下棋
MOUSEMSG msg= GetMouseMsg();//定义MOUSEMSG类型的变量,获取用户鼠标信息
//判断鼠标信息类型
if (msg.uMsg == WM_LBUTTONDOWN) {//WM_LBUTTONDOWN 鼠标左键按下
//用户下棋
manGo(&msg);
//判断结果
if (check()) {
continue;//如果胜利,跳过循环
};
//电脑下棋
aiGo();
check();
}
}
system("pause");//设置暂停,使窗口停留
return 0;
}
/*********************************************************************************************************/