目录
1.主函数
2.主菜单的打印(图形化界面的学习)
3.棋盘的打印
4.PVP部分
5.复盘部分(文件操作的学习)
6.AI部分(计分法的学习)
7.PVE部分
8.EVE部分
1.主函数:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<windows.h> #include<time.h> #include<graphics.h> #include<stdlib.h> int r[4][4] = { { 241,180,515,226 }, {241,230,460,276},{241,282,460,333 }, {285,386,460,424 } }; int flag = 0; int flag3 = 0; int count = 0; int arr[16][16] = { 0 }; int score[16][16] = { 0 }; int ret = 0; int r1[4] = { 530,30,660,75 }; int r4[4] = { 530,200,680,250 }; int r5[4] = { 530,260,640,300 }; int r6[4] = { 530,320,640,350 }; int r7[4] = { 530,380,640,410 }; RECT R1 = { r1[0], r1[1], r1[2], r1[3] };//矩阵指针 RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; RECT R5 = { r5[0], r5[1], r5[2], r5[3] }; RECT R6 = { r6[0], r6[1], r6[2], r6[3] }; RECT R7 = { r7[0], r7[1], r7[2], r7[3] }; int main() { menu(); return 0; }
在主函数中我们引出了menu菜单,方便菜单的打印。在主函数之前我们引用了很多全局变量,在后面的函数中都会用到。
2.主菜单的打印(图形化界面的学习)
void menu() { initgraph(520, 550);//初始化界面 IMAGE back;//定义图片接收 loadimage(&back, _T("背景图片.png"));//接收图片 putimage(0, 0, &back);//输出图片
这里我们需要将图片导入,首先要将我们的exe框的大小初始化一下,随后将图片导入并接收,需要注意的是我们要将导入的图片的名字与loadimage()里的名字保存一致哦。
putimage里的(0,0)表示的是从(0,0)起始坐标开始放图片。
图片的原图在这,需要的老铁们可以自取。
运行后的结果是这样的:
接下来我们要像在游戏中用鼠标选择“开始游戏”一样,这里就涉及到到鼠标的操作和按钮跳转的操作。
MOUSEMSG m;//鼠标指针 while (1) { m = GetMouseMsg();//获取一条鼠标消息 if (m.uMsg == WM_LBUTTONDOWN)//当鼠标落下时 { switch (button_judge(m.x, m.y)) { case 0: break; case 1: closegraph(); PVE(); break; case 2: closegraph(); EVE(); break; case 3: closegraph(); PVP(); break; case 5: closegraph(); exit(0); } } } }
要获得鼠标消息首先要用MOUSEMSG获得鼠标指针,用while(1)循环进行选择。那么我们是如何选择操作的呢?
我们用m获取鼠标消息,我们用m.uMsg == WM_LBUTTONDOWN判断是否是鼠标的左击也就是点击。当我们鼠标在exe上面左击一个地方就会保存他的坐标(m.x,m.y)。要想选择操作,就要判断鼠标点击的地方在哪个选项的矩形边框内,是选择人机对战,还是人人对战还是退出游戏都是通过鼠标的左击完成。
注意这里的图片上的文字是我在ps上写入的,人机对战,机器对战,人人对战矩形的坐标我们是通过画图软件来观察他的像素坐标的。这里的二位数组就是我们定义的全局变量。
我们的鼠标只要点击在该矩形边框内,就会选择该模式。
随后我们用一个按钮函数来根据选择的位置选择相应的游戏。
int button_judge(int x, int y)//判断点击的是哪个按钮 { if (x > r[0][0] && x<r[0][2] && y>r[0][1] && y < r[0][3]) return 1;//人机 if (x > r[1][0] && x<r[1][2] && y>r[1][1] && y < r[1][3]) return 2;//机器 if (x > r[2][0] && x<r[2][2] && y>r[2][1] && y < r[2][3]) return 3;//人人对战 if (x > r[3][0] && x<r[3][2] && y>r[3][1] && y < r[3][3]) return 5;//退出 return 0; }
3.棋盘的打印
void print_board() { initgraph(800, 525); //贴图 IMAGE back1;//定义图片接收 loadimage(&back1, _T("棋盘.png"));//接收图片 putimage(0, 0, &back1);//输出图片 int i = 0; for (i = 15; i <= 542; i += 32) { line(i, 5, i, 517); } for (i = 5; i <= 525; i += 32) { line(15, i, 527, i); } //将边框画粗 line(16, 5, 16, 517); line(528, 5, 528, 517); line(15, 6, 527, 6); line(15, 518, 527, 518); }
一样的,我们将我们的这张图片导入exe中。
在画图软件中我们可以知道图片的长和宽,这里我们要打印15*15的棋盘,就要通过计算,算出需要我们话的线的数量和长度。这里的line()函数放的是两个横纵坐标,代表一条线,我们最后将边框重新画了一遍,就是为了将其边框加粗。
//绘制矩阵 fillrectangle(r7[0], r7[1], r7[2], r7[3]); setbkmode(TRANSPARENT);//设置透明文字背景 settextcolor(BLACK);//设置字体颜色 setfillcolor(WHITE); drawtext(_T("退出"), &R7, DT_CENTER | DT_VCENTER | DT_SINGLELINE); fillrectangle(r1[0], r1[1], r1[2], r1[3]); drawtext(_T("返回主菜单"), &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
这里我们是在图片上绘制矩形边框并且在图片上打印文字,fillrectangle内的分别代表矩形左上角和右下角的坐标,正好四个数字就可以画出该矩形。同时我们要将背景设为透明,不然文字会被图片覆盖,随后设置文字的颜色。实际效果是这样的:
4.PVP部分:
接下来就到我们的人人对战代码的书写,首先我们将二位数组初始化,再在棋盘上打印一个矩形边框方便提示用户下棋。
void PVP() { memset(arr, 0, sizeof(int[16][16])); print_board(); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); int x = 0, y = 0; int a, b, i, j; flag = 0; count = 0;
同样的我们保存鼠标的消息,因为我们要将棋子下在格子上而不是乱下,所以我们要将我们下棋的位置四舍五入到最近的格子上。
MOUSEMSG m;//保存鼠标消息 while (1) { m = GetMouseMsg(); for (i = 1; i < 16; i++) { for (j = 1; j < 16; j++) { if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16) { x = i * 32 + 15; y = j * 32 + 5; a = i; b = j; } } }
当然,为了防止越界,我们用MessageBox提示用户是否越界并判断玩家所下位置是否有棋,提示以后玩家重新下棋,用continue继续循环。
if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } if (arr[a][b]) { MessageBox(NULL, "这里已经有了", "提示", MB_OK); continue; } if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527) { MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK); continue; }
我们先让黑方下棋,初始化flag=0,如果flag为偶数,则下黑棋,为奇数下白棋,每次flag++即可。下棋的话我们用solidcircle就可以画出一个圆形棋子,当然,画棋子之前要用setfillcolor规定棋子的颜色!每一个棋子下完以后要在我们的二维数组内,黑棋用1表示,白棋用2表示。在每次下一个棋之后,我们还要判断输赢。
if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示 setfillcolor(BLACK); solidcircle(x, y, 12); flag++; count++; arr[a][b] =1; ret = is_win(arr, count); if (ret) { judge_winPVP(ret); break; } } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); setfillcolor(WHITE); solidcircle(x, y, 12); arr[a][b] = 2; flag++; count++; ret = is_win(arr, count); if (ret) { judge_winPVP(ret); break; } } } }
判断输赢的函数有两个
int is_win(int arr[16][16], int count) { int i = 0; int j = 0; //竖行 for (i = 1; i < 16; i++) { for (j = 1; j < 12; j++) { if (arr[i][j] == arr[i][j + 1] && arr[i][j + 1] == arr[i][j + 2] && arr[i][j + 2] == arr[i][j + 3] && arr[i][j + 3] == arr[i][j + 4] && arr[i][j] != 0) return arr[i][j]; } } //横行 for (j = 1; j < 16; j++) { for (i = 1; i < 12; i++) { if (arr[i][j] == arr[i + 1][j] && arr[i + 1][j] == arr[i + 2][j] && arr[i + 2][j] == arr[i + 3][j] && arr[i + 3][j] == arr[i + 4][j] && arr[i][j] != 0) return arr[i][j]; } } //右下 for (j = 1; j < 12; j++) { for (i = 1; i < 12; i++) { if (arr[i][j] == arr[i + 1][j + 1] && arr[i + 1][j + 1] == arr[i + 2][j + 2] && arr[i + 2][j + 2] == arr[i + 3][j + 3] && arr[i + 3][j + 3] == arr[i + 4][j + 4] && arr[i][j] != 0) return arr[i][j]; } } //左下 for (i = 1; i < 12; i++) { for (j = 15; j > 4; j--) { if (arr[i][j] == arr[i + 1][j - 1] && arr[i + 1][j - 1] == arr[i + 2][j - 2] && arr[i + 2][j - 2] == arr[i + 3][j - 3] && arr[i + 3][j - 3] == arr[i + 4][j - 4] && arr[i][j] != 0) return arr[i][j]; } } //平局 if (count == 225) return 4; return 0; }
这里我们返回存入arr数组里的值,随后在判断输赢的函数里判断输赢。
void judge_winPVP(int t) { if (t == 1) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("黑棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 2) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("白棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 4) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } setfillcolor(WHITE); fillrectangle(r6[0], r6[1], r6[2], r6[3]); drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE); }
一局结束以后,我们要选择是返回主菜单还是复盘还是退出该游戏,所以我们要继续用鼠标做出选择。
while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanPVP(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } }
像这样,一局PVP就下完了。
5.复盘部分(文件操作的基本学习)
留心的老铁应该会发现复盘这一操作,我们如何让一局下过的棋重新复盘一遍呢,这就需要文件操作的知识了。
FILE* file = fopen("PVP.txt", "w"); fclose(file); FILE* fq = fopen("PVP.txt", "a+");
这里我们将txt文件以写的形式打开,之前txt内的数据就会全部删除,随后我们再以追加的方式读入数据。
我们在将棋子存入二维数组以后,再将他存入文件中。
//黑棋: arr[a][b] = 1; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b); //白棋 arr[a][b] = 2; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b);
复盘函数:
void fupanPVP() { int a, b; int r4[4] = { 530,200,680,250 }; RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; flag = 0; count = 0; print_board(); FILE* fq = fopen("PVP.txt", "a+"); memset(arr, 0, sizeof(int[16])); while (fscanf_s(fq, "%d %d ", &a, &b) == 2) { if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示 setfillcolor(BLACK); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 1; } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); setfillcolor(WHITE); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 2; } Sleep(500); } ret = is_win(arr, count); judge_winPVP(ret); }
同样的我们以a+追加的方式读入数据,用fscanf()读入数据,存入二维数组,在exe界面上进行一定的操作画棋子,判断输赢等操作与PVP一样,不同的是我们要用Sleep函数使下棋有时间的停顿,这样才可以更真实。
6.AI部分
计算每个空白的落子点的“权值”,然后再权值最大的点落子
以后,可以在这个基础之上,实现多个层次的计算.
对于每个空白点,分别计算周围的八个方向
为了使AI更智能,在计算分数时,电脑可以先假设对方下这个点时的结果来先打个分,随后在假设电脑自己下这个位置的结果来打个分。这里我们假设玩家下黑棋,电脑下白棋,
选择轮到电脑下棋。
void computer(int arr[16][16]) { int i, x, y, k, r, c; int persennum = 0; int ainum = 0; int emptynum = 0; memset(score, 0, sizeof(int[16][16])); for (r = 1; r < 16; r++) { for (c = 1; c < 16; c++) { if (arr[r][c] == 0) { int direction[4][2] = { {1,0},{1,1},{0,1},{-1,1} }; //规定正方向 for (k = 0; k < 4; k++) { x = direction[k][0]; y = direction[k][1]; //遍历不同方向 //清空积分器 persennum = 0; ainum = 0; emptynum = 0; //预测人下棋的分数(防御) // //正向 for (i = 1; i <= 4; i++) { if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 2) { persennum++; } //玩家的棋子 else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0) { emptynum++; break; } //空白的棋子 else { break; } } //反向 for (i = 1; i <= 4; i++) { if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 2) { persennum++; } //玩家的棋子 else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0) { emptynum++; break; } //搜索到空白的棋子,停止搜索 else { break; } //搜索到越界的棋子和ai棋子,停止搜索 } //杀二 if (persennum == 1) { score[r][c] += 10; } //杀三 else if (persennum == 2) { //死三 if (emptynum == 1) score[r][c] += 30; //活三 else if (emptynum == 2) score[r][c] += 40; } //杀四 else if (persennum == 3) { //死四 if (emptynum == 1) score[r][c] += 60; //活四 else if (emptynum == 2) score[r][c] += 200; } //杀五 else if (persennum == 4) { score[r][c] += 20000; } //清空 emptynum = 0; //预测ai的分数(进攻) //正向 for (i = 1; i <= 4; i++) { if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 1) { ainum++; } //玩家的棋子 else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0) { emptynum++; break; } //空白的棋子 else { break; } } //反向 for (i = 1; i <= 4; i++) { if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 1) { ainum++; } //玩家的棋子 else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0) { emptynum++; break; } //搜索到空白的棋子,停止搜索 else { break; } //搜索到越界的棋子和ai棋子,停止搜索 } //杀二 if (ainum == 0) { score[r][c] += 5; } if (ainum == 1) { score[r][c] += 10; } //杀三 else if (ainum == 2) { //死三 if (emptynum == 1) score[r][c] += 25; //活三 else if (emptynum == 2) score[r][c] += 50; } //杀四 else if (ainum == 3) { //死四 if (emptynum == 1) score[r][c] += 55; //活四 else if (emptynum == 2) score[r][c] += 300; } //杀五 else if (ainum == 4) { score[r][c] += 999999; } } } } } }
注意:这里我们用全局的二位数组score来保存分数,以便后面寻找最大分数点的操作。
打分的详细表格如下:
将所有的分数存入score数组以后,我们就写一个函数寻找最大的分数。
void find_max(int* x, int* y, int arr[16][16]) { int max = 0; int n = 0; int maxpoint[225][2]; memset(maxpoint, 0, sizeof(int[225][2])); for (int i = 1; i <= 15; i++) { for (int j = 1; j <= 15; j++) { if (arr[i][j] == 0) { if (score[i][j] > max) { max = score[i][j]; *x = i; *y = j; } } } } for (int i = 1; i <= 15; i++) { for (int j = 1; j <= 15; j++) { if (score[i][j] == max) { maxpoint[n][0] = i; maxpoint[n++][1] = j; } } } srand((unsigned int)time(0)); int index = rand() % n; *x = maxpoint[index][0]; *y = maxpoint[index][1]; }
这里值得注意的是,如果我们有几个地方的分数一样并且都是最大,我们就需要电脑随机找一个点下,这样使ai更真实,也让机器对战的每一盘不在一样。(如果不随机下,每一盘棋子可能都会出现一模一样的情况)。我们将所有的最大分数都存起来,再以time为种子生成随机数。
7.PVE部分:
在写完ai部分后我们就可以写我们的人机对战和机器对战了。
与人人不同的是,我们要先确定先后手,即电脑先手还是玩家先手,我们在messagebox提示以后,让用户进行选择。
void PVE() { int x = 0, y = 0; int a = 0, b = 0, i = 0, j = 0; memset(arr, 0, sizeof(int[16][16])); FILE* file = fopen("PVE.txt", "w"); fclose(file); count = 0; FILE* fq = fopen("PVE.txt", "a+"); print_board(); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("电脑先下"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); drawtext(_T("我先下"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); MOUSEMSG m; while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r4[0] && m.x<r4[2] && m.y>r4[1] && m.y < r4[3]) { flag3 = 0; flag = 0; MessageBox(NULL, "电脑先手", "提示", MB_OK); break; } else if (m.x > r5[0] && m.x<r5[2] && m.y>r5[1] && m.y < r5[3]) { flag3 = 1; flag = 1; MessageBox(NULL, "你先手", "提示", MB_OK); break; } else { MessageBox(NULL, "请选择先后", "提示", MB_OK); } } }
选择完后就是人机对战了
while (1) { //机器部分 if (flag == 0) { setfillcolor(BLACK); solidcircle(271, 261, 12); arr[8][8] = 1; flag++; count++; fprintf(fq, "%d ", 8); fprintf(fq, "%d ", 8); } if (flag % 2 == 0) { Sleep(500); computer(arr); find_max(&i, &j,arr); setfillcolor(BLACK); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 1; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(BLACK); drawtext(_T("该你下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winPVE(ret); break; } flag++; count++; } //人的部分 m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { for (i = 1; i < 16; i++) { for (j = 1; j < 16; j++) { if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16) { x = i * 32 + 15; y = j * 32 + 5; a = i; b = j; } } } if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } if (arr[a][b]) { MessageBox(NULL, "这里已经有了", "提示", MB_OK); continue; } if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527) { MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK); continue; } if (flag % 2 == 1) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); solidcircle(x, y, 12); arr[a][b] = 2; flag++; count++; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b); ret = is_win(arr, count); if (ret) { judge_winPVE(ret); break; } } } } fclose(fq); while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanPVE(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } }
这里唯一不同的是在选择电脑先手后我们要帮助电脑在棋盘正中间下一个棋子,其他的与人人对战相似,ai部分也在上面做过讲解,就不在赘述。
8.EVE部分:
机器对战就是两个ai对战,所以我们就让我们之前写的两个ai互相下棋即可。
void EVE() { int x = 0, y = 0; int a = 0, b = 0, i = 0, j = 0; flag = 0; count = 0; memset(arr, 0, sizeof(int[16][16])); FILE* file = fopen("EVE.txt", "w"); fclose(file); FILE* fq = fopen("EVE.txt", "a+"); print_board(); MOUSEMSG m; while (1) { //机器部分 if (flag == 0) { setfillcolor(BLACK); solidcircle(271, 261, 12); arr[8][8] = 1; flag++; count++; fprintf(fq, "%d ", 8); fprintf(fq, "%d ", 8); } //玩家一 if (flag % 2 == 0) { Sleep(310); computer(arr); find_max(&i, &j,arr); setfillcolor(BLACK); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 1; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("P2下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winEVE(ret); break; } flag++; count++; } //P2: if (flag % 2 == 1) { Sleep(310); computer(arr); find_max(&i, &j,arr); setfillcolor(WHITE); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 2; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("P1下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winEVE(ret); break; } flag++; count++; } } fclose(fq); while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanEVE(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } }
完整代码:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<windows.h> #include<time.h> #include<graphics.h> #include<stdlib.h> void menu(); //全局变量 int r[4][4] = { { 241,180,515,226 }, {241,230,460,276},{241,282,460,333 }, {285,386,460,424 } }; int flag = 0; int flag3 = 0; int count = 0; int arr[16][16] = { 0 }; int score[16][16] = { 0 }; int ret = 0; int r1[4] = { 530,30,660,75 }; int r4[4] = { 530,200,680,250 }; int r5[4] = { 530,260,640,300 }; int r6[4] = { 530,320,640,350 }; int r7[4] = { 530,380,640,410 }; RECT R1 = { r1[0], r1[1], r1[2], r1[3] };//矩阵指针 RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; RECT R5 = { r5[0], r5[1], r5[2], r5[3] }; RECT R6 = { r6[0], r6[1], r6[2], r6[3] }; RECT R7 = { r7[0], r7[1], r7[2], r7[3] }; void find_max(int* x, int* y, int arr[16][16]) { int max = 0; int n = 0; int maxpoint[225][2]; memset(maxpoint, 0, sizeof(int[225][2])); for (int i = 1; i <= 15; i++) { for (int j = 1; j <= 15; j++) { if (arr[i][j] == 0) { if (score[i][j] > max) { max = score[i][j]; *x = i; *y = j; } } } } for (int i = 1; i <= 15; i++) { for (int j = 1; j <= 15; j++) { if (score[i][j] == max) { maxpoint[n][0] = i; maxpoint[n++][1] = j; } } } srand((unsigned int)time(0)); int index = rand() % n; *x = maxpoint[index][0]; *y = maxpoint[index][1]; } int button_judge(int x, int y)//判断点击的是哪个按钮 { if (x > r[0][0] && x<r[0][2] && y>r[0][1] && y < r[0][3]) return 1;//人机 if (x > r[1][0] && x<r[1][2] && y>r[1][1] && y < r[1][3]) return 2;//机器 if (x > r[2][0] && x<r[2][2] && y>r[2][1] && y < r[2][3]) return 3;//rr if (x > r[3][0] && x<r[3][2] && y>r[3][1] && y < r[3][3]) return 5;//退出 return 0; } void judge_winPVP(int t) { if (t == 1) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("黑棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 2) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("白棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 4) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } setfillcolor(WHITE); fillrectangle(r6[0], r6[1], r6[2], r6[3]); drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } void judge_winPVE(int t) { if (t == 1) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("电脑胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 2) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("你胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 4) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } setfillcolor(WHITE); fillrectangle(r6[0], r6[1], r6[2], r6[3]); drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } void judge_winEVE(int t) { if (t == 1) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("P1胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 2) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("P2胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else if (t == 4) { setfillcolor(WHITE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); setfillcolor(RED); drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } setfillcolor(WHITE); fillrectangle(r6[0], r6[1], r6[2], r6[3]); drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } int is_win(int arr[16][16], int count) { int i = 0; int j = 0; //竖行 for (i = 1; i < 16; i++) { for (j = 1; j < 12; j++) { if (arr[i][j] == arr[i][j + 1] && arr[i][j + 1] == arr[i][j + 2] && arr[i][j + 2] == arr[i][j + 3] && arr[i][j + 3] == arr[i][j + 4] && arr[i][j] != 0) return arr[i][j]; } } //横行 for (j = 1; j < 16; j++) { for (i = 1; i < 12; i++) { if (arr[i][j] == arr[i + 1][j] && arr[i + 1][j] == arr[i + 2][j] && arr[i + 2][j] == arr[i + 3][j] && arr[i + 3][j] == arr[i + 4][j] && arr[i][j] != 0) return arr[i][j]; } } //右下 for (j = 1; j < 12; j++) { for (i = 1; i < 12; i++) { if (arr[i][j] == arr[i + 1][j + 1] && arr[i + 1][j + 1] == arr[i + 2][j + 2] && arr[i + 2][j + 2] == arr[i + 3][j + 3] && arr[i + 3][j + 3] == arr[i + 4][j + 4] && arr[i][j] != 0) return arr[i][j]; } } //左下 for (i = 1; i < 12; i++) { for (j = 15; j > 4; j--) { if (arr[i][j] == arr[i + 1][j - 1] && arr[i + 1][j - 1] == arr[i + 2][j - 2] && arr[i + 2][j - 2] == arr[i + 3][j - 3] && arr[i + 3][j - 3] == arr[i + 4][j - 4] && arr[i][j] != 0) return arr[i][j]; } } if (count == 225) return 4; return 0; } void print_board() { initgraph(800, 525); //贴图 IMAGE back1;//定义图片接收 loadimage(&back1, _T("棋盘.png"));//接收图片 putimage(0, 0, &back1);//输出图片 int i = 0; for (i = 15; i <= 542; i += 32) { line(i, 5, i, 517); } for (i = 5; i <= 525; i += 32) { line(15, i, 527, i); } line(16, 5, 16, 517); line(528, 5, 528, 517); line(15, 6, 527, 6); line(15, 518, 527, 518); //绘制矩阵 fillrectangle(r7[0], r7[1], r7[2], r7[3]); setbkmode(TRANSPARENT);//设置透明文字背景 settextcolor(BLACK);//设置字体颜色 setfillcolor(WHITE); drawtext(_T("退出"), &R7, DT_CENTER | DT_VCENTER | DT_SINGLELINE); fillrectangle(r1[0], r1[1], r1[2], r1[3]); drawtext(_T("返回主菜单"), &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } void fupanPVP() { int a, b; int r4[4] = { 530,200,680,250 }; RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; flag = 0; count = 0; print_board(); FILE* fq = fopen("PVP.txt", "a+"); memset(arr, 0, sizeof(int[16])); while (fscanf_s(fq, "%d %d ", &a, &b) == 2) { if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示 setfillcolor(BLACK); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 1; } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); setfillcolor(WHITE); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 2; } Sleep(500); } ret = is_win(arr, count); judge_winPVP(ret); } void fupanPVE() { int a, b; int r4[4] = { 530,200,680,250 }; RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; count = 0; flag = flag3; print_board(); FILE* fq = fopen("PVE.txt", "a+"); memset(arr, 0, sizeof(int[16])); while (fscanf_s(fq, "%d %d ", &a, &b) == 2) { if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 1; } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 2; } Sleep(500); } ret = is_win(arr, count); judge_winPVE(ret); } void fupanEVE() { int a, b; int r4[4] = { 530,200,680,250 }; RECT R4 = { r4[0], r4[1], r4[2], r4[3] }; count = 0; flag = 0; print_board(); FILE* fq = fopen("EVE.txt", "a+"); memset(arr, 0, sizeof(int[16])); while (fscanf_s(fq, "%d %d ", &a, &b) == 2) { if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 1; } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(WHITE); solidcircle(a * 32 + 15, b * 32 + 5, 12); flag++; count++; arr[a][b] = 2; } Sleep(500); } ret = is_win(arr, count); judge_winPVP(ret); } void computer(int arr[16][16]) { int i, x, y, k, r, c; int persennum = 0; int ainum = 0; int emptynum = 0; memset(score, 0, sizeof(int[16][16])); for (r = 1; r < 16; r++) { for (c = 1; c < 16; c++) { if (arr[r][c] == 0) { int direction[4][2] = { {1,0},{1,1},{0,1},{-1,1} }; //规定正方向 for (k = 0; k < 4; k++) { x = direction[k][0]; y = direction[k][1]; //遍历不同方向 //清空积分器 persennum = 0; ainum = 0; emptynum = 0; //预测人下棋的分数(防御) // //正向 for (i = 1; i <= 4; i++) { if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 2) { persennum++; } //玩家的棋子 else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0) { emptynum++; break; } //空白的棋子 else { break; } } //反向 for (i = 1; i <= 4; i++) { if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 2) { persennum++; } //玩家的棋子 else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0) { emptynum++; break; } //搜索到空白的棋子,停止搜索 else { break; } //搜索到越界的棋子和ai棋子,停止搜索 } //杀二 if (persennum == 1) { score[r][c] += 10; } //杀三 else if (persennum == 2) { //死三 if (emptynum == 1) score[r][c] += 30; //活三 else if (emptynum == 2) score[r][c] += 40; } //杀四 else if (persennum == 3) { //死四 if (emptynum == 1) score[r][c] += 60; //活四 else if (emptynum == 2) score[r][c] += 200; } //杀五 else if (persennum == 4) { score[r][c] += 20000; } //清空 emptynum = 0; //预测ai的分数(进攻) //正向 for (i = 1; i <= 4; i++) { if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 1) { ainum++; } //玩家的棋子 else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0) { emptynum++; break; } //空白的棋子 else { break; } } //反向 for (i = 1; i <= 4; i++) { if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 1) { ainum++; } //玩家的棋子 else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0) { emptynum++; break; } //搜索到空白的棋子,停止搜索 else { break; } //搜索到越界的棋子和ai棋子,停止搜索 } //杀二 if (ainum == 0) { score[r][c] += 5; } if (ainum == 1) { score[r][c] += 10; } //杀三 else if (ainum == 2) { //死三 if (emptynum == 1) score[r][c] += 25; //活三 else if (emptynum == 2) score[r][c] += 50; } //杀四 else if (ainum == 3) { //死四 if (emptynum == 1) score[r][c] += 55; //活四 else if (emptynum == 2) score[r][c] += 300; } //杀五 else if (ainum == 4) { score[r][c] += 999999; } } } } } } void PVP() { memset(arr, 0, sizeof(int[16][16])); print_board(); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); int x = 0, y = 0; int a, b, i, j; flag = 0; count = 0; FILE* file = fopen("PVP.txt", "w"); fclose(file); FILE* fq = fopen("PVP.txt", "a+"); MOUSEMSG m;//保存鼠标消息 while (1) { m = GetMouseMsg(); for (i = 1; i < 16; i++) { for (j = 1; j < 16; j++) { if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16) { x = i * 32 + 15; y = j * 32 + 5; a = i; b = j; } } } if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } if (arr[a][b]) { MessageBox(NULL, "这里已经有了", "提示", MB_OK); continue; } if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527) { MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK); continue; } if (flag % 2 == 0) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示 setfillcolor(BLACK); solidcircle(x, y, 12); flag++; count++; arr[a][b] = 1; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b); ret = is_win(arr, count); if (ret) { judge_winPVP(ret); break; } } else { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); setfillcolor(WHITE); solidcircle(x, y, 12); arr[a][b] = 2; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b); flag++; count++; ret = is_win(arr, count); if (ret) { judge_winPVP(ret); break; } } } } fclose(fq); while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanPVP(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } } void PVE() { int x = 0, y = 0; int a = 0, b = 0, i = 0, j = 0; memset(arr, 0, sizeof(int[16][16])); FILE* file = fopen("PVE.txt", "w"); fclose(file); count = 0; FILE* fq = fopen("PVE.txt", "a+"); print_board(); fillrectangle(r4[0], r4[1], r4[2], r4[3]); drawtext(_T("电脑先下"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); fillrectangle(r5[0], r5[1], r5[2], r5[3]); drawtext(_T("我先下"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE); MOUSEMSG m; while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r4[0] && m.x<r4[2] && m.y>r4[1] && m.y < r4[3]) { flag3 = 0; flag = 0; MessageBox(NULL, "电脑先手", "提示", MB_OK); break; } else if (m.x > r5[0] && m.x<r5[2] && m.y>r5[1] && m.y < r5[3]) { flag3 = 1; flag = 1; MessageBox(NULL, "你先手", "提示", MB_OK); break; } else { MessageBox(NULL, "请选择先后", "提示", MB_OK); } } } while (1) { //机器部分 if (flag == 0) { setfillcolor(BLACK); solidcircle(271, 261, 12); arr[8][8] = 1; flag++; count++; fprintf(fq, "%d ", 8); fprintf(fq, "%d ", 8); } if (flag % 2 == 0) { Sleep(500); computer(arr); find_max(&i, &j,arr); setfillcolor(BLACK); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 1; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(BLACK); drawtext(_T("该你下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winPVE(ret); break; } flag++; count++; } //人的部分 m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { for (i = 1; i < 16; i++) { for (j = 1; j < 16; j++) { if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16) { x = i * 32 + 15; y = j * 32 + 5; a = i; b = j; } } } if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } if (arr[a][b]) { MessageBox(NULL, "这里已经有了", "提示", MB_OK); continue; } if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527) { MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK); continue; } if (flag % 2 == 1) { setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); solidcircle(x, y, 12); arr[a][b] = 2; flag++; count++; fprintf(fq, "%d ", a); fprintf(fq, "%d ", b); ret = is_win(arr, count); if (ret) { judge_winPVE(ret); break; } } } } fclose(fq); while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanPVE(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } } void EVE() { int x = 0, y = 0; int a = 0, b = 0, i = 0, j = 0; flag = 0; count = 0; memset(arr, 0, sizeof(int[16][16])); FILE* file = fopen("EVE.txt", "w"); fclose(file); FILE* fq = fopen("EVE.txt", "a+"); print_board(); MOUSEMSG m; while (1) { //机器部分 if (flag == 0) { setfillcolor(BLACK); solidcircle(271, 261, 12); arr[8][8] = 1; flag++; count++; fprintf(fq, "%d ", 8); fprintf(fq, "%d ", 8); } //玩家一 if (flag % 2 == 0) { Sleep(310); computer(arr); find_max(&i, &j,arr); setfillcolor(BLACK); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 1; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("P2下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winEVE(ret); break; } flag++; count++; } //P2: if (flag % 2 == 1) { Sleep(310); computer(arr); find_max(&i, &j,arr); setfillcolor(WHITE); solidcircle(i * 32 + 15, j * 32 + 5, 12); arr[i][j] = 2; fprintf(fq, "%d ", i); fprintf(fq, "%d ", j); setfillcolor(WHITE); fillrectangle(r4[0], r4[1], r4[2], r4[3]); setfillcolor(BLACK); drawtext(_T("P1下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE); ret = is_win(arr, count); if (ret) { judge_winEVE(ret); break; } flag++; count++; } } fclose(fq); while (1) { m = GetMouseMsg(); if (m.uMsg == WM_LBUTTONDOWN) { if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3]) { exit(0); } else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3]) { closegraph(); fupanEVE(); } else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3]) { closegraph(); menu(); } } } } void menu() { initgraph(520, 550);//初始化界面 IMAGE back;//定义图片接收 loadimage(&back, _T("背景图片.png"));//接收图片 putimage(0, 0, &back);//输出图片 MOUSEMSG m;//鼠标指针 while (1) { m = GetMouseMsg();//获取一条鼠标消息 if (m.uMsg == WM_LBUTTONDOWN)//当鼠标落下时 { switch (button_judge(m.x, m.y)) { case 0: break; case 1: closegraph(); PVE(); break; case 2: closegraph(); EVE(); break; case 3: closegraph(); PVP(); break; case 5: closegraph(); exit(0); } } } } int main() { menu(); return 0; }
这篇博客有26000多个字,真的花了我很多时间捏,如果对大家有帮助的话希望多多点赞和关注,谢谢大家啦!我们一起进步啦!