C语言200行代码实现简易三子棋

news/2024/10/28 20:18:20/

在这里插入图片描述

前言

三子棋应该是是我们最早接触到的棋类游戏,用C语言实现三子棋对初学者来说是一种不错的锻炼
编写三子棋只需要用到数组、函数和生成随机数的知识,所以比较适合成为编程学习者编写的第一个小游戏。

一.代码实现

第一部分是源码复制就可以使用,每一个自定义函数在第二部分设计思路中都有详细解释,结合代码实现设计思路理解会有一个更好的效果

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void reset(char arr[ROW][COL])//将棋盘arr[ROW][COL]数据赋值为空格
{for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){arr[i][j] = ' ';}}
}
void dis_play(char arr[ROW][COL])//打印棋盘
{for (int i = 0; i < ROW; i++)//for每一次进去,打印一行数组和一条分割线{	                         //数组行为:(空格)元素(空格)|(空格)元素(空格)|(空格)元素(空格)//分割线为: -      -      -   |   -      -     -   |   -     -      -for (int j = 0; j < COL; j++)//一行数组{printf(" %c ", arr[i][j]);if (j < COL - 1)//为了美观,最后的“|”不打印{printf("|");}}printf("\n");for (int k = 0; k < COL; k++)//一行分割线{printf("---");if (k < COL - 1)//为了美观,最后的“|”不打印{printf("|");}}printf("\n");}}void player_move(char arr[ROW][COL])//玩家下棋
{int row = 0, col = 0;while (1){printf("玩家下棋,请输入坐标>:");scanf("%d %d", &row, &col);if (arr[row - 1][col - 1] == ' ')//判断是否可以下棋{arr[row - 1][col - 1] = '*';break;}printf("输入错误,请再次输入\n");}
}void computer_move(char arr[ROW][COL])//电脑下棋
{int row = rand() % ROW;//生成行号int col = rand() % COL;//生成列标printf("电脑下棋:>\n");while (1){if (arr[row][col] == ' ')//判断是否可以下棋{arr[row][col] = '#';break;}row = rand() % ROW;col = rand() % COL;}
}
int is_full(char arr[ROW][COL])//用于在is_win()中判断是否为平局
{for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){if (arr[i][j] == ' ')return 0;}}return 1;
}char is_win(char arr[ROW][COL])//三子棋胜利无非就三种情况:行相同、列相同和对角线相同。除开胜利还有平局
{for (int i = 0; i < ROW; i++)//判断行{if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')return arr[i][0];}for (int i = 0; i < COL; i++)//判断列{if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')return arr[0][i];}//判断对角线if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')return arr[0][0];if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')return arr[0][2];//判断平局if (is_full(arr)){return 'q';}//都不满足游戏继续运行 return ‘c’return 'c';
}void meau()
{printf("------------------\n");printf("|     1.play     |\n");printf("|----------------|\n");printf("|     0.exit     |\n");printf("------------------\n");
}void game()
{char arr[ROW][COL];//初始化棋盘char ch;reset(arr);//将棋盘里每一个元素赋值为空格dis_play(arr);do{player_move(arr);dis_play(arr);ch=is_win(arr);if (ch != 'c'){break;}computer_move(arr);dis_play(arr);ch=is_win(arr);if (ch != 'c'){break;}} while (1);switch (ch)//根据返回字符判断结果{case '#':printf("电脑胜利\n"); break;case '*':printf("玩家胜利\n"); break;case 'q':printf("平局\n"); break;}
}int main()
{srand((unsigned)time(NULL));int input = 0;do {meau();scanf("%d", &input);switch (input){case 1 :game(); break;case 0 :break;default :printf("输入错误\n");}} while (input);return 0;
}

二.设计思路

main()函数搭建框架

1.main()函数搭建框架:像所有的电脑游戏一样,我们需要一个菜单,通过菜单选择进入游戏和退出游戏,当一盘游戏结束时可以再次选择进入或者退出,菜单用printf()打印就可以解决,循环的进入游戏用do while()循环就可以解决

实现代码如下

 void meau(){printf("------------------\n");printf("|     1.play     |\n");printf("|----------------|\n");printf("|     0.exit     |\n");printf("------------------\n");} void game()
{·········
}
int main()
{int input = 0;do {meau();scanf("%d", &input);switch (input){case 1 :game(); break;case 0 :break;default :printf("输入错误\n");}} while (input);return 0;
}

2.当我们进入case 1,运行game()函数;首先我们需要一个容器来存放我们的游戏数据,此时创建字符二维数组arr[3][3]作为容器,玩家下的棋用“*”表示电脑用”#“表示。因为行和列都为3,后面经常要使用,我们对他进行宏定义一下
#define ROW 3
#define COL 3

dis_play( )函数

》.dis_play( ):我们下棋肯定需要棋盘来显示我们的数据,我们通过构造一个函数dis_play()将数组打印出来来实现这一功能

dis_play()的功能其实就是把arr[ROW][COL]以棋盘形式打印显示出来,需要借助一些特殊字符”|“和”_“辅助打印

#define ROW 3 / 行:3
#define COL 3 / 列:3
void dis_play(char arr[ROW][COL])
{for (int i=0;i<ROW;i++) /for每一次进去,打印一行数组和一条分割线{for (int j = 0; j < COL; j++)//打印数组{printf(" %c ", arr[i][j]);if (j < COL - 1){printf("|");}}printf("\n");for (int k = 0; k < COL; k++)//打印分割线{printf("---");if (k < COL - 1){printf("|");}}printf("\n");}}

初步运行代码,打印棋盘:
在这里插入图片描述

reset ( )函数

reset ( ) :我们下完一盘棋,还想下该怎么办?这时候我们构造一个函数reset(),将棋盘数组的每一个元素重置为空格

reset()函数,遍历数组,赋值为空格

void reset( char arr[ROW][COL])
{for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){arr[i][j] = ' ';//赋值空格}}
}

player_move( )函数

player_move( ):玩家下棋,不能随便下,下过的地方不能下,我们构造一个player_move()函数完成这一功能

player_move( )函数功能其实就是为数组arr[ROW][COL]赋值,数组元素为空格的地方就是可以下棋的地方
输入坐标时,和我们程序员思维不同,正常人认为行是从1开始而不是从0开始,玩家输入的数据需要减1才能正常赋值

void player_move(char arr[ROW][COL])
{int row = 0, col = 0;while (1){printf("玩家下棋,请输入坐标>:");scanf("%d %d", &row, &col);if (arr[row-1][col-1] == ' '){arr[row-1][col-1] = '*';break;}printf("输入错误,请再次输入\n");}
}

玩家下棋
在这里插入图片描述

computer_move()函数

computre_move()电脑下棋,为了更容易实现我们这里让他再棋盘上随机下,需要生成随机数的知识,我们需要构造一个函数

使用头文件#include<stdlib.h>中的rand()函数可以生成一个0~32767的伪随机数,但使用rand()前先要使用srand()设置伪随机数起点
起点只要写一次,我们将srand((unsigned)time(NULL))定义在主函数,此处是一种固定的写法,time()函数需要引<time.h>头文件

将rand()%3即%ROW可以生产0、1、2这三个随机数,可以用来做数组的行号和列标

int main()
{srand((unsigned)time(NULL));/设置起点的固定写法int input = 0;do {meau();scanf("%d", &input);switch (input){case 1 :game(); break;case 0 :break;default :printf("输入错误\n");}} while (input);return 0;
}
void computer_move(char arr[ROW][COL])
{int row = rand() % ROW ;//利用随机数生成行号列标int col = rand() % COL ;printf("电脑下棋:>\n");while (1){if (arr[row][col] == ' ')//判断是否为空格{arr[row][col] = '#';break;}row = rand() % ROW;col = rand() % COL;}
}

电脑下棋
在这里插入图片描述

is_win()函数

is_win()光下棋也不行,每当玩家或电脑下一步棋必须有东西来判断到底是玩家赢了还是电脑赢了还是平局还是继续,我们构造is_win()函数完成这一功能

is_win()函数功能最后是返回一个字符,电脑赢返回"#",玩家赢返回”*“,平局返回”q“,以上情况都不符合就返回”c“(continue)
三子棋胜利无非就三种情况:行相同、列相同和对角线相同我们用for和if语句就可以判断
平局的情况其实就是棋盘满了,我们构造一个is_fuii()函数,棋盘满了,该函数返回1否则返回0;

int is_full(char arr[ROW][COL])
{for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){if (arr[i][j] == ' ')/棋盘还有空格则return 0return 0;}}return 1;
}char is_win(char arr[ROW][COL])  /is_win()函数
{for (int i = 0; i < ROW; i++)/判断是否有行相同{if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')return arr[i][0];}for (int i = 0; i <COL; i++)/判断是否有列相同{if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')return arr[0][i];}/判断对角线是否相同if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')return arr[0][0];if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')return arr[0][2];if (1==is_full(arr))/is_full()返回1return ‘q’{return 'q';}return 'c';/都不满足,return ‘c’
}

总结
整理不易,如果有帮助就来个三联吧,后续有时间我会改进这个代码


http://www.ppmy.cn/news/68867.html

相关文章

C++基础篇:05 静态成员与单例模式

1 静态成员 1.1 什么是静态成员 被static修饰的成员变量、成员函数都称为静态成员 1.2 普通成员的特点 普通成员变量&#xff1a;每个类对象中都独有一份成员变量&#xff0c;相互之间没有任何关联 普通成员函数&#xff1a;都隐藏着一个this指针 1.3 静态成员的特点 静态成…

深入探究C++中的仿函数和迭代器——提升你的STL技能

&#x1f4d6;作者介绍&#xff1a;22级树莓人&#xff08;计算机专业&#xff09;&#xff0c;热爱编程&#xff1c;目前在c&#xff0b;&#xff0b;阶段>——目标Windows&#xff0c;MySQL&#xff0c;Qt&#xff0c;数据结构与算法&#xff0c;Linux&#xff0c;多线程&…

一分钟图情论文:《公共图书馆法》视域下的馆员知识与能力体系探究

一分钟图情论文&#xff1a;《公共图书馆法》视域下的馆员知识与能力体系探究 在公共服务体系建设过程中&#xff0c;图书馆建设是十分关键地一环&#xff0c;在图书馆建设过程中又以图书馆员队伍的建设首当其冲。在当今复杂的信息环境下&#xff0c;我们该如何培养图书馆员&a…

Mybatis二级缓存详解

目录 二级缓存 MyBatis的缓存机制整体设计以及二级缓存的工作模式 二级缓存的划分 使用二级缓存&#xff0c;必须要具备的条件 一级缓存和二级缓存的使用顺序 二级缓存实现的选择 MyBatis自身提供的二级缓存的实现 二级缓存的作用 二级缓存的作用域 二级缓存应用场景…

NexNosql Client与chatGPT的对话

问&#xff1a;Nexnosql client有哪些优点&#xff1f; 答&#xff1a;nexnosql client 的优点包括&#xff1a; 即开即用&#xff0c;无需部署服务&#xff0c;最大限度降低使用成本。高度集成&#xff0c;Elasticsearch、Redis、MongoDB&#xff0c;非关系型数据库一网打尽…

ROS 下 激光扫描仪 YDLidar-G4 使用

环境配置&#xff1a; ubuntu20.04 LTS ROS noetic 编程工具&#xff1a;vs code&#xff0c;远程通过ssh访问 扫描仪&#xff1a;YDLidar-G4 YDLidar驱动&#xff1a; YDLidar SDK YDLidar ROS 功能包 此环境包含树莓派&#xff0c;以下过程在树莓派3B上测试通过&#xff0c…

canal学习-运行canal-adapter源码并记录解决报错问题(一)

运行canal-adapter 1. 下载canal源码1.1 下载源码并安装好环境1.2 查看目录结构 2.项目运行2.1 项目打包2.2 项目打包可能遇到的问题&#xff1a;1.Failure to find com.alibaba.otter:connector.tcp:jar:jar-with-dependencies:1.1.52.com.alibaba.druid.pool.DruidDataSource…

leetcode 27. 移除元素

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…