• C语言--五子棋项目【图文详解 经典】


     今天小编带领大家学一学C语言入门必写的五子棋项目,题目非常经典,值得一学。


    目录

     

    一.目标效果

    二.五子棋的元素

    1.棋子

     2.棋盘

     三,需要准备的工具

    四.具体内容

    1.加载背景图片

    2.画横线与竖线

    3. 画小黑点

    4.获取鼠标消息

     5.画棋子

    6.如何判断比赛的输赢(核心)

     9.显示游戏结束的提示

     五.完整代码

     六.运行结果

    ​编辑果

     七.学习时的代码


    一.目标效果🍗

    能做出一个图形界面,能先下黑棋,后下白棋,能判断输赢,判断输赢后不会再下棋,会显示棋子赢的信息提示。

    • 背景知识(先稍微看一下)
    • 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:设置字体样式

    二.五子棋的元素🍗

    1.棋子

     棋子分为黑白棋,双方对弈时要将棋子下到交叉点处。

    棋盘的每一个交叉点位置设置为三种状态:

    0表示没有棋子,1表示黑子,2表示白子。

    定义一个全局的二维数组,int pieceArr[NUM][NUM] = { 0 };用来记录棋子的情况

    int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子

     2.棋盘🍗

     定义棋盘的线的数量与棋子个数。

    1. #define NUM 15 //15条线
    2. #define WIN_NUM 5//五子棋

    棋盘有竖线15条,横线15条。在第4,12线交界点需要画黑点,在第8线交界点需要画黑点。

     三,需要准备的工具🍗

    vs编译器是无法直接加载出图形界面,需要两个软件:

    一.EasyX,图形(加载图形界面)

    二.EasyX_Help( 帮助手册)

    如果还不知道的小伙伴可以去看一下前篇文章,这里就不多赘述。

    http://t.csdnimg.cn/0mnzJ

    四.具体内容🍗

    1.加载背景图片

    首先要自己打开画图板,选择一种自己喜欢的颜色,涂好后保存。

    保存图片。

    点击五子棋项目,打开所在文件夹。并复制粘贴过去。

     然后点击查看EasyX的帮助手册

     

     

     

     最后就加载好背景图片了。


    2.画横线与竖线

    Draw_line();//画线

    1. void Draw_line()
    2. {
    3. setlinecolor(BLACK);
    4. //画竖线
    5. for (int x = 20; x < 600; x += 40)
    6. line(x, 20, x, 580);
    7. //画横线
    8. for (int y = 20; y < 600; y += 40)
    9. line(20, y, 580, y);
    10. }

     运行结果如下:


    3. 画小黑点

    Draw_point();//画点

    找到函数fillcircle,有三个参数,圆心坐标(x,y),半径大小。

    1. 画点
    2. void Draw_point()
    3. {
    4. setfillcolor(BLACK); //把线的颜色弄成黑色
    5. fillcircle(140, 140, 5), //坐标+半径
    6. fillcircle(140, 460, 5);
    7. fillcircle(460, 140, 5);
    8. fillcircle(460, 460, 5);
    9. fillcircle(300, 300, 5);
    10. }

     效果是这样的

     


    4.获取鼠标消息

     找到ExMessage,这个东西是用来保存鼠标消息的,是一个结构体。

     

    还有一个getmessage,用来获取鼠标消息。

     我们再写一个死循环,用来给鼠标一直下棋,直到有一方获胜。

    1. while (1)
    2. {
    3. m = getmessage(EX_MOUSE);
    4. if (m.message == WM_LBUTTONDOWN) //如果访问的是鼠标向下,那么就画一个棋子
    5. {
    6. //画一个棋子
    7. //未完...
    8. }
    9. }

     那么,鼠标可以获取消息了,那么怎么画棋子呢?


     5.画棋子

    要解决的问题:

    • 如何先下黑棋,然后再下白棋呢?
    • 如何把棋子下到线与线交叉的位置?而不下到其它的位置呢?
    • 如何才能再下另一颗棋子时不覆盖先前下好的棋子呢?

    • 第一个问题:

    定义一个bool类型,如果是黑棋就为真

    bool black = true;//黑子先下
    •  第二个问题:

    一开始,我们是用像素定义图像的大小,现在我们要把他换算为下标,即一个二维数组的下标,

    定义一个全局的二维数组,int pieceArr[NUM][NUM] = { 0 };用来记录棋子的情况,0表示没有棋

    子,1表示黑子,2表示白子。

    1. void Draw_piece(bool black, int x, int y)
    2. {
    3. //计算棋盘中的坐标
    4. int i = x / 40;
    5. int j = y / 40;
    6. if (black)//黑子
    7. {
    8. setfillcolor(BLACK);
    9. pieceArr[i][j] = 1; //黑棋为1
    10. }
    11. else //白子
    12. {
    13. setfillcolor(WHITE);
    14. pieceArr[i][j] = 2; //白棋为2
    15. }
    16. fillcircle(20 + i * 40, 20 + j * 40, 15); //画一个圆(x,y,半径)
    17. }
    • 第三个问题:

    定义一个好位置函数bool NicePos(int x, int y),如果这个位置是0,那么代表没有下过棋子,可以继续下,否则就不可以。

    1. //判断这个位置是否有其他棋子
    2. bool NicePos(int x, int y)
    3. {
    4. //计算棋盘中的坐标
    5. int i = x / 40;
    6. int j = y / 40;
    7. return pieceArr[i][j] == 0;
    8. }

    6.如何判断比赛的输赢(核心)⭐

    定义一个Gameover函数,int GameOver(int x, int y)

    如果为0,游戏继续;

    如果为1,黑棋赢;

    如果为2,白棋赢;

     我们可以暴力地遍历整个二维数组,看有没有5个棋子是连在一起的,如果有,那么游戏结束。这样也行,但是时间会慢一些。

    我们最优的解法是

    只需要判断刚才下的棋子是否为5个即可
    判断行,列,45度和135度斜线

    定义一个n,用来保存棋子的颜色,如果为0则游戏继续。

    定义一个计数器count,如果碰到一个棋子与自己一样,那么就++。

     我们需要判断四个方向,每个方向都要用一个for循环,如果与自己一样,那么计数器++,如果计数器大于等于5,那么就返回n。

    1. //判断游戏胜利
    2. int GameOver(int x, int y)
    3. {
    4. x = x / 40;//换算为下标
    5. y = y / 40;//换算为下标
    6. int n = pieceArr[x][y];//得到棋子颜色
    7. if (n == 0)
    8. return 0;
    9. int count = 0;//统计棋子的数量
    10. int i, j; //当前棋子的前面或后面,或上面或下面,或斜向上或斜向下
    11. //同行的棋子
    12. for (i = x; i >= 0 && pieceArr[i][y] == n; i--)//同行的前面有没有相同的
    13. count++;
    14. for (i = x + 1; i < NUM && pieceArr[i][y] == n; i++)//同行的后面有没有相同的
    15. count++;
    16. if (count >= WIN_NUM)
    17. return n;
    18. //同列的棋子
    19. count = 0;//重新计算
    20. for (j = y; j >= 0 && pieceArr[x][j] == n; j--)//同列的上面有没有相同的
    21. count++;
    22. for (j = y + 1; j < NUM && pieceArr[x][j] == n; j++)
    23. count++;
    24. if (count >= WIN_NUM)
    25. return n;
    26. //45度的棋子
    27. count = 0;//重新计算
    28. for (i = x, j = y; i < NUM && j >= 0 && pieceArr[i][j] == n; i++, j--)//右上
    29. count++;
    30. for (i = x - 1, j = y + 1; i >= 0 && j < NUM && pieceArr[i][j] == n; i--, j++)//左下
    31. count++;
    32. if (count >= WIN_NUM)
    33. return n;
    34. //135度的棋子
    35. count = 0;
    36. for (i = x, j = y; i >= 0 && j >= 0 && pieceArr[i][j] == n; i--, j--)//左上
    37. count++;
    38. for (i = x + 1, j = y + 1; i < NUM && j < NUM && pieceArr[i][j] == n; i++, j++)//右下
    39. count++;
    40. if (count >= WIN_NUM)
    41. return n;
    42. return 0;
    43. }

    • 换算下标:

    对x,y分别对40做取模运算就可以转换为下标了。


     9.显示游戏结束的提示

     使用这些函数函数outtextxy,settextstyle,outtextxy,具体内容读者可以自己查看手册。

    1. while (1)
    2. {
    3. m = getmessage(EX_MOUSE);
    4. if (m.message == WM_LBUTTONDOWN)
    5. {
    6. if (NicePos(m.x, m.y))
    7. {
    8. Draw_piece(black, m.x, m.y);
    9. int n = GameOver(m.x, m.y);
    10. if (n == 1)//黑子赢
    11. {
    12. settextcolor(RED);//字体颜色
    13. settextstyle(36, 0, _T("Consolas"));//字体样式
    14. outtextxy(250, 0, _T("黑棋赢了")); //输出文字内容
    15. break;
    16. }
    17. else if (n == 2)//白子赢
    18. {
    19. settextcolor(RED);
    20. settextstyle(36, 0, _T("Consolas"));
    21. outtextxy(250, 0, _T("白棋赢了"));
    22. break;
    23. }
    24. black = !black;
    25. }
    26. }
    27. }

     五.完整代码🍗

    1. #define _CRT_SECURE_NO_WARNINGS//这一句必须放在第一行
    2. #include // 引用图形库头文件
    3. #include
    4. ///*
    5. //* * 15*15条边,(15条边中间14个格子+左留白0.5+右留白0.5),一共15个格子,一个格子像素为40
    6. //* 则窗口的大小 15*40=600(x) 600(y)
    7. //* //在第4,12线交界点需要画黑点
    8. 在第8线交界点需要画黑点
    9. //* loadimage:用于从文件中读取图像。加载图片
    10. //* putimage:显示图片
    11. //* setlinecolor();
    12. //* line:画线,需要两点坐标
    13. //* setfillcolor:设置填充颜色
    14. //* fillcircle:画填充(实心)圆,参数为坐标,半径
    15. //* getmessage:获取鼠标消息
    16. //* outtextxy:在指定位置(坐标)输出字符串
    17. //* settextcolor:设置字体颜色
    18. //* settextstyle:设置字体样式
    19. //*
    20. //*/
    21. #define NUM 15
    22. #define WIN_NUM 5//五子棋
    23. int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子
    24. void Draw_line()
    25. {
    26. setlinecolor(BLACK);
    27. //画竖线
    28. for (int x = 20; x < 600; x += 40)
    29. line(x, 20, x, 580);
    30. //画横线
    31. for (int y = 20; y < 600; y += 40)
    32. line(20, y, 580, y);
    33. }
    34. //画点
    35. void Draw_point()
    36. {
    37. setfillcolor(BLACK);
    38. fillcircle(140, 140, 5),
    39. fillcircle(140, 460, 5);
    40. fillcircle(460, 140, 5);
    41. fillcircle(460, 460, 5);
    42. fillcircle(300, 300, 5);
    43. }
    44. void Draw_piece(bool black, int x, int y)
    45. {
    46. //计算棋盘中的坐标
    47. int i = x / 40;
    48. int j = y / 40;
    49. if (black)//黑子
    50. {
    51. setfillcolor(BLACK);
    52. pieceArr[i][j] = 1; //黑棋为1
    53. }
    54. else //白子
    55. {
    56. setfillcolor(WHITE);
    57. pieceArr[i][j] = 2; //白棋为2
    58. }
    59. fillcircle(20 + i * 40, 20 + j * 40, 15); //画一个圆(x,y,半径)
    60. }
    61. //判断这个位置是否有其他棋子
    62. bool NicePos(int x, int y)
    63. {
    64. //计算棋盘中的坐标
    65. int i = x / 40;
    66. int j = y / 40;
    67. return pieceArr[i][j] == 0;
    68. }
    69. //0:游戏继续,1:黑子赢; 2:白子赢
    70. //只需要判断刚才下的棋子是否为5个即可
    71. //判断行,列,45度和135度斜线
    72. //判断游戏胜利
    73. int GameOver(int x, int y)
    74. {
    75. x = x / 40;//换算为下标
    76. y = y / 40;//换算为下标
    77. int n = pieceArr[x][y];//得到棋子颜色
    78. if (n == 0)
    79. return 0;
    80. int count = 0;//统计棋子的数量
    81. int i, j; //当前棋子的前面或后面,或上面或下面,或斜向上或斜向下
    82. //同行的棋子
    83. for (i = x; i >= 0 && pieceArr[i][y] == n; i--)//同行的前面有没有相同的
    84. count++;
    85. for (i = x + 1; i < NUM && pieceArr[i][y] == n; i++)//同行的后面有没有相同的
    86. count++;
    87. if (count >= WIN_NUM)
    88. return n;
    89. //同列的棋子
    90. count = 0;//重新计算
    91. for (j = y; j >= 0 && pieceArr[x][j] == n; j--)//同列的上面有没有相同的
    92. count++;
    93. for (j = y + 1; j < NUM && pieceArr[x][j] == n; j++)
    94. count++;
    95. if (count >= WIN_NUM)
    96. return n;
    97. //45度的棋子
    98. count = 0;//重新计算
    99. for (i = x, j = y; i < NUM && j >= 0 && pieceArr[i][j] == n; i++, j--)//右上
    100. count++;
    101. for (i = x - 1, j = y + 1; i >= 0 && j < NUM && pieceArr[i][j] == n; i--, j++)//左下
    102. count++;
    103. if (count >= WIN_NUM)
    104. return n;
    105. //135度的棋子
    106. count = 0;
    107. for (i = x, j = y; i >= 0 && j >= 0 && pieceArr[i][j] == n; i--, j--)//左上
    108. count++;
    109. for (i = x + 1, j = y + 1; i < NUM && j < NUM && pieceArr[i][j] == n; i++, j++)//右下
    110. count++;
    111. if (count >= WIN_NUM)
    112. return n;
    113. return 0;
    114. }
    115. int main()
    116. {
    117. initgraph(600, 600); // 创建绘图窗口,大小为 600x600 像素
    118. loadimage(NULL, _T("2.png")); //加载图片
    119. Draw_line();//画线
    120. Draw_point();//画点
    121. ExMessage m;//鼠标消息 ExMessage是一个结构体
    122. bool black = true;//黑子先下
    123. while (1)
    124. {
    125. m = getmessage(EX_MOUSE);
    126. if (m.message == WM_LBUTTONDOWN)
    127. {
    128. if (NicePos(m.x, m.y))
    129. {
    130. Draw_piece(black, m.x, m.y);
    131. int n = GameOver(m.x, m.y);
    132. if (n == 1)//黑子赢
    133. {
    134. settextcolor(RED);//字体颜色
    135. settextstyle(36, 0, _T("Consolas"));//字体样式
    136. outtextxy(250, 0, _T("黑棋赢了")); //输出文字内容
    137. break;
    138. }
    139. else if (n == 2)//白子赢
    140. {
    141. settextcolor(RED);
    142. settextstyle(36, 0, _T("Consolas"));
    143. outtextxy(250, 0, _T("白棋赢了"));
    144. break;
    145. }
    146. black = !black;
    147. }
    148. }
    149. }
    150. _getch(); // 按任意键继续
    151. closegraph(); // 关闭绘图窗口
    152. return 0;
    153. }

     六.运行结果🍗


     七.学习时的代码🍗

    观众老爷可以先把这一段代码拿去当模板,一点一点尝试去写,错了不要紧,代码就是一点一点改出来的,表示说一下子就可以写好。失败是成功之母,错误是正确他爹。慢慢来嘛。

    1. #include // 引用图形库头文件
    2. #include
    3. #define NUM 15
    4. #define WIN_NUM 5//五子棋
    5. int pieceArr[NUM][NUM] = { 0 };//记录15*15个棋盘的棋子情况,0表示没有棋子,1表示黑子,2表示白子
    6. //画线
    7. void Draw_line()
    8. //画点
    9. void Draw_point()
    10. //判断这个位置是否有其他棋子
    11. bool NicePos(int x, int y)
    12. //判断游戏胜利
    13. int GameOver(int x, int y)
    14. int main()
    15. {
    16. initgraph(600,600); // 创建绘图窗口,大小为 640x480 像素
    17. // 读取图片至绘图窗口
    18. loadimage(NULL, _T("2.png"));
    19. //画线
    20. Draw_line();
    21. //画点
    22. Draw_point();
    23. //鼠标消息
    24. ExMessage m; //结构体m ,用与存放鼠标消息
    25. //黑子先下
    26. bool black = true;//黑子先下
    27. _getch(); // 按任意键继续
    28. closegraph(); // 关闭绘图窗口
    29. return 0;
    30. }

    创作不易, 如果这份博客👍对你有帮助,可以给博主一个免费的点赞以示鼓励。
    欢迎各位帅哥美女点赞👍评论⭐收藏,谢谢!!!
    如果有什么疑问或不同的见解,欢迎在评论区留言哦👀。
    祝各位生活愉快⭐

  • 相关阅读:
    公钥密码(非对称加密)
    PPT怎么输出PDF(不留白)
    架构-三层架构:三层架构
    Go和Java实现抽象工厂模式
    iPhone或在2024开放第三方应用商店。
    Qt 目录操作(QDir 类)及展示系统文件实战 & QFilelnfo 类介绍和获取文件属性项目实战
    《一文搞懂IoU发展历程》GIoU、DIoU、CIoU、EIoU、αIoU、SIoU
    记一次攻防演练之vcenter后渗透利用
    CSS padding(填充)
    含文档+PPT+源码等]精品微信小程序ssm超市购物系统小程序+后台管理系统|前后分离VUE[包运行成功]微信小程序项目源码Java毕业设计
  • 原文地址:https://blog.csdn.net/m0_75266675/article/details/134412317