C语言实现三子棋游戏(详解)

目录

引言:

1.游戏规则:

2.实现步骤:

2.1实现菜单:

2.2创建棋盘并初始化:

2.3绘制棋盘:

2.4玩家落子:

2.5电脑落子:

2.6判断胜负:

 3.源码:

结语:


引言:

《三子棋》是一款古老的民间传统游戏,又被称为OOXX棋、黑白棋,井字棋,九宫棋等。游戏分为双方对战,双方依次在九宫格棋盘上摆放棋子,率先将自己的三个棋子连成一条线的一方则为胜利者。

 

1.游戏规则:

三子棋是一种两人对战的游戏,棋盘是一个3x3的方格矩阵。玩家和电脑轮流在空白的方格中落子,一方执X,另一方执O。当玩家在横向纵向对角线上连成三个相同的棋子时,该玩家获胜,反之,电脑获胜。如果棋盘填满而无法连成三子,游戏结束,双方平局。

2.实现步骤:

想要完整的实现三子棋代码,我们首先必须在脑海里构建出一个大致的框架,然后再去一步步实现它里边的细节。

  1. 实现进入游戏的菜单界面
  2. 创建棋盘并初始化
  3. 绘制棋盘(打印棋盘)
  4. 玩家落子
  5. 电脑落子
  6. 判断胜负

2.1实现菜单:

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

2.2创建棋盘并初始化:

首先,我们需要创建一个3x3的二维数组来表示棋盘,但考虑到这样不灵活,那么我们可以使用宏定义的方式来使我们的代码变得更加易于维护。

#define ROW 3//行
#define COL 3//列
void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
}

2.3绘制棋盘:

最终呈现在玩家眼里的棋盘应该是由分割线和空位置组成的。

void DisplayBoard(char board[ROW][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){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}}printf("\n");}
}

2.4玩家落子:

当玩家下棋时,他眼里的坐标只有1,2,3行,而在计算机中,数组是通过下标访问的,是从0开始的,所以在写代码时应该将玩家输入的坐标减去1才合适。还应该对玩家输入的坐标进行判断看有没有越界访问,以及判断棋子有没有被占用

void PlayerMove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家下棋\n");while (1){printf("请输入坐标:>");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("坐标被占用,请重新输入!\n");}}elseprintf("坐标非法,请重新输入!\n");}
}

2.5电脑落子:

利用rand函数生成的随机数再模个行和列输入坐标实现落子,电脑落子也要判断落子点是否被占用。

void ComputerMove(char board[ROW][COL], int row, int col)
{printf("电脑下棋\n");int x = 0;int y = 0;while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = 'O';break;}}
}

2.6判断胜负:

🎈我们规定:

  • 玩家赢返回 "X"
  • 电脑赢返回 "O"
  • 平局返回 "Q"
  • 以上三种情况都不是即游戏继续返回 "C"
//未分出胜负并且所有元素都不为空格则为平局
static int IsFull(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;
}//玩家赢 X
//电脑赢 O
//平局 Q
//游戏继续 C
char IsWin(char board[ROW][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][1] != ' '){return board[i][1];}}//判断列for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '){return board[1][i];}}//判断对角线if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//判断平局if (IsFull(board, row, col)){return 'Q';}return 'C';
}

 3.源码:

为了让代码逻辑更清晰,更易于调试,我们可以将整个三子棋代码分为三个文件。

  1. 主函数(main.c):实现游戏的进入和退出功能。
  2. 游戏实现函数(game.c):思考游戏的逻辑并构建函数,通过调用一系列函数来实现整个游戏。
  3. 游戏实现头文件(game.h):定义宏并声明游戏实现函数中的各个函数。

 

🎈(main.c)

#include "game.h"
void menu()
{printf("*******************\n");printf("****  1.play   ****\n");printf("****  0.exit   ****\n");printf("*******************\n");
}void game()
{char ret = 0;char board[ROW][COL];//创建二位数组//开始的时候,数组的内容应该全部是空格InitBoard(board, ROW, COL);//初始化棋盘 DisplayBoard(board, ROW, COL);//打印棋盘//下棋while (1){PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C'){break;}ComputerMove(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");}
}
int main()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,重新选择!\n");break;}} while (input);return 0;
}

 

 🎈(game.c)

#include "game.h"void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
}void DisplayBoard(char board[ROW][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){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}}printf("\n");}
}void PlayerMove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("玩家下棋\n");while (1){printf("请输入坐标:>");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("坐标被占用,请重新输入!\n");}}elseprintf("坐标非法,请重新输入!\n");}
}void ComputerMove(char board[ROW][COL], int row, int col)
{printf("电脑下棋\n");int x = 0;int y = 0;while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = 'O';break;}}
}static int IsFull(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;
}//玩家赢   返回"X"
//电脑赢   返回"O"
//平局     返回"Q"
//游戏继续  返回"C"
char IsWin(char board[ROW][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][1] != ' '){return board[i][1];}}//判断列for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '){return board[1][i];}}//判断对角线if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//判断平局if (IsFull(board, row, col)){return 'Q';}return 'C';
}

 

🎈(game.h)

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3//行
#define COL 3//列//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);//判断输赢
char IsWin(char board[ROW][COL], int row, int col);

结语:

通过本篇博客,我们学习了如何使用C语言实现三子棋游戏。通过实现菜单、创建棋盘并初始化棋盘、绘制棋盘、玩家落子、电脑落子、判断胜负等步骤,我们成功完成了这个有趣的项目。希望本篇博客对初学者和有一定编程经验的佬佬都能有所帮助,最后祝大家玩得愉快呀!

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

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

相关文章

GB28181学习(三)——心跳保活

心跳保活 要求&#xff1a; 1. 当原设备发现工作异常时&#xff0c;应立即向本SIP监控域的SIP服务器发送状态信息&#xff1b; 2. 无异常时&#xff0c;定时向本SIP监控域的SIP服务器发送状态信息&#xff1b; 3. 状态信息报送采用**MESSGAE**方法&#xff1b; 4. SIP设备宜在…

简简单单教你如何用C语言实现获取当前所有可用网口!

一、获取本机所有可用网卡名 原理&#xff1a; 在 Linux 系统中&#xff0c;/proc 目录是一个位于内存中的伪文件系统。 /proc目录是内核提供给我们的查询中心&#xff0c;通过查询该目录下的文件内容&#xff0c;可以获取到有关系统硬件及当前运行进程的信息&#xff0c;如…

leetcode 54. 螺旋矩阵

1. 题解 如果一条边从头遍历到底&#xff0c;则下一条边遍历的起点随之变化选择不遍历到底&#xff0c;可以减小横向、竖向遍历之间的影响一轮迭代结束时&#xff0c;4条边的两端同时收窄 1一轮迭代所做的事情变得很清晰&#xff1a;遍历一个“圈”&#xff0c;遍历的范围收缩为…

日常开发小汇总(3)js类型判断

1.typeof 能判断出字符串、数字、方法和undefined&#xff0c;array、null、object判断不出 let num 1;let str "x";let fn function user(){}let arr [1,2]let obj {name:"zhangs"}let und;let nul null;console.log(typeof num) //numberconsole.l…

JAVAEE初阶相关内容第八弹--多线程(初阶)

本文目录 阻塞队列 阻塞队列是什么&#xff1f; 标准库中的阻塞队列 生产者消费者模型 阻塞队列的实现 普通队列实现&#xff1a; 入队列&#xff1a; 出队列&#xff1a; 完整代码&#xff1a; 加阻塞 加锁 加阻塞 阻塞队列 队列&#xff1a;先进先出&#xff0c;…

量化:基于支持向量机的择时策略

文章目录 参考机器学习简介策略简介SVM简介整体流程收集数据准备数据建立模型训练模型测试模型调节参数 参考 Python机器学习算法与量化交易 利用机器学习模型&#xff0c;构建量化择时策略 机器学习简介 机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。…

请重新安装msvcp140.dll的修复方法,多种msvcp140.dll的处理方案

当你在电脑上安装或运行某些程序时出现了“缺少msvcp140.dll”或“msvcp140.dll丢失”会要求你“重新安装msvcp140.dll”等的错误提示&#xff0c;这意味着你的计算机缺少了一个重要的动态链接库文件。msvcp140.dll是微软Visual C Redistributable for Visual Studio 2015库的一…

硬件总线基础07:PCIe总线基础-事务层(2)

说在开头&#xff1a;关于哲学 在《东邪西毒》电影里欧阳锋说&#xff1a;“看来你的年纪也有四十出头了&#xff0c;这四十多年来&#xff0c;总有些事你是不愿再提&#xff0c;或是有些人不想再见&#xff0c;有的人曾经对不起你&#xff0c;也许你想过杀了他们&#xff0c;…

vue2中使用富文本编辑器tinyMCE全过程

第一步&#xff1a;安装TinyMCE $npm install tinymce5.10.0 -S $npm install tinymce/tinymce-vue3.0.1 -S 第二步&#xff1a;在node_modules中找到tinymce文件夹将内部文件移入pubilc/tinymce文件夹中在index.html文件中引入tinymce.min.js 注意&#xff1a;不把js文件放…

在 Arweave 中轻松管理文件:借助 4EVERLAND 完成 Web3 前端Path Manifests的终极指南

为什么使用Path Manifests&#xff1f; 当在 IPFS 上发布 NFT 时&#xff0c;图片和元数据会被上传到 IPFS 网络以获得一个根 CID&#xff0c;其形式如下&#xff1a; ipfs://bafybeic36ik6cngu37xbzmpytuvyo7z3lyeen44clkkxq5d263zj4nkzr4 通过使用这个根 CID&#xff0c;每…

运算放大器典型应用(二)

文章目录 十、采样保持电路十一、有源滤波电路二阶有源低通滤波器问题二阶截至频率如何算 十、采样保持电路 十一、有源滤波电路 给单片机供电R一般大于4.1Ω小于10Ω&#xff0c;太大会产生功耗 二阶有源低通滤波器问题 二阶截至频率如何算 通频带比较窄可以用这种&#xff0…

揭秘策划行业就业前景怎么样?

策划这个行业总的来说就是&#xff1a;门槛低&#xff0c;上限高&#xff01;&#xff01; 咱们一般说的策划也分很多类型&#xff0c;这里选取身边朋友做的最多的4种类型简单说说。 1、前端品牌策划&#xff0c;转型容易出路广 品牌策划以品牌思维为核心去分析公司的经营发…

计算机毕业设计 高校课程评价系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Revit SDK 介绍:AddSpaceAndZone 添加空间和分区

前言 这个例子介绍添加空间和分区。 内容 从 UI 界面看空间和分区。“分析”选项卡“空间和分区”面板&#xff1a; 创建空间 点击“Create Space”按钮&#xff0c;点“OK”&#xff0c;出现右边所示的6个空间。 核心逻辑&#xff1a; // SpaceManager::CreateSpaces(…

Redis的java客户端

在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;https://redis.io/resources/clients/ redis的java客户端 https://redis.io/resources/clients/#java 1.jedis使用 引入依赖 <dependency><groupId>redis.clients</groupId><artifac…

类和对象(1)

文章目录 1.面向过程和面向对象初步认识2.类的引入3.类的定义4.类的访问限定符和封装4.1访问限定符4.2封装 5.类的作用域6.类的实例化6.2结构体内存对齐规则 7.this指针7.2this指针的特性 封装&#xff08;补充&#xff09; 1.面向过程和面向对象初步认识 C面向对象但不纯面向…

时间和空间复杂度

目录 一、如何衡量一个算法的好坏 二、算法效率 三、时间复杂度 3.1 时间复杂度概念 3.2 大O的渐进表示法 3.3 推导大O阶方法 3.4 常见时间复杂度计算 3.5 空间复杂度 一、如何衡量一个算法的好坏 以下是求斐波那契数列的算法&#xff0c;这个算法是好还是不好呢&#xff1f…

ARM Linux DIY(八)USB 调试

前言 V3s 带有一个 USB 接口&#xff0c;将其设置为 HOST 或 OTG 模式&#xff0c;这样可以用来接入键盘、鼠标等 USB 外设。 USB 简介 USB 有两种设备&#xff1a;HOST 和 USB 功能设备。 在 USB2.0 中又引入了一个新的概念 OTG&#xff0c;即设备角色可以动态切换。 切换方…

ctfhub ssrf(3关)

文章目录 内网访问伪协议读取文件扫描端口 内网访问 根据该题目&#xff0c;是让我们访问127.0.0.1/falg.php&#xff0c;访问给出的链接后用bp抓包&#xff0c;修改URL&#xff0c;发送后得到flag&#xff1a; 伪协议读取文件 这题的让我们用伪协议&#xff0c;而网站的目录…

Java 基本类型和包装类

Java 是基于对象的&#xff0c;所以我们都需要以对象的想法来进行思维。 但 Java 又提供了 8 个基本类型&#xff0c;这 8 个基本类型基本上都和数字有关&#xff0c;是直接可以使用的类型。 基本类型大小包装器类型boolean/Booleanchar16bitCharacterbyte8bitByteshort16bitS…