今天小编带领大家学一学C语言入门必写的五子棋项目,题目非常经典,值得一学。
目录
能做出一个图形界面,能先下黑棋,后下白棋,能判断输赢,判断输赢后不会再下棋,会显示棋子赢的信息提示。
- 5*15条边,(15条边中间14个格子+左留白0.5+右留白0.5),一共15个格子,一个格子像素40
- 窗口的大小 15*40=600(x) 600(y)
- 在第4,12线交界点需要画黑点
- 在第8线交界点需要画黑点
- loadimage:用于从文件中读取图像。加载图片
- putimage:显示图片
- setlinecolor();
- line:画线,需要两点坐标
- setfillcolor:设置填充颜色
- fillcircle:画填充(实心)圆,参数为坐标,半径
- getmessage:获取鼠标消息
- outtextxy:在指定位置(坐标)输出字符串
- settextcolor:设置字体颜色
- settextstyle:设置字体样式
棋子分为黑白棋,双方对弈时要将棋子下到交叉点处。
棋盘的每一个交叉点位置设置为三种状态:
0表示没有棋子,1表示黑子,2表示白子。
定义一个全局的二维数组,int pieceArr[NUM][NUM] = { 0 };用来记录棋子的情况
int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子
定义棋盘的线的数量与棋子个数。
- #define NUM 15 //15条线
- #define WIN_NUM 5//五子棋
棋盘有竖线15条,横线15条。在第4,12线交界点需要画黑点,在第8线交界点需要画黑点。
vs编译器是无法直接加载出图形界面,需要两个软件:
如果还不知道的小伙伴可以去看一下前篇文章,这里就不多赘述。
首先要自己打开画图板,选择一种自己喜欢的颜色,涂好后保存。
保存图片。
点击五子棋项目,打开所在文件夹。并复制粘贴过去。
然后点击查看EasyX的帮助手册
最后就加载好背景图片了。
Draw_line();//画线
- void Draw_line()
- {
- setlinecolor(BLACK);
- //画竖线
- for (int x = 20; x < 600; x += 40)
- line(x, 20, x, 580);
- //画横线
- for (int y = 20; y < 600; y += 40)
- line(20, y, 580, y);
- }
运行结果如下:
Draw_point();//画点
找到函数fillcircle,有三个参数,圆心坐标(x,y),半径大小。
- 画点
- void Draw_point()
- {
- setfillcolor(BLACK); //把线的颜色弄成黑色
- fillcircle(140, 140, 5), //坐标+半径
- fillcircle(140, 460, 5);
- fillcircle(460, 140, 5);
- fillcircle(460, 460, 5);
- fillcircle(300, 300, 5);
- }
效果是这样的
找到ExMessage,这个东西是用来保存鼠标消息的,是一个结构体。
还有一个getmessage,用来获取鼠标消息。
我们再写一个死循环,用来给鼠标一直下棋,直到有一方获胜。
- while (1)
- {
- m = getmessage(EX_MOUSE);
- if (m.message == WM_LBUTTONDOWN) //如果访问的是鼠标向下,那么就画一个棋子
- {
- //画一个棋子
- //未完...
- }
-
- }
那么,鼠标可以获取消息了,那么怎么画棋子呢?
要解决的问题:
- 如何先下黑棋,然后再下白棋呢?
- 如何把棋子下到线与线交叉的位置?而不下到其它的位置呢?
- 如何才能再下另一颗棋子时不覆盖先前下好的棋子呢?
定义一个bool类型,如果是黑棋就为真
bool black = true;//黑子先下
一开始,我们是用像素定义图像的大小,现在我们要把他换算为下标,即一个二维数组的下标,
定义一个全局的二维数组,int pieceArr[NUM][NUM] = { 0 };用来记录棋子的情况,0表示没有棋
子,1表示黑子,2表示白子。
- void Draw_piece(bool black, int x, int y)
- {
- //计算棋盘中的坐标
- int i = x / 40;
- int j = y / 40;
-
- if (black)//黑子
- {
- setfillcolor(BLACK);
- pieceArr[i][j] = 1; //黑棋为1
- }
- else //白子
- {
- setfillcolor(WHITE);
- pieceArr[i][j] = 2; //白棋为2
- }
- fillcircle(20 + i * 40, 20 + j * 40, 15); //画一个圆(x,y,半径)
- }
定义一个好位置函数bool NicePos(int x, int y),如果这个位置是0,那么代表没有下过棋子,可以继续下,否则就不可以。
- //判断这个位置是否有其他棋子
- bool NicePos(int x, int y)
- {
- //计算棋盘中的坐标
- int i = x / 40;
- int j = y / 40;
- return pieceArr[i][j] == 0;
- }
定义一个Gameover函数,int GameOver(int x, int y)
如果为0,游戏继续;
如果为1,黑棋赢;
如果为2,白棋赢;
我们可以暴力地遍历整个二维数组,看有没有5个棋子是连在一起的,如果有,那么游戏结束。这样也行,但是时间会慢一些。
我们最优的解法是:
只需要判断刚才下的棋子是否为5个即可
判断行,列,45度和135度斜线
定义一个n,用来保存棋子的颜色,如果为0则游戏继续。
定义一个计数器count,如果碰到一个棋子与自己一样,那么就++。
我们需要判断四个方向,每个方向都要用一个for循环,如果与自己一样,那么计数器++,如果计数器大于等于5,那么就返回n。
- //判断游戏胜利
- int GameOver(int x, int y)
- {
- x = x / 40;//换算为下标
- y = y / 40;//换算为下标
-
- int n = pieceArr[x][y];//得到棋子颜色
- if (n == 0)
- return 0;
-
- int count = 0;//统计棋子的数量
-
- int i, j; //当前棋子的前面或后面,或上面或下面,或斜向上或斜向下
-
-
- //同行的棋子
- for (i = x; i >= 0 && pieceArr[i][y] == n; i--)//同行的前面有没有相同的
- count++;
- for (i = x + 1; i < NUM && pieceArr[i][y] == n; i++)//同行的后面有没有相同的
- count++;
- if (count >= WIN_NUM)
- return n;
-
-
- //同列的棋子
- count = 0;//重新计算
- for (j = y; j >= 0 && pieceArr[x][j] == n; j--)//同列的上面有没有相同的
- count++;
- for (j = y + 1; j < NUM && pieceArr[x][j] == n; j++)
- count++;
- if (count >= WIN_NUM)
- return n;
-
-
- //45度的棋子
- count = 0;//重新计算
- for (i = x, j = y; i < NUM && j >= 0 && pieceArr[i][j] == n; i++, j--)//右上
- count++;
- for (i = x - 1, j = y + 1; i >= 0 && j < NUM && pieceArr[i][j] == n; i--, j++)//左下
- count++;
- if (count >= WIN_NUM)
- return n;
-
-
- //135度的棋子
- count = 0;
- for (i = x, j = y; i >= 0 && j >= 0 && pieceArr[i][j] == n; i--, j--)//左上
- count++;
- for (i = x + 1, j = y + 1; i < NUM && j < NUM && pieceArr[i][j] == n; i++, j++)//右下
- count++;
- if (count >= WIN_NUM)
- return n;
-
- return 0;
- }
对x,y分别对40做取模运算就可以转换为下标了。
使用这些函数函数outtextxy,settextstyle,outtextxy,具体内容读者可以自己查看手册。
- while (1)
- {
- m = getmessage(EX_MOUSE);
- if (m.message == WM_LBUTTONDOWN)
- {
- if (NicePos(m.x, m.y))
- {
- Draw_piece(black, m.x, m.y);
- int n = GameOver(m.x, m.y);
- if (n == 1)//黑子赢
- {
- settextcolor(RED);//字体颜色
- settextstyle(36, 0, _T("Consolas"));//字体样式
- outtextxy(250, 0, _T("黑棋赢了")); //输出文字内容
- break;
- }
- else if (n == 2)//白子赢
- {
- settextcolor(RED);
- settextstyle(36, 0, _T("Consolas"));
- outtextxy(250, 0, _T("白棋赢了"));
- break;
- }
- black = !black;
- }
- }
- }
- #define _CRT_SECURE_NO_WARNINGS//这一句必须放在第一行
- #include
// 引用图形库头文件 - #include
- ///*
- //* * 15*15条边,(15条边中间14个格子+左留白0.5+右留白0.5),一共15个格子,一个格子像素为40
- //* 则窗口的大小 15*40=600(x) 600(y)
- //* //在第4,12线交界点需要画黑点
- 在第8线交界点需要画黑点
- //* loadimage:用于从文件中读取图像。加载图片
- //* putimage:显示图片
- //* setlinecolor();
- //* line:画线,需要两点坐标
- //* setfillcolor:设置填充颜色
- //* fillcircle:画填充(实心)圆,参数为坐标,半径
- //* getmessage:获取鼠标消息
- //* outtextxy:在指定位置(坐标)输出字符串
- //* settextcolor:设置字体颜色
- //* settextstyle:设置字体样式
- //*
- //*/
- #define NUM 15
- #define WIN_NUM 5//五子棋
-
- int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子
-
- void Draw_line()
- {
- setlinecolor(BLACK);
- //画竖线
- for (int x = 20; x < 600; x += 40)
- line(x, 20, x, 580);
- //画横线
- for (int y = 20; y < 600; y += 40)
- line(20, y, 580, y);
- }
-
- //画点
- void Draw_point()
- {
- setfillcolor(BLACK);
- fillcircle(140, 140, 5),
- fillcircle(140, 460, 5);
- fillcircle(460, 140, 5);
- fillcircle(460, 460, 5);
- fillcircle(300, 300, 5);
- }
-
- void Draw_piece(bool black, int x, int y)
- {
- //计算棋盘中的坐标
- int i = x / 40;
- int j = y / 40;
-
- if (black)//黑子
- {
- setfillcolor(BLACK);
- pieceArr[i][j] = 1; //黑棋为1
- }
- else //白子
- {
- setfillcolor(WHITE);
- pieceArr[i][j] = 2; //白棋为2
- }
- fillcircle(20 + i * 40, 20 + j * 40, 15); //画一个圆(x,y,半径)
- }
-
- //判断这个位置是否有其他棋子
- bool NicePos(int x, int y)
- {
- //计算棋盘中的坐标
- int i = x / 40;
- int j = y / 40;
- return pieceArr[i][j] == 0;
- }
-
- //0:游戏继续,1:黑子赢; 2:白子赢
- //只需要判断刚才下的棋子是否为5个即可
- //判断行,列,45度和135度斜线
-
-
- //判断游戏胜利
- int GameOver(int x, int y)
- {
- x = x / 40;//换算为下标
- y = y / 40;//换算为下标
- int n = pieceArr[x][y];//得到棋子颜色
- if (n == 0)
- return 0;
- int count = 0;//统计棋子的数量
- int i, j; //当前棋子的前面或后面,或上面或下面,或斜向上或斜向下
-
- //同行的棋子
- for (i = x; i >= 0 && pieceArr[i][y] == n; i--)//同行的前面有没有相同的
- count++;
- for (i = x + 1; i < NUM && pieceArr[i][y] == n; i++)//同行的后面有没有相同的
- count++;
- if (count >= WIN_NUM)
- return n;
-
- //同列的棋子
- count = 0;//重新计算
- for (j = y; j >= 0 && pieceArr[x][j] == n; j--)//同列的上面有没有相同的
- count++;
- for (j = y + 1; j < NUM && pieceArr[x][j] == n; j++)
- count++;
- if (count >= WIN_NUM)
- return n;
-
- //45度的棋子
- count = 0;//重新计算
- for (i = x, j = y; i < NUM && j >= 0 && pieceArr[i][j] == n; i++, j--)//右上
- count++;
- for (i = x - 1, j = y + 1; i >= 0 && j < NUM && pieceArr[i][j] == n; i--, j++)//左下
- count++;
- if (count >= WIN_NUM)
- return n;
-
- //135度的棋子
- count = 0;
- for (i = x, j = y; i >= 0 && j >= 0 && pieceArr[i][j] == n; i--, j--)//左上
- count++;
- for (i = x + 1, j = y + 1; i < NUM && j < NUM && pieceArr[i][j] == n; i++, j++)//右下
- count++;
- if (count >= WIN_NUM)
- return n;
-
- return 0;
- }
-
- int main()
- {
- initgraph(600, 600); // 创建绘图窗口,大小为 600x600 像素
-
- loadimage(NULL, _T("2.png")); //加载图片
-
- Draw_line();//画线
-
- Draw_point();//画点
-
- ExMessage m;//鼠标消息 ExMessage是一个结构体
-
- bool black = true;//黑子先下
-
- while (1)
- {
- m = getmessage(EX_MOUSE);
- if (m.message == WM_LBUTTONDOWN)
- {
- if (NicePos(m.x, m.y))
- {
- Draw_piece(black, m.x, m.y);
- int n = GameOver(m.x, m.y);
- if (n == 1)//黑子赢
- {
- settextcolor(RED);//字体颜色
- settextstyle(36, 0, _T("Consolas"));//字体样式
- outtextxy(250, 0, _T("黑棋赢了")); //输出文字内容
- break;
- }
- else if (n == 2)//白子赢
- {
- settextcolor(RED);
- settextstyle(36, 0, _T("Consolas"));
- outtextxy(250, 0, _T("白棋赢了"));
- break;
- }
- black = !black;
- }
- }
- }
- _getch(); // 按任意键继续
- closegraph(); // 关闭绘图窗口
- return 0;
- }
-
观众老爷可以先把这一段代码拿去当模板,一点一点尝试去写,错了不要紧,代码就是一点一点改出来的,表示说一下子就可以写好。失败是成功之母,错误是正确他爹。慢慢来嘛。
- #include
// 引用图形库头文件 - #include
-
- #define NUM 15
- #define WIN_NUM 5//五子棋
-
- int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子
-
- //画线
- void Draw_line()
-
- //画点
- void Draw_point()
-
- //判断这个位置是否有其他棋子
- bool NicePos(int x, int y)
-
- //判断游戏胜利
- int GameOver(int x, int y)
-
- int main()
- {
- initgraph(600,600); // 创建绘图窗口,大小为 640x480 像素
-
- // 读取图片至绘图窗口
- loadimage(NULL, _T("2.png"));
-
- //画线
- Draw_line();
-
- //画点
- Draw_point();
-
- //鼠标消息
- ExMessage m; //结构体m ,用与存放鼠标消息
-
- //黑子先下
- bool black = true;//黑子先下
-
- _getch(); // 按任意键继续
- closegraph(); // 关闭绘图窗口
- return 0;
- }
创作不易, 如果这份博客👍对你有帮助,可以给博主一个免费的点赞以示鼓励。
欢迎各位帅哥美女点赞👍评论⭐收藏,谢谢!!!
如果有什么疑问或不同的见解,欢迎在评论区留言哦👀。
祝各位生活愉快⭐