【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("|");
			else
				printf("\n");
		}
		if(i != rows - 1)
		{
			for(int j = 0; j < cols; j++)
			{
				printf("---");
				if(j != cols - 1)
					printf("|");
				else
					printf("\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 3

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("|");
			else
				printf("\n");
		}
		if (i != rows - 1)
		{
			for (int j = 0; j < cols; j++)
			{
				printf("---");
				if (j != cols - 1)
					printf("|");
				else
					printf("\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("|");
			else
				printf("\n");
		}
		if (i != rows - 1)
		{
			for (int j = 0; j < cols; j++)
			{
				printf("---");
				if (j != cols - 1)
					printf("|");
				else
					printf("\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( ̄▽ ̄)ブ

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sqllab第二十关通关笔记

知识点&#xff1a; cookie注入 可以进行url解析错误注入传参位置 get请求post请求cookie传参 输入admin admin进行登录&#xff0c;抓取当前数据包 通过放包发现是一个302跳转的响应包&#xff0c;页面只有一个 I Love Cookies&#xff1b;没什么信息 通过点击页面上方的按钮…

【Java】List, Set, Queue, Map 区别?

目录 List, Set, Queue, Map 区别&#xff1f; Collection和Collections List ArrayList 和 Array区别&#xff1f; ArrayList与LinkedList区别? ArrayList 能添加null吗&#xff1f; ArrayList 插入和删除时间复杂度&#xff1f; LinkedList 插入和删除时间复杂度&…

Vue2(4)——iHRM组织架构

组织架构-树组件应用 树形组件-用层级结构展示信息&#xff0c;可展开或折叠。 属性设置 data(绑定数据)props(设置属性)- children(设置子节点的字段名)/ label(设置显示内容的字段名)default-expand-all(默认展开所有节点) 组织架构-树组件自定义结构 显示右侧结构 节点结…

Vue2(三):绑定样式、条件渲染(v-if,v-show)、列表渲染(v-for)、key的原理、列表过滤、列表排序

一、绑定样式 1.绑定class样式 (1)字符串写法 适用于&#xff1a;样式类名不确定&#xff0c;需要动态获取。 <div id"root"><div class"basic" :class"mood" click"changeMood">test</div><!-- class是原本的…

【Python】进阶学习:基于Numpy实现按指定维度拼接两个数组

【Python】进阶学习&#xff1a;基于Numpy实现按指定维度拼接两个数组 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希…

第十三届蓝桥杯(C/C++ 大学B组)

目录 试题 A: 九进制转十进制 试题 B: 顺子日期 试题 C: 刷题统计 试题 D: 修剪灌木 试题 E: X 进制减法 试题 F: 统计子矩阵 试题 G: 积木画 试题 H: 扫雷 试题 I: 李白打酒加强版 试题 J: 砍竹子 试题 A: 九进制转十进制 九进制正整数 ( 2022 )转换成十进制等于多…

2000-2021年各省外商直接投资水平面板数据(含原始数据+计算结果)(无缺失)

2000-2021年各省外商直接投资水平面板数据&#xff08;含原始数据计算结果&#xff09;&#xff08;无缺失&#xff09; 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;外商直接投资额&#xff08;万美元&#xff09;、外商直接投资额&#xff08;万元&#xff09;、国…

MySQL语法分类 DQL(4)聚合函数

为了更好的学习这里给出基本表数据用于查询操作 create table student (id int, name varchar(20), age int, sex varchar(5),address varchar(100),math int,english int );insert into student (id,name,age,sex,address,math,english) values (1,马云,55,男,杭州,66,78),…

2024年【危险化学品经营单位主要负责人】找解析及危险化学品经营单位主要负责人模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位主要负责人找解析考前必练&#xff01;安全生产模拟考试一点通每个月更新危险化学品经营单位主要负责人模拟考试题目及答案&#xff01;多做几遍&#xff0c;其实通过危险化学品经营单位主要负责人…

移动云行动:5.5G技术引领数字化转型

刚刚结束的全国两会上&#xff0c;有人大代表建议应尽快发挥5G-A&#xff08;5.5G&#xff09;优势&#xff0c;加快试点城市布局。此前&#xff0c;中国移动已宣布将在300多个城市启动5.5G商用部署。在通信技术的历史长河中&#xff0c;4G改变了我们的生活方式&#xff0c;而5…

【Poi-tl Documentation】区块对标签显示隐藏改造

前置说明&#xff1a; <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency>模板&#xff1a; 删除行表格测试.docx 改造前测试效果 package run.siyuan…

Iframe 嵌入: 页面嵌入并保持自适应页面的宽高并铺满整个屏幕

文章目录 问题分析1. 嵌入 Iframe2. 样式3. 源码 问题 当我们使用 Iframe 嵌入页面后&#xff0c;会看到它只在小小的一部分进行展示&#xff0c;如何让它铺满整个屏幕 分析 1. 嵌入 Iframe <template><div><iframe :src"embeddedPageUrl" width…

【编程项目开源】微信飞机大战(鸿蒙版)

目标 仿微信飞机大战 效果 开发工具 下载DevEco Studio 工程截图 开源地址 https://gitee.com/lblbc/plane_game/tree/master/PlaneGame_hongmeng_ArkTS 关于 厦门大学计算机专业|华为八年高级工程师 专注《零基础学编程系列》 http://lblbc.cn/blog 包含&#xff1a;Ja…

18.相交链表

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&…

腾讯云2核4g服务器能支持多少人访问?没搞错吧

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

2024年【P气瓶充装】模拟考试及P气瓶充装证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 P气瓶充装模拟考试是安全生产模拟考试一点通生成的&#xff0c;P气瓶充装证模拟考试题库是根据P气瓶充装最新版教材汇编出P气瓶充装仿真模拟考试。2024年【P气瓶充装】模拟考试及P气瓶充装证考试 1、【多选题】《中华…

Java中的实用类讲解(上篇)

如果想观看更多Java内容 可上我的个人主页关注我&#xff0c;地址子逸爱编程-CSDN博客https://blog.csdn.net/a15766649633?spm1000.2115.3001.5343 使用工具 IntelliJ IDEA Community Edition 2023.1.4 使用语言 Java8 代码能力快速提升小方法&#xff0c;看完代码自己敲…

python 实现阿里云OSS文件上传

因为我们出口的带宽限制&#xff0c;测试经常找我给他上传个包到阿里云的对象存储&#xff0c;虽然传起来也不是很费事&#xff0c;但是出于运维的职业素养&#xff0c;特意写了一个自动上传的接口&#xff0c;代码如下&#xff1a; # -*- coding: UTF-8 -*- from flask imp…

【保姆及教程】简直不要太爽了!md文件图床工具picgo配合typora和阿里云oss存储,实现文md文件的复制转贴

md文件图床工具picgo的安装和使用、配合阿里云面向对象oss 一、网址 官方网址&#xff1a;https://molunerfinn.com/PicGo/ github地址&#xff1a;https://github.com/Molunerfinn/picgo/releases 选择对应的版本下载即可 但也可以提供我给你的下载的地址&#xff1a; 方…

前端学习之css选择器--基本选择器、关系选择器、属性选择器、复合选择器、伪类选择器

目录 基本选择器 结果 关系选择器 结果 父子关系 祖先后代关系 相邻兄弟关系 兄弟关系 ​编辑 属性选择器 结果 复合选择器 结果 伪类选择器 结果 伪类选择器-操作标签 结果 未访问 访问后 悬停 基本选择器 <!DOCTYPE html> <html lang"en"…