当前位置: 首页 > news >正文

【C语言】三子棋游戏——超细教学

🚩纸上得来终觉浅, 绝知此事要躬行。
🌟主页:June-Frost
🚀专栏:C语言

🔥该篇将结合之前的知识来实现 三子棋游戏。

目录:

  • 🌟思路框架:
    • 测试
    • 游戏
  • 🌟测试部分函数实现
  • 🌟游戏部分函数实现
  • 🌟完整的代码:
  • ❤️ 结语

🌟思路框架:

测试

通过迭代保证每次玩完游戏后可以再来一局或者退出。

游戏

博主将会对上图每一个板块进行函数实现。


🌟测试部分函数实现

  • 选择是否玩游戏

该板块的循环部分将会使用do while 循环来实现(保证一开始可以选择,运行完游戏部分后还可以继续选择)。

#include"game.h"int main()
{int input = 0;do{menu();//菜单printf("请选择:> ");scanf("%d", &input);switch (input){case 1:printf("三子棋游戏:\n");game();//游戏部分break;case 0:printf("退出游戏\n");break;default:printf("输入非法,请重新输入\n");break;}} while (input);return 0;
}

🌟游戏部分函数实现

在玩三子棋游戏中,每一步棋下完之后的状态需要保存,即需要数据的保存,所以可以创建一个3X3的数组,之后的数据操作就可以针对数组进行操作。

  • 菜单
void menu()
{printf("**************************\n");printf("********* 1.play *********\n");printf("********* 0.exit *********\n");printf("**************************\n");
}
  • 初始化棋盘

定义一个 3X3 数组后,我们将数组的元素都赋为 空格,这样就可以保证打印出来的效果是空的棋盘。

void BoardInit(char board[][Col], int row, int col)
{//遍历数组将每个元素赋为 空格int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){board[i][j] = ' ';}}
}
  • 打印棋盘

需要产生的效果:

实现上述的效果,只需要两步拆解:
1.
将这样的棋盘首先分为三部分,每一个部分由数据部分分割线部分构成,分割线部分在最后一部分没有(只需要加一个限制条件即可)

    int i = 0;for (i = 0; i < row; i++){//打印数据printf("\n");//打印后换行//打印分割线if (i < row - 1)//保证最后一部分不打印分割线{}printf("\n");//打印后换行}


每个部分内部又可以划分为三部分,与第一次拆解逻辑一摸一样,注意第三部分没有 | 即可

void DisplayBoard(char board[][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){//打印数据int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");//打印分割线if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}}printf("\n");}
}
  • 玩家下棋:

这里需要注意 检查玩家输入的坐标是否合法,以及该坐标下是否已经有棋子。而且,在写条件的时候,需要代入玩家视角,输入区间为 1 —— 3,但访问区间为 0——2 。

void PlayerMove(char board[][Col], int row, int col)
{printf("玩家下棋:\n");printf("请输入下棋的坐标,中间使用空格:>");while (1){int x = 0;int y = 0;scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >=1 && y <= col)//保证棋子能落入棋盘{if (board[x - 1][y - 1] == ' ')//该坐标下无棋子{board[x - 1][y - 1] = 'X';//落子break;}else{printf("该位置已有棋子,请重新输入:>");}}else{printf("输入非法,请重新输入:>");}}
}
  • 电脑下棋
    这里需要使用伪随机数,并且直接将范围锁定在 0——2,可以直接访问数组元素。完成该功能只需要判断 坐标下是否有棋子,若有棋子,则重新生成随机数。若要了解随机数,可以参考——随机数 。
void ComputerMove(char board[][Col], int row, int col)
{printf("电脑下棋:\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = 'O';break;}}
}
  • 判断输赢

只需要从4种方向遍历数组,有符合获胜条件的直接返回数组元素,如果没有获胜,则需要判断是否棋盘已满(平局),除此之外就是未完成该局,继续下棋。

所以返回值 有四种情况:
电脑赢 —— 返回 ‘O’
玩家赢 —— 返回 ‘X’
平局 —— 返回 ‘P’
继续 —— 返回 ‘C’

int IsFull(char board[][Col], int row, int col)//判断是否已满,已满返回1
{//遍历int  i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){if (board[i][j] == ' ')return 0;}}return 1;
}
//判断输赢
char IsWin(char board[][Col], int row, int col)
{//一方获胜//从上到下遍历int i = 0;for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}//从左至右遍历for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}//左上至右下if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' '){return board[1][1];}//左下至右上if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' '){return board[1][1];}//平局if (IsFull(board,row,col)){return 'P';}return 'C';}
  • 游戏逻辑部分

我们已经有了所有的功能函数,按照思路框架直接写出来即可。

void game()
{char board[Row][Col] = { 0 };BoardInit(board, Row, Col);DisplayBoard(board, Row, Col);//先手判断//假设玩家先手void(*Fir)(char board[][Col], int, int) = PlayerMove;void(*Sec)(char board[][Col], int, int) = ComputerMove;int flag = rand()%2; //1——玩家先手,0——电脑先手if (flag == 0){printf("电脑先手\n");Fir = ComputerMove;Sec = PlayerMove;}else{printf("玩家先手\n");}//char ret = 0;while (1){Fir(board, Row, Col);DisplayBoard(board, Row, Col);ret = IsWin(board, Row, Col);if (ret != 'C')break;Sec(board, Row, Col);DisplayBoard(board, Row, Col);ret = IsWin(board, Row, Col);if (ret != 'C')break;}if (ret == 'X'){printf("玩家获胜\n");}else if (ret == 'O'){printf("电脑获胜\n");}else{printf("平局\n");}
}

首先假设玩家是先手,如果flag =1,则照旧进行,如果flag = 0,就直接交换先后手。

🌟完整的代码:

test.c :

请记得设置随机数起点srand。

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"int main()
{int input = 0;srand((unsigned int)time(NULL));//起点do{menu();//菜单printf("请选择:> ");scanf("%d", &input);switch (input){case 1:printf("三子棋游戏:\n");game();//游戏部分break;case 0:printf("退出游戏\n");break;default:printf("输入非法,请重新输入\n");break;}} while (input);return 0;
}

game.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Row 3
#define Col 3
//菜单
void menu();
//游戏(逻辑)
void game();
//初始化棋盘
void BoardInit(char board[][Col], int row, int col);
//打印棋盘
void DisplayBoard(char board[][Col], int row, int col);
//玩家下棋
void PlayerMove(char board[][Col], int row, int col);
//电脑下棋
void ComputerMove(char board[][Col], int row, int col);
//判断输赢
char IsWin(char board[][Col], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"void menu()
{printf("**************************\n");printf("********* 1.play *********\n");printf("********* 0.exit *********\n");printf("**************************\n");
}void BoardInit(char board[][Col], int row, int col)
{//遍历数组将每个元素赋为 空格int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){board[i][j] = ' ';}}
}void DisplayBoard(char board[][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){//打印数据int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");//打印分割线if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}}printf("\n");}
}void PlayerMove(char board[][Col], int row, int col)
{printf("玩家下棋:\n");printf("请输入下棋的坐标,中间使用空格:>");while (1){int x = 0;int y = 0;scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >=1 && y <= col)//保证棋子能落入棋盘{if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = 'X';//落子break;}else{printf("该位置已有棋子,请重新输入:>");}}else{printf("输入非法,请重新输入:>");}}
}void ComputerMove(char board[][Col], int row, int col)
{printf("电脑下棋:\n");while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = 'O';break;}}
}int IsFull(char board[][Col], int row, int col)
{//遍历int  i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){if (board[i][j] == ' ')return 0;}}return 1;
}char IsWin(char board[][Col], int row, int col)
{//一方获胜//从上到下遍历int i = 0;for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}//从左至右遍历for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}//左上至右下if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' '){return board[1][1];}//左下至右上if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' '){return board[1][1];}//平局if (IsFull(board,row,col)){return 'P';}return 'C';}void game()
{char board[Row][Col] = { 0 };BoardInit(board, Row, Col);DisplayBoard(board, Row, Col);//先手判断//假设玩家先手void(*Fir)(char board[][Col], int, int) = PlayerMove;void(*Sec)(char board[][Col], int, int) = ComputerMove;int flag = rand()%2; //1——玩家先手,0——电脑先手if (flag == 0){printf("电脑先手\n");Fir = ComputerMove;Sec = PlayerMove;}else{printf("玩家先手\n");}//char ret = 0;while (1){Fir(board, Row, Col);DisplayBoard(board, Row, Col);ret = IsWin(board, Row, Col);if (ret != 'C')break;Sec(board, Row, Col);DisplayBoard(board, Row, Col);ret = IsWin(board, Row, Col);if (ret != 'C')break;}if (ret == 'X'){printf("玩家获胜\n");}else if (ret == 'O'){printf("电脑获胜\n");}else{printf("平局\n");}
}

❤️ 结语

文章到这里就结束了,如果对你有帮助,你的点赞将会是我的最大动力,如果大家有什么问题或者不同的见解,欢迎大家的留言~

http://www.lryc.cn/news/134749.html

相关文章:

  • redux的介绍、安装、三大核心与执行流程
  • Redis 5环境搭建
  • stm32红绿灯源代码示例(附带Proteus电路图)
  • Qt与电脑管家4
  • 使用css美化gradio界面
  • Flink流批一体计算(13):PyFlink Tabel API之SQL DDL
  • java笔试手写算法面试题大全含答案
  • 点云平面拟合和球面拟合
  • 部署问题集合(十九)linux设置Tomcat、Docker,以及使用脚本开机自启(亲测)
  • 视觉SLAM:一直在入门,如何能精通,CV领域的绝境长城,
  • 【报错】yarn --version Unrecognized option: --version Error...
  • 二叉搜索树的(查找、插入、删除)
  • 电力虚拟仿真 | 高压电气试验VR教学系统
  • innovus如何设置size only
  • Java之继承详解二
  • 国内常见的几款可视化Web组态软件
  • 通过 git上传到 gitee 仓库
  • 设置Windows主机的浏览器为wls2的默认浏览器
  • 森林生物量(蓄积量)估算全流程
  • MySQL数据库概述
  • 2023年国赛数学建模思路 - 案例:退火算法
  • 怎么借助ChatGPT处理数据结构的问题
  • Docker容器无法启动 Cannot find /usr/local/tomcat/bin/setclasspath.sh
  • Pytorch-day08-模型进阶训练技巧-checkpoint
  • 【ArcGIS Pro二次开发】(61):样式(Style)和符号(Symbol)
  • 深入理解 HTTP/2:提升 Web 性能的秘密
  • 800V高压电驱动系统架构分析
  • Camunda_3:主动撤回
  • ClickHouse(二十三):Java Spark读写ClickHouse API
  • Linux下的GPIO基本概念指南