五子棋(C语言实现)

目录

构思

1、主程序

2、初始化

3、游戏菜单

4、打印棋盘

6、玩家下棋

7、判断输赢

 8、功能整合

人机下棋

完整版: 

game.h

game.c

text.c

 测试功能代码


构思

五子棋不必多介绍了,大家小时候都玩过哈。

我们要通过程序实现这个小游戏,大体上的构思得有:

游戏流程:运行游戏>>打印棋盘>>下棋>>判断输赢

由此,我们声明如下函数、棋盘数组和回合数 (用于双人下棋时下不同棋子的判断)。

将这些都放在我创建的头文件game.h中方便其他文件使用: 

#include <stdio.h>
#include <Windows.h>int map[19][19];//棋盘
int flag;//回合数//初始化棋盘
void init();//游戏菜单
void menuView();//打印棋盘
void gameView_ShowMap();//玩家下棋
int playerMove(int x, int y);//判断输赢
int isWin(int x, int y);//判断输赢
void winView();

1、主程序

先进行游戏下棋,后进行判断输赢,比较符合do—while的特点。 

int main()
{int input = 0;do{menuView();printf("请选择:");scanf("%d", &input);switch (input) {case 1:gameView();break;case 0:printf("退出游戏\n");break;default:printf("输入错误,请重新选择.\n");break;}} while (input);return 0;
}
  • 首先打印菜单,提示玩家进行选择开始游戏。
  • 通过输入变量input的值,判断是否进行游戏,
  • 值为1则调用gameView函数进行游戏,0则结束游戏。
  • gameView函数对各种功能函数进行整合。

在此之前先将各种功能函数进行实现,最后将它们放入gameView整合。 

2、初始化

void init() {for (int i = 0; i < 19; i++) {for (int j = 0; j < 19; j++) {map[i][j] = 0;}}flag = 0;
}
  • 将棋盘每个格子初始化为0。
  • 回合数初始化为0。

3、游戏菜单

void menuView() {printf("*************************\n");printf("*****   1. play    ******\n");printf("*****   0. exit    ******\n");printf("*************************\n");
}

4、打印棋盘

这里我选择设计了棋盘格和横纵坐标,我们可以根据需要自行设计。 

void gameView_ShowMap() {int i, j;printf("   ");for (i = 0; i < 19; i++) {//打印横坐标printf("%3d ",i);}printf("\n   ");for (i = 0; i < 19; i++) {printf("+---");}printf("+\n");for (i = 0; i < 19; i++) {printf("%2d |", i);//每行输出前都先打印纵坐标for (j = 0; j < 19; j++) {printf(" %d ", map[i][j]);//打印棋子if (j < 18)printf("|");}printf("|\n");if(i<18)printf("   |");if(i==18)printf("   +");for (j = 0; j < 19; j++) {printf("---");if (j < 18)printf("+");}printf("+\n");}
}

效果如下: 

6、玩家下棋

int playerMove(int x, int y) {if (x >= 0 && x < 19 && y >= 0 && y < 19) {if (map[x][y] == 0) {if (flag % 2 == 0)map[x][y] = 1;//下黑子elsemap[x][y] = 2;//下白子//落子成功return 1;}else {//该位置已有棋子return 0;}}else {//坐标不合法return -1;}
}
  • 首先判断下棋位置是否在棋盘0到18的横纵坐标内,如果不在函数返回值-1,
  • 如果在棋盘内,则进行下棋。
  • 棋盘每个格子初始值为0,判断当前格子的值为0才可以下棋,否则返回值为0。
  • 回合数flag初始值为0,当flag为偶数下黑子>>1,奇数下白子>>2,成功下棋返回值为1。

7、判断输赢

int isWin(int x, int y) {int i, j;for (i = 0; i < 19; i++) {for (j = 0; j < 19; j++) {if (map[i][j] == 0) {continue;}//横着连成五子if (j < 15)if (map[i][j] == map[i][j + 1] && map[i][j] == map[i][j + 2]&& map[i][j] == map[i][j + 3] && map[i][j] == map[i][j + 4])return map[i][j];//竖着连成五子if (i < 15)if (map[i][j] == map[i + 1][j] && map[i][j] == map[i + 2][j]&& map[i][j] == map[i + 3][j] && map[i][j] == map[i + 4][j])return map[i][j];//左斜着连成五子-> " \ "if (i < 15 && j < 15)if (map[i][j] == map[i + 1][j + 1] && map[i][j] == map[i + 2][j + 2]&& map[i][j] == map[i + 3][j + 3] && map[i][j] == map[i + 4][j + 4])return map[i][j];//右斜着连成五子-> " / "if (i < 15 && j > 4)if (map[i][j] == map[i + 1][j - 1] && map[i][j] == map[i + 2][j - 2]&& map[i][j] == map[i + 3][j - 3] && map[i][j] == map[i + 4][j - 4])return map[i][j];}}return 0;
}
  • i < 15 用于确保在检查垂直和左斜方向的连续五子时,起始位置 (i, j) 之后至少还有4个位置。因为五子连成一线需要五个连续的位置,所以确保从当前位置开始往下检查的时候不会超出数组的边界。

  • j < 15 用于确保在检查水平和左斜方向的连续五子时,起始位置 (i, j) 之后至少还有4个位置。同样,这是为了确保从当前位置开始往右检查的时候不会超出数组的边界。

  • j > 4 用于确保在检查右斜方向的连续五子时,起始位置 (i, j) 之前至少还有4个位置。这是为了确保从当前位置开始往左检查的时候不会超出数组的边界。

 8、功能整合

void gameView()
{init();int x = 0, y = 0;int ret = 0;//辅助判断坐标是否合法while (1) {gameView_ShowMap();printf("请输入要下棋的坐标:");scanf("%d %d", &x, &y);if (playerMove(x, y) == 0) {printf("\n!!!该坐标已被占用!!!\n");Sleep(2000);continue;}else if (playerMove(x, y) == -1) {printf("\n!!!请输入合法坐标!!!\n");Sleep(2000);continue;}else {flag++;//切换回合}if (isWin(x, y) == 0) {continue;}else if (isWin(x, y) == 1) {printf("黑子获胜\n");break;}else if (isWin(x, y) == 2) {printf("白子获胜\n");break;}}}
  •  这里的Sleep函数需要头文件#include <Windows.h>,使用该函数暂停两秒,防止continue后下次循环打印的棋盘将提示信息挡住。
  • 下棋坐标不合法打印提示信息后,进入下次循环重新输入。
  • 成功下棋则flag自增,切换回合。
  • 每次下棋后都要判断输赢,有人赢了则停止循环,否则继续下棋。
  • (其实应该从下棋次数第五次开始判断输赢更合理,读者可以自行添加判断)

人机下棋

想要实现人机下棋可以看看我这篇文章《三子棋》 ,里面实现了人机下棋,读者可以自行模仿改进,实现其功能的重要函数可以在这篇文章中学习 rand&srand函数 。 

完整版: 

game.h

#include <stdio.h>
#include <Windows.h>
int map[19][19];//棋盘
int flag;//回合数//初始化
void init();//游戏菜单
void menuView();//打印棋盘
void gameView_ShowMap();//玩家下棋
int playerMove(int x, int y);//判断输赢
int isWin(int x, int y);

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"void init() {for (int i = 0; i < 19; i++) {for (int j = 0; j < 19; j++) {map[i][j] = 0;}}flag = 1;
}int isWin(int x, int y) {int i, j;for (i = 0; i < 19; i++) {for (j = 0; j < 19; j++) {if (map[i][j] == 0) {continue;}//横着连成五子if (j < 15)if (map[i][j] == map[i][j + 1] && map[i][j] == map[i][j + 2]&& map[i][j] == map[i][j + 3] && map[i][j] == map[i][j + 4])return map[i][j];//竖着连成五子if (i < 15)if (map[i][j] == map[i + 1][j] && map[i][j] == map[i + 2][j]&& map[i][j] == map[i + 3][j] && map[i][j] == map[i + 4][j])return map[i][j];//左斜着连成五子-> " \ "if (i < 15 && j < 15)if (map[i][j] == map[i + 1][j + 1] && map[i][j] == map[i + 2][j + 2]&& map[i][j] == map[i + 3][j + 3] && map[i][j] == map[i + 4][j + 4])return map[i][j];//右斜着连成五子-> " / "if (i < 15 && j > 4)if (map[i][j] == map[i + 1][j - 1] && map[i][j] == map[i + 2][j - 2]&& map[i][j] == map[i + 3][j - 3] && map[i][j] == map[i + 4][j - 4])return map[i][j];}}return 0;
}int playerMove(int x, int y) {if (x >= 0 && x < 19 && y >= 0 && y < 19) {if (map[x][y] == 0) {if (flag % 2 == 0)map[x][y] = 1;//下黑子elsemap[x][y] = 2;//下白子//落子成功return 1;}else {//该位置已有棋子return 0;}}else {//坐标不合法return -1;}
}void menuView() {printf("*************************\n");printf("*****   1. play    ******\n");printf("*****   0. exit    ******\n");printf("*************************\n");
}void gameView_ShowMap() {int i, j;printf("   ");for (i = 0; i < 19; i++) {//打印横坐标printf("%3d ",i);}printf("\n   ");for (i = 0; i < 19; i++) {printf("+---");}printf("+\n");for (i = 0; i < 19; i++) {printf("%2d |", i);//每行输出前先都打印纵坐标for (j = 0; j < 19; j++) {printf(" %d ", map[i][j]);if (j < 18)printf("|");}printf("|\n");if(i<18)printf("   |");if(i==18)printf("   +");for (j = 0; j < 19; j++) {printf("---");if (j < 18)printf("+");}printf("+\n");}
}

text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"void gameView()
{init();int x = 0, y = 0;int ret = 0;//辅助判断坐标是否合法while (1) {gameView_ShowMap();printf("请输入要下棋的坐标:");scanf("%d %d", &x, &y);if (playerMove(x, y) == 0) {printf("\n!!!该坐标已被占用!!!\n");Sleep(2000);continue;}else if (playerMove(x, y) == -1) {printf("\n!!!请输入合法坐标!!!\n");Sleep(2000);continue;}else {flag++;//切换回合}if (isWin(x, y) == 0) {continue;}else if (isWin(x, y) == 1) {printf("黑子获胜\n");break;}else if (isWin(x, y) == 2) {printf("白子获胜\n");break;}}}int main()
{int input = 0;do{menuView();printf("请选择:");scanf("%d", &input);switch (input) {case 1:gameView();break;case 0:printf("退出游戏\n");break;default:printf("输入错误,请重新选择.\n");break;}} while (input);return 0;
}

 测试功能代码

此代码可以替换int main主函数,用于测试函数功能是否正确,可以减少自行下棋测试时间 

成功运行输出如下:

int main()
{int testflag = 0;//init测试代码init();if (flag != 0) {printf("init()错误");exit(0);}for (int i = 0; i < 19; i++) {for (int j = 0; j < 19; j++) {if (map[i][j]) {printf("init()错误");exit(0);}}}printf("init()测试成功\n");testflag++;//playerMove测试代码int result = 1;result &= playerMove(2, 2);result &= playerMove(2, 3);result &= playerMove(2, 4);result &= playerMove(2, 5);if (result != 1 || (map[2][2] && map[2][3] && map[2][4] && map[2][5]) != 1) {printf("playerMove()错误");exit(0);}flag = 1;result &= playerMove(2, 5);if (result != 0 || map[2][5] != 1) {printf("playerMove()错误");exit(0);}printf("playerMove()测试成功\n");testflag++;//isWin测试代码playerMove(2, 1);if (isWin(2, 1)) {printf("isWin()错误");exit(0);}playerMove(1, 0);playerMove(3, 2);playerMove(4, 3);playerMove(5, 4);if (isWin(1, 0) != 2) {printf("isWin()错误");exit(0);}printf("isWin()测试成功\n");testflag++;if (testflag == 3) {printf("service代码测试成功\n");}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/105074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++算法:最短回文串

题目 给定一个字符串 s&#xff0c;你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。 示例 1&#xff1a; 输入&#xff1a;s “aacecaaa” 输出&#xff1a;“aaacecaaa” 示例 2&#xff1a; 输入&#xff1a;s “abcd” 输…

Django框架集成Celery异步-【2】:django集成celery,拿来即用,可用操作django的orm等功能

一、项目结构和依赖 study_celery | --user |-- models.py |--views.py |--urls.py |--celery_task |--__init__.py |--async_task.py |-- celery.py | --check_task.py | --config.py | --scheduler_task.py | --study_celery | --settings.py | --manage.py 依赖&#xff1a…

ChatGPT

chatgpt使用地址 https://mycaht.top/#/chat 申请内测免费key https://github.com/chatanywhere/GPT_API_free 设置 接口地址设置改成 https://api.chatanywhere.com.cnAPI Key设置成申请出来的免费key 开始聊天

关于网络协议的若干问题(五)

1、DH 算法会因为传输随机数被破解吗&#xff1f; 答&#xff1a;DH 算法的交换材料要分公钥部分和私钥部分&#xff0c;公钥部分和其他非对称加密一样&#xff0c;都是可以传输的&#xff0c;所以对于安全性是没有影响的&#xff0c;而且传输材料远比传输原始的公钥更加安全。…

zabbix触发器与动作

一、触发器&#xff08;Trigger&#xff09; 1、概念&#xff1a; 在 Zabbix 中&#xff0c;触发器用于监测 Zabbix 监控系统中的各种指标和条件&#xff0c;并在特定条件满足时触发警报。&#xff08;触发器用于定义监控项的报警阈值&#xff09; 2、触发器对象&#xff1a…

2核4G服务器支持多少用户同时在线访问?卡不卡?

腾讯云轻量2核4G5M带宽服务器支持多少人在线访问&#xff1f;5M带宽下载速度峰值可达640KB/秒&#xff0c;阿腾云以搭建网站为例&#xff0c;假设优化后平均大小为60KB&#xff0c;则5M带宽可支撑10个用户同时在1秒内打开网站&#xff0c;从CPU内存的角度&#xff0c;网站程序效…

【数据结构】排序--插入排序(希尔排序)

目录 一 基本思想 二 直接插入排序 三 希尔排序 一 基本思想 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为 止&#xff0c;得到一个新的有序序列 。 实际中我们玩扑克牌时&#xff0c;就用了插入排序的思想 二…

【Linux】进程概念讲解

前言 在了解进程概念之前&#xff0c;还有很多东西需要我们先了解&#xff0c;以助我们更好地学习以后的知识 大部分都是概念的东西&#xff0c;大部分大概有个印象就好了 冯诺依曼体系结构&#xff08;硬件方面&#xff09; 当代计算机的设计都是按照冯诺依曼体系结构设计…

快速修复“找不到xinput1_3.dll无法继续执行此代码的”问题的5个方法

在计算机系统中&#xff0c;DLL&#xff08;动态链接库&#xff09;是一个重要的组件&#xff0c;它负责在程序和操作系统之间进行有效的通信。然而&#xff0c;有时候我们可能会遇到“xinput1_3.dll”文件出现问题的情况&#xff0c;这可能会导致系统不稳定甚至无法正常运行。…

Git 回退代码的两种方法对比

Git 回退代码版本 在项目的开发中&#xff0c;有时候还是会出现&#xff0c;一些误提交了一些代码&#xff0c;这时候就会想撤回提交的代码&#xff0c;在Git中有两种方法可以使用&#xff0c;现在通过对比方法比较这两种方法的区别&#xff0c;分别适用于哪些情况&#xff1f…

Flink(林子雨慕课课程)

文章目录 12.Flink12.1 Flink简介12.2 为什么要选择Flink12.3 Flink应用场景12.4 Flink技术栈、体系架构和编程模型12.5 Flink的安装和编程实战 12.Flink 12.1 Flink简介 企业的处理架构已经由传统数据处理架构和大数据Lamda架构向流处理架构演变 Flink实现了Goole Dataflow…

区块链的两个核心概念之一签名, 另一个是共识.

Alice的公私钥&#xff0c; 签名和验证签名仅仅确定了Alice对数字资产A所有权的宣言. 之后, Bob也可以用自己的私钥对资产A进行签名宣誓所有权。区块链中叫双花&#xff0c;即重复宣称所有权&#xff0c; 也称重复花费交易。这时候需要共识算法(集体成员pow或委员会代表pos监督…

微信小程序入门级

目录 一.什么是小程序&#xff1f; 二.小程序可以干什么&#xff1f; 三.入门使用 3.1. 注册 3.2. 安装 3.3.创建项目 3.4.项目结构 3.5.应用 好啦今天就到这里了&#xff0c;希望能帮到你哦&#xff01;&#xff01;&#xff01; 一.什么是小程序&#xff1f; 微信小程…

浅析倾斜摄影三维模型(3D)几何坐标精度偏差的几个因素

浅析倾斜摄影三维模型&#xff08;3D&#xff09;几何坐标精度偏差的几个因素 倾斜摄影是一种通过倾斜角度较大的相机拍摄建筑物、地形等场景&#xff0c;从而生成高精度的三维模型的技术。然而&#xff0c;在进行倾斜摄影操作时&#xff0c;由于多种因素的影响&#xff0c;导致…

解决ERROR: No query specified的错误以及\G 和 \g 的区别

文章目录 1. 复现错误2. 分析错误3. 解决问题4. \G和\g的区别 1. 复现错误 今天使用powershell连接数据库后&#xff0c;执行如下SQL语句&#xff1a; mysql> select * from student where id 39 \G;虽然成功查询除了数据&#xff0c;但报出如下错误的信息&#xff1a; my…

挖机技术哪家强

挖机技术哪家强&#xff0c;中国山东找蓝翔&#xff0c;开挖机是我曾经的梦想&#xff0c;每个男人心中都有一台自己的挖机&#xff0c;近半年做的项目就是关于挖机销售CRM&ERP系统&#xff0c; 今天我们聊聊关于挖机的基本知识。 注&#xff1a;此文并非广告&#xff0c;…

快速构建代理应对

今天我要和大家分享一个解决反爬策略升级问题的方法&#xff0c;那就是快速构建代理池。如果您是一位爬虫开发人员&#xff0c;一定深知反爬策略的烦恼。但是&#xff0c;通过构建代理池&#xff0c;您可以轻松地应对反爬策略的升级&#xff0c;让您的爬虫持续高效运行。接下来…

8年经验之谈 —— 如何用 JMeter 编写性能测试脚本?

Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 i STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例&#xff09;。 如下图所示&#xff1a; W…

Vue3路由引入报错解决:无法找到模块“xxx.vue”的声明文件 xxx隐式拥有 “any“ 类型。

这类情况应该遇见过吧&#xff0c;这是因为 TypeScript只能理解 .ts 文件&#xff0c;无法理解 .vue 文件。 解决方法&#xff1a;在项目的根目录或者src文件夹下创建一个后辍为 文件名.d.ts 的文件&#xff0c;并写入一下内容&#xff1a; declare module *.vue {import { …

前端基础一:用Formdata对象来上传图片的原因

最近有人问&#xff1a;你是否能用json来传图片&#xff0c;其实应该这么理解就对了。 一、上传的数据体格式Content-Type 1.application/x-www-form-urlencoded 2.application/json 3.multipart/form-data 以上三种类型旨在告诉服务器需要接收的数据类型同事要…