【C语言步行梯】C语言实现三子棋游戏(含详细分析)

在这里插入图片描述

🎯每日努力一点点,技术进步看得见
🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~

文章目录

  • 需求分析
  • 具体实现
    • 主函数体
    • 菜单实现
    • 游戏实现
      • 棋盘初始化
      • 显示棋盘
      • 玩家下棋
      • 电脑下棋
      • 判断棋盘是否已满
      • 判断输赢
      • 游戏函数主体
    • 完整代码
    • 分文件编写


需求分析

上课摸鱼的时候,我们可以画个九宫格,在里面画上圆圈,或者叉。现在,我们通过C语言实现这个三子棋游戏,实现用户与电脑下棋。
在这里插入图片描述

具体实现

主函数体

在主函数体内,我们需要调用一个menu函数,用它提醒用户:输入1开始游戏,输入0退出游戏。接收用户输入后,通过switch语句,执行game()函数或者退出游戏。menu和game函数将在下文中讲解。

int main()
{int input = 0;do{menu();printf("请输入您的选择>");scanf("%d", &input);switch(input){case 1:game();//游戏具体实现函数break;case 0:printf("游戏结束\n");break;default:printf("输入有误,请重新输入\n");}}while(input);return 0;
}

菜单实现

首先,我们需要一个菜单,提示用户:输入1可以开始游戏,输入0会退出游戏。我通过封装一个menu函数实现↓↓↓

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

游戏实现

棋盘初始化

我们通过一个char board[3][3]来存储棋盘。如果board[i][j]为空格,表示该位置还没有下棋;如果board[i][j]存储’*‘(星号),表示该位置用户已经下棋;如果board[i][j]存储‘#’(井号),表示该位置电脑已经下棋。
在这里插入图片描述
但在开始游戏前,我们需要将棋盘数组每个元素都初始化空格。↓↓↓

void initBoard(char board[ROW][COL], int rows, int cols)
{for(int i = 0; i < rows; i++){for(int j = 0; j < cols; j++){board[i][j] = ' ';}}
}

显示棋盘

在游戏过程中,玩家或者电脑下完棋后,需要显示棋盘。用户才能知道当前棋盘的落子情况。

void displayBoard(char board[ROW][COL], int rows, int cols)
{for(int i = 0; i < rows; i++){for(int j = 0; j < cols; j++){printf(" %c ", board[i][j]);if(j != cols - 1)printf("|");elseprintf("\n");}if(i != rows - 1){for(int j = 0; j < cols; j++){printf("---");if(j != cols - 1)printf("|");elseprintf("\n");}}}
}

上方打印棋盘效果如下图所示。
在这里插入图片描述

玩家下棋

提示玩家输入下棋的坐标,接收到坐标后,我们需要判断该坐标是否为空格(表示还没有棋子),如果是空格,则下棋成功;如果不是空格,则下棋失败。

void playerAddChess(char board[ROW][COL], int rows, int cols)
{printf("玩家下棋\n");displayBoard(board, rows, cols);int x = 0;int y = 0;while (1){printf("请输入下棋坐标>");scanf("%d %d", &x, &y);if (x > rows || x <= 0 || y > cols || y <= 0){printf("该坐标超出棋盘边界,请重新输入\n");continue;}if (board[x - 1][y - 1] != ' '){printf("该坐标已经下过棋子,请重新输入\n");continue;}board[x - 1][y - 1] = '*';break;}}

电脑下棋

通过随机数函数生成x,y坐标。如果生成的坐标位置为空格,则电脑下棋完成;如果该坐标已被占用,则重新生成坐标。

void computerAddChess(char board[ROW][COL], int rows, int cols)
{printf("电脑下棋\n");int x = 0;int y = 0;while(1){x = rand() % 3 + 1;y = rand() % 3 + 1;if(board[x][y] != ' ')continue;else{board[x - 1][y - 1] = '#';break;}}displayBoard(board, rows, cols);
}

判断棋盘是否已满

假设经过判断,没有三个棋子能连成一条直线,那就无法判断谁赢谁输。若在此时,棋盘已经满了,但还是没有三个棋子练成一条直线,则双方平手(平局)。如下图所示。
在这里插入图片描述
因此,我们需要一个函数,用来判断棋盘是否已经满了。如果满了,则游戏结束;没有满则游戏继续。

int isFull(char board[ROW][COL], int rows, int cols)
{for(int i = 0; i < rows; i++){for(int j = 0; j < cols; j++){if(board[i][j] == ' ')return 0;}}return 1;
}

判断输赢

在电脑或者玩家下完棋后,我们需要判断当前状态下,是否有人获胜。根据三子棋的规则,三个棋子连成直线即获胜。下面函数中,如果玩家获胜,则返回’*‘(星号);如果电脑获胜,则返回’#‘(井号);如果棋盘满了,则返回Q,表示平局;如果没人获胜,棋盘也没满,则游戏继续,返回’C’。

char isWin(char board[ROW][COL], int rows, int cols)
{//对每一行判断for(int i = 0; i < rows; i++){if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')return board[i][0];}//对每一列判断for(int i = 0; i < cols; 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[0][0];if(board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')return board[0][2];if(isFull(board, rows, cols))return 'Q';return 'C';
}

游戏函数主体

在实现了上述各个函数后,我们只要稍加组织,就可以实现游戏了。

void game()
{char board[ROW][COL] = { 0 };initBoard(board, ROW, COL);char ret = 0;while (1){playerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;computerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;}switch (ret){case '*':printf("玩家获胜\n");break;case '#':printf("电脑获胜\n");break;case 'Q':printf("平局\n");break;}
}

完整代码

上面代码中主函数中没有加入随机数种子,在下面代码中加入了srand((unsigned int)time(NULL)),同时对于上面出现ROW、COL的宏定义等也在下方代码整体给出。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3
#define COL 3void menu()
{printf("*********************************************\n");printf("************** 1.play  0.exit ***************\n");printf("*********************************************\n");
}void initBoard(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = ' ';}}
}void displayBoard(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){printf(" %c ", board[i][j]);if (j != cols - 1)printf("|");elseprintf("\n");}if (i != rows - 1){for (int j = 0; j < cols; j++){printf("---");if (j != cols - 1)printf("|");elseprintf("\n");}}}
}void playerAddChess(char board[ROW][COL], int rows, int cols)
{printf("玩家下棋\n");displayBoard(board, rows, cols);int x = 0;int y = 0;while (1){printf("请输入下棋坐标>");scanf("%d %d", &x, &y);if (x > rows || x <= 0 || y > cols || y <= 0){printf("该坐标超出棋盘边界,请重新输入\n");continue;}if (board[x - 1][y - 1] != ' '){printf("该坐标已经下过棋子,请重新输入\n");continue;}board[x - 1][y - 1] = '*';break;}}void computerAddChess(char board[ROW][COL], int rows, int cols)
{printf("电脑下棋\n");int x = 0;int y = 0;while (1){x = rand() % 3 + 1;y = rand() % 3 + 1;if (board[x - 1][y - 1] != ' ')continue;else{board[x - 1][y - 1] = '#';break;}}displayBoard(board, rows, cols);
}int isFull(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){if (board[i][j] == ' ')return 0;}}return 1;
}char isWin(char board[ROW][COL], int rows, int cols)
{//对每一行判断for (int i = 0; i < rows; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')return board[i][0];}//对每一列判断for (int i = 0; i < cols; 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[0][0];if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')return board[0][2];if (isFull(board, rows, cols))return 'Q';return 'C';
}void game()
{char board[ROW][COL] = { 0 };initBoard(board, ROW, COL);char ret = 0;while (1){playerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;computerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;}switch (ret){case '*':printf("玩家获胜\n");break;case '#':printf("电脑获胜\n");break;case 'Q':printf("平局\n");break;}
}int main()
{int input = 0;do{menu();printf("请输入您的选择>");scanf("%d", &input);switch (input){case 1:game();//游戏具体实现函数break;case 0:printf("游戏结束\n");break;default:printf("输入有误,请重新输入\n");}} while (input);return 0;
}

分文件编写

可以创建game.h保存头文件,及各函数的函数声明;game.c保存各个函数的具体实现;main.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 rows, int cols);//菜单
void menu();//打印棋盘
void displayBoard(char board[ROW][COL], int rows, int cols);//玩家下棋
void playerAddChess(char board[ROW][COL], int rows, int cols);//电脑下棋
void computerAddChess(char board[ROW][COL], int rows, int cols);//游戏
void game();//判断棋盘是否已经满了
int isFull(char board[ROW][COL], int rows, int cols);//判断是否赢
char isWin(char board[ROW][COL], int rows, int cols);

game.c ↓↓↓

#include "game.h"void menu()
{printf("*********************************************\n");printf("************** 1.play  0.exit ***************\n");printf("*********************************************\n");
}void initBoard(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = ' ';}}
}void displayBoard(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){printf(" %c ", board[i][j]);if (j != cols - 1)printf("|");elseprintf("\n");}if (i != rows - 1){for (int j = 0; j < cols; j++){printf("---");if (j != cols - 1)printf("|");elseprintf("\n");}}}
}void playerAddChess(char board[ROW][COL], int rows, int cols)
{printf("玩家下棋\n");displayBoard(board, rows, cols);int x = 0;int y = 0;while (1){printf("请输入下棋坐标>");scanf("%d %d", &x, &y);if (x > rows || x <= 0 || y > cols || y <= 0){printf("该坐标超出棋盘边界,请重新输入\n");continue;}if (board[x - 1][y - 1] != ' '){printf("该坐标已经下过棋子,请重新输入\n");continue;}board[x - 1][y - 1] = '*';break;}}void computerAddChess(char board[ROW][COL], int rows, int cols)
{printf("电脑下棋\n");int x = 0;int y = 0;while (1){x = rand() % 3 + 1;y = rand() % 3 + 1;if (board[x - 1][y - 1] != ' ')continue;else{board[x - 1][y - 1] = '#';break;}}displayBoard(board, rows, cols);
}int isFull(char board[ROW][COL], int rows, int cols)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){if (board[i][j] == ' ')return 0;}}return 1;
}char isWin(char board[ROW][COL], int rows, int cols)
{//对每一行判断for (int i = 0; i < rows; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')return board[i][0];}//对每一列判断for (int i = 0; i < cols; 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[0][0];if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')return board[0][2];if (isFull(board, rows, cols))return 'Q';return 'C';
}void game()
{char board[ROW][COL] = { 0 };initBoard(board, ROW, COL);char ret = 0;while (1){playerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;computerAddChess(board, ROW, COL);ret = isWin(board, ROW, COL);if (ret != 'C')break;}switch (ret){case '*':printf("玩家获胜\n");break;case '#':printf("电脑获胜\n");break;case 'Q':printf("平局\n");break;}
}

main.c ↓↓↓

int main()
{int input = 0;do{menu();printf("请输入您的选择>");scanf("%d", &input);switch (input){case 1:game();//游戏具体实现函数break;case 0:printf("游戏结束\n");break;default:printf("输入有误,请重新输入\n");}} while (input);return 0;
}

🚩这篇文章结束了~~
如果文章中出现了错误,欢迎私信或留言。(๑•̀ㅂ•́)و✧
有任何疑问请评论或私信哦~~o( ̄▽ ̄)ブ

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

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

相关文章

高级JAVA工程师解决生产环境JVM宕机Java进程挡掉操作系统内存异常实例讲解

高级JAVA工程师解决生产环境JVM宕机Java进程挡掉内存溢出实例讲解 一、事故描述 生产环境Java进程莫名挡掉&#xff0c;JVM宕机。监控平台报警。生产停了&#xff0c;老板急了&#xff0c;客户爆了&#xff0c;怎么迅速解决事故&#xff1f;每次出现生产事故&#xff0c;都是…

IT廉连看——Uniapp——模板语法

IT廉连看——Uniapp——模板语法 众所周知&#xff0c;Uniapp是使用vue.js框架开发出来的&#xff0c;所以说它可以使用vue中的语法和指令来开发我们的项目。如果没有学习过vue的话开发起来会比较吃力&#xff0c;所以这节课就带大家学习几个常用的vue知识。如果有学习过vue&a…

【五、接口自动化测试】

大家好&#xff0c;我是山茶&#xff0c;一个探索AI 测试的程序员 在网上看到了许多关于post与get之间区别的帖子&#xff0c;也有很多帖子是直接粘贴复制的&#xff0c;甚至连标题、符号都没改&#xff0c;甚至还有很多争议 一、post、get 关于post与get之间区别&#xff0c;…

BigDL-LLM 安装指南——在iGPU集成显卡下使用BigDL-LLM大模型库加速LLM

文章目录 iGPU是什么&#xff1f;一、环境准备1.1 Visual Studio 2022 Community 安装1.2 安装或更新最新版本的GPU驱动程序1.3 安装英特尔oneAPI工具包2024.0版本1.4 安装Anaconda 二、BigDL -LLM 安装2.1 创建虚拟环境2.2 激活虚拟环境2.3 安装bigdl-llm[xpu] 三、运行环境配…

nacos做注册注册中心go语言实战教程(服务的注册与获取)

背景 随着访问量的逐渐增大&#xff0c;单体应用结构渐渐不满足需求&#xff0c;在微服务出现之后引用被拆分为一个个的服务&#xff0c;服务之间可以互相访问。初期服务之间的调用只要知道服务地址和端口即可&#xff0c;而服务会出现增减、故障、升级等变化导致端口和ip也变…

法规解读 | 坚持总体国家安全观,新修订的《保守国家秘密法》今年5月1日起施行!

2024年2月27日&#xff0c;第十四届全国人大常委会第八次会议表决通过新修订的《中华人民共和国保守国家秘密法》&#xff08;以下简称保密法&#xff09;&#xff0c;自2024年5月1日起施行。 本次保密法修订坚持总体国家安全观&#xff0c;统筹发展与安全。 一方面吸收了一些工…

雅特力AT32A403开发板评测 05 0.96寸 IIC接口 OLED模块显示

雅特力AT32A403开发板评测 05 0.96寸 IIC接口 OLED模块显示 1.软硬件平台 软硬件平台 AT32A403A Board开发板 MDK-ARM Keil 0.96寸 IIC接口 OLED显示模块 2.IIC总线 处理器和芯片间的通信可以形象的比喻成两个人讲话&#xff1a;1、你说的别人得能听懂&#xff1a;双方…

OPPO后端二面,凉了!

这篇文章的问题来源于一个读者之前分享的 OPPO 后端凉经&#xff0c;我对比较典型的一些问题进行了分类并给出了详细的参考答案。希望能对正在参加面试的朋友们能够有点帮助&#xff01; Java String 为什么是不可变的? public final class String implements java.io.Seri…

4.MAC平台Python的下载、安装(含Python2.7+Python3.12双版本环境变量配置)——《跟老吕学Python编程》

4.MAC平台Python的下载、安装&#xff08;含Python2.7Python3.12双版本环境变量配置&#xff09;——《跟老吕学Python编程》&#xff09;——跟老吕学Python编程 一、下载MAC版Python1.Python官网2.MAC版Python下载网址 二、在MAC安装Python1.在MAC安装Python2.阅读Python重要…

JVM之调优(一)

背景&#xff1a;生产环境由于堆内存较大&#xff0c;fullgc 垃圾回收导致程序卡顿问题&#xff08;假死&#xff09; 目录 一、程序卡顿导致的影响 前端页面空白后端数据重复 二、解决方法 降低堆内存大小使用合适的垃圾回收器&#xff08;可以尝试&#xff0c;还未进行测试…

ROS 语音交互(三) tts

目录 一、模型选择 二、流程 三、核心代码展示 一、模型选择 科大讯飞超拟人识别 二、流程 超拟⼈合成协议 | 讯飞开放平台文档中心 (xfyun.cn) 三、核心代码展示 # coding: utf-8 import _thread as thread import os import time import base64import base64 import …

雅特力车规级MCU-AT32A403A开发板评测 06 GC9A01 SPI-LCD 1.28圆形屏幕

雅特力车规级MCU-AT32A403A开发板评测 06 GC9A01 SPI-LCD 1.28圆形屏幕 硬件平台 AT32A403A Board开发板 1.28寸圆形彩色TFT显示屏高清IPS 模块240X240 SPI接口GC9A01 产品介绍 推荐一个屏幕资料参考网站 http://www.lcdwiki.com/1.28inch_IPS_Module 1.28寸圆形IPS彩屏&…