【C语言小游戏】详解三子棋,深刻掌握二维数组

news2024/11/19 15:39:45

前言:
大家好,我是良辰丫,今天带领大家实现一个C语言小游戏,主要运用的知识点为二维数组,希望这篇文章让大家对二维数组有更深刻的认识。

💞看似不起波澜的日复一日,会突然在某一天让人看到坚持的意义。💟
在这里插入图片描述

目录

  • 🚢1、游戏思路
  • 🚢2、游戏板块详解
    • 🚁2.1 游戏菜单
    • 🚁2.2 游戏环节
    • 🚁2.3 代码块的具体实现
      • 🍖2.3.1 初始化棋盘
      • 🍖2.3.2 打印棋盘
      • 🍖2.3.3 玩家下棋
      • 🍖2.3.4 电脑下棋
      • 🍖2.3.5 判断棋盘是否满
      • 🍖2.3.6 判断游戏输赢状态
  • 🚢3、游戏整体代码
    • 🚁test.h
    • 🚁test.c
    • 🚁game.c


🚢1、游戏思路

或许三子棋大家还是稍微有点陌生,但是大家小时候肯定经常玩,只不过各个地方叫的名字不同罢了。

  1. 首先要有棋盘,没有棋盘怎能像棋呢?
  2. 玩家和电脑进行博弈,每走一步需要打印一次棋盘,这样才能让玩家看的出来下一步该如何走。
  3. 用一个死循环可以让玩家游戏结束后可以继续游戏。
  4. 建立三个源文件。(好处)

🚢2、游戏板块详解

🚁2.1 游戏菜单

既然是游戏,那么就要像样一点,有一个菜单,让玩家可以很好的体验游戏。

void menu()
{
	printf("*********************\n");
	printf("****** 1.start ******\n");
	printf("****** 2.exit  ******\n");
	printf("*********************\n");
}

想必目录这一板块大家一看就懂,就是用了多条输出语句写了一个简单的目录,然后通过调用很好的呈现给玩家。

🚁2.2 游戏环节

  • 玩家可以通过自己的需求对内容进行选择,可以选择开始游戏和退出游戏。
  • 在这里我们选择switch语句进行选择,用do…while语句进行循环操作,可以让玩家进行重新玩游戏操作。
  • do…while的优势是先进行一次循环体,然后再条件判断,巧妙的是我们的退出序号是0,input等于0时,条件为假,将不再执行循环体,游戏将不再执行。
do
	{
		menu();
		printf("请选择序号\n");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新选择\n");
		}
	} while (input);
  • 选择游戏序号,调用游戏函数,游戏中当达到一定条件时,本次游戏就结束了,很简单,无非就是玩家赢,电脑赢以及平局,那么我们就来设置一个变量接收游戏状态,达到条件结束游戏。
  • 紧接着,我们需要用一个死循环进行玩家和电脑下棋,达到条件后结束循环。
  • 但是,需要注意的是,玩家或者电脑没下完一次棋都要打印一次棋盘,这样玩家才能判断自己以及电脑把棋子下到什么地方了,一定要全方面考虑。
void game()
{
	char ret = 0;
	//用于接收游戏输赢状态
	char board[ROW][COL] = { 0 };
	initBoard(board, ROW, COL);
	displayBoard(board, ROW, COL);
	while(1)//死循环下棋,达到一定条件跳出循环
	{
		playerBoard(board, ROW, COL);
		displayBoard(board, ROW, COL);
		ret = isWin(board, ROW, COL);
		if (ret != 'C')//C是定义的继续的标志
			break;
		computerBoard(board, ROW, COL);
		displayBoard(board, ROW, COL);
		if (ret != 'C')//C是定义的继续的标志
			break;
	}
	if (ret == '*')
	{
		printf("恭喜玩家赢了\n");
	}
	else if (ret == '#')
		printf("电脑赢了,玩家继续加油\n");
	else if (ret == 'Q')
		printf("平局了\n");
}

游戏思路:

  1. 首先初始化棋盘,展示棋盘,让玩家可以看到棋盘,用死循环可以让玩家与电脑持续下棋,直到玩家赢,或者电脑赢,又或者平局,结束游戏。
  2. 游戏结束后玩家可以继续进行选择,是继续玩还是退出游戏,后面写到main函数中。。。 玩家先开始下棋,下一步棋就要显示一次棋盘,随后电脑下棋,电脑下棋一次也要显示一次棋盘,这样玩家才容易看清棋的局势。

🚁2.3 代码块的具体实现

🍖2.3.1 初始化棋盘

//1.初始化棋盘
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.2 打印棋盘

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

棋盘总要有一个棋盘的样子,边边框框总是要有的。
在这里插入图片描述

🍖2.3.3 玩家下棋

void playerBoard(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入要下棋的坐标:>");
		scanf("%d %d", &x, &y);
		//1.坐标的合法性
		//2.坐标是否被占用
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
}

轮到玩家下棋系统要进行提醒,系统要判断玩家下棋的位置是否有棋子,下棋位置是否合法,而且,需要注意的是,我们的数组下标是从0开始的,但是==玩家并不知道所谓的坐标需要从0开始,==因此呢,我们需要让玩家输入的坐标减一,方能满足系统中二维数组的下标要求。

🍖2.3.4 电脑下棋

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

对于我们新手来说,电脑具有智能识别功能需要再增加各种代码进行判断棋盘,今天我们主要的目的是应用一下二维数组,因此呢?我们只需要让电脑做到随机下棋的目的就OK啦,可千万别觉得电脑傻乎乎的哦,我们只是没有赋予它高超的功能。
我们主要运用随机函数rand,横坐标和纵坐标具有随机性,如果该位置为空时,电脑就可以落子。

🍖2.3.5 判断棋盘是否满

static int isFull(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++)
		{
			if (' ' == board[i][j])
			{
				return 0;
			}
		}
	}

	return 1;
}

该函数是为了判断棋盘是否有空位置,有空位置返回0,无空位置返回1。当棋盘满时没有输赢时则判平局。

🍖2.3.6 判断游戏输赢状态

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][0] != ' ')
		{
			return board[i][0];
		}
	}

	for (i = 0; i < col; 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[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) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

横3子或者斜3子一样,则分出输赢。
不知道大家注意了没有,我们用的返回值是*或者#,这样我们可以减少代码的冗余性,某一方赢了就返回它的棋子形状,这样不用多次写一个多余的代码块。
在这里插入图片描述

🚢3、游戏整体代码

🚁test.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
//保证同一个文件不会同时出现两次
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//1.初始化棋盘
void initBoard(char board[ROW][COL], int row, int col);
//2.打印棋盘
void displayBoard(char board[ROW][COL], int row, int col);
//3.玩家下棋
void playerBoard(char board[ROW][COL], int row, int col);
//4.电脑下棋
void computerBoard(char board[ROW][COL], int row, int col);
//5.判断游戏输赢状态
char isWin(char board[ROW][COL], int row, int col);

🚁test.c

#include"game.h"
void menu()
{
	printf("*********************\n");
	printf("****** 1.start ******\n");
	printf("****** 2.exit  ******\n");
	printf("*********************\n");
}
void game()
{
	char ret = 0;
	//用于接收游戏输赢状态
	char board[ROW][COL] = { 0 };
	initBoard(board, ROW, COL);
	displayBoard(board, ROW, COL);
	while(1)//死循环下棋,达到一定条件跳出循环
	{
		playerBoard(board, ROW, COL);
		displayBoard(board, ROW, COL);
		ret = isWin(board, ROW, COL);
		if (ret != 'C')//C是定义的继续的标志
			break;
		computerBoard(board, ROW, COL);
		displayBoard(board, ROW, COL);
		if (ret != 'C')//C是定义的继续的标志
			break;
	}
	if (ret == '*')
	{
		printf("恭喜玩家赢了\n");
	}
	else if (ret == '#')
		printf("电脑赢,玩家还需再接再厉\n");
	else if (ret == 'Q')
		printf("平局了\n");
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择序号\n");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新选择\n");
		}
	} while (input);
	return 0;
}

🚁game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//1.初始化棋盘
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.打印棋盘
void displayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}
//3.玩家下棋
void playerBoard(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入要下棋的坐标:>");
		scanf("%d %d", &x, &y);
		//1.坐标的合法性
		//2.坐标是否被占用
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
}
//4.电脑下棋
void computerBoard(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
//判断棋盘是否满
static int isFull(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++)
		{
			if (' ' == board[i][j])
			{
				return 0;
			}
		}
	}

	return 1;
}
//5.判断游戏输赢状态
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][0] != ' ')
		{
			return board[i][0];
		}
	}

	for (i = 0; i < col; 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[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) == 1)
	{
		return 'Q';
	}

	//继续
	return 'C';
}

后序:
这篇文章是一个对于二维数组以及函数的一个简单的应用,希望可以帮助大家更好的理解数组及其函数,重新认识一下,我是良辰,希望与大家成为朋友,一起共勉,加油加油再加油。

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

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

相关文章

【day14】【洛谷算法题】-P5711闰年判断-刷题反思集[入门2分支结构]

&#x1f338;大家好&#xff0c;我是花无缺&#xff0c;一枚热爱生活的新时代青年&#xff0c;感谢你的阅读&#x1f970;~ &#x1f468;‍&#x1f4bb;个人主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专…

PC - 史上最简单的远程访问群晖 NAS 方法

文章目录1、下载安装cpolar群晖套件1.1 注册cpolar账号1.2 下载cpolar群晖套件1.3 安装cpolar群晖套件2、创建隧道映射5000端口2.1 打开cpolar群晖套件2.2 创建远程访问隧道2.3 获取公网URL地址3、公网远程群晖NAS教大家一个新手小白都可以轻松掌握的远程群晖NAS方法&#xff0…

算法的时间复杂度和空间复杂度

文章目录算法的时间复杂度和空间复杂度算法效率算法的复杂度时间复杂度时间复杂度的概念大O的渐进表示法常见的时间复杂度计算举例空间复杂度常见复杂度对比复杂度的oj练习算法的时间复杂度和空间复杂度 算法效率时间复杂度空间复杂度常见的时间复杂度以及复杂度的oj练习 算法…

【题解】方格取数

&#x1f60a;博主目前也在学习&#xff0c;有错误欢迎指正&#x1f60a; &#x1f308;保持热爱 奔赴星海&#x1f308; 文章目录一、题目1、题目描述3、原题链接二、解题报告1、思路分析2、代码详解三、本题知识一、题目 1、题目描述 输入格式&#xff1a; 输入的第一行为一…

Java并发编程实战之互斥锁

文章目录Java并发编程实战之互斥锁如何解决原子性问题&#xff1f;锁模型Java synchronized 关键字Java synchronized 关键字 只能解决原子性问题&#xff1f;如何正确使用Java synchronized 关键字&#xff1f;锁和受保护资源的合理关联关系死锁预防死锁破坏占有且等待条件破坏…

字节一面:TCP 三次握手,问的好细!

大家好&#xff0c;我是小林。 有位读者在面试字节时&#xff0c;被问到这么个问题&#xff1a; 概括起来&#xff0c;是这两个问题&#xff1a; TCP 三次握手中&#xff0c;客户端收到的第二次握手中 ack 确认号不是自己期望的&#xff0c;会发生什么&#xff1f;是直接丢弃…

1024程序员节:从关注自身健康开始

今天是1024程序员节&#xff0c;我们已经历经了尽三年的疫情&#xff0c;健康是我们最应该关注的事情&#xff0c;在这个特别的日子里&#xff0c;希望程序员们都能更加爱惜自己的身体&#xff0c;少加班&#xff0c;多锻炼。 健身不仅是保持健康体魄的关键要素之一&#xff0c…

基于ssm高校科研管理系统-计算机毕业设计源码+LW文档

【摘 要】高校科研管理是一项重要而又繁琐的工作&#xff0c;有效的信息管理平台可以大大缓解科研管理压力&#xff0c;减少工作量。本文以石河子大学信息科学与技术学院为应用背景&#xff0c;开发教师教学信息与论文信息交流平台。该系统能对科研成果和课题进行较为全面的管理…

第十三届蓝桥杯C++B组国赛I题——齿轮 (AC)

目录1.齿轮1.题目描述2.输入格式3.输出格式4.样例输入5.样例输出6.样例说明6.数据范围7.原题链接2.解题思路3.Ac_code1.齿轮 1.题目描述 这天, 小明在组装齿轮。 他一共有 nnn 个齿轮, 第 iii 个齿轮的半径为 rir_{i}ri​, 他需要把这 nnn 个齿轮按一定 顺序从左到右组装起来…

[附源码]Java计算机毕业设计SSM公司办公自动化系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

10个实用的CSS样式之悬浮卡片

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位喜欢写作&#xff0c;计科专业大三菜鸟 &#x1f3e1;个人主页&#xff1a;starry陆离 &#x1f4da;订阅专栏&#xff1a;『10个实用的CSS样式』 10个实用的CSS样式之悬浮卡片1.简介2.布局设计3.样式美化3.1body美化3.2c…

隔离技术之端口隔离

端口隔离技术 端口隔离主要应用在同一个vlan内&#xff0c;不同的用户之间不可互相访问 好处&#xff1a; 可以避免广播风暴&#xff0c;节约了vlan的资源&#xff0c;提高了用户之间的安全性 比如一个用户的电脑中病毒了&#xff0c;不会影响到其他用户 端口隔离是基于端口&…

网络原理——No.2 传输层_TCP的连接管理(画图理解三次握手与四次挥手)

JavaEE传送门JavaEE 网络原理——传输层_UDP 网络原理——No.1 传输层_TCP的确认应答机制与超时重传 目录TCP的连接管理三次握手(建立连接)四次挥手(断开连接)TCP的连接管理 描述的就是 TCP 建立链接和断开链接的过程 TCP 的链接, 只是一个 “逻辑上的” “虚拟的连接” (只要…

qt学习笔记4:QMainWindow 菜单栏、工具栏、状态栏、铆接部件、

在创建基类的时候&#xff0c;有三大选择&#xff0c;一个是QWidge 空窗口&#xff0c; 另一个就是QMainWindow QMainWindow是一个为用户提供主窗口的类&#xff0c;包含一个菜单栏&#xff0c;多个工具栏&#xff0c;多个链接部件&#xff0c; 一个状态栏以及一个中心部件&…

《数据结构》(六)八大排序(上)

生活中大家从小到大处处可见排队&#xff0c;但是排队有哪些快速的方法你了解吗&#xff1f; 八大排序排序的基本概念插入排序直接插入排序基本思想代码直接插入排序总结希尔排序基本思想代码希尔排序总结选择排序直接选择排序基本思想&#xff1a;代码直接选择排序总结堆排序堆…

大数据基础之java常用API一

常用API1. Object类2. String类String案例1. Object类 构造方法空参构造全参构造 Object类: 是所有类的基类,或者说公共父类,每个类都直接或者间接的继承自Object,所以该类中有的方法,其他类中都有 构造方法: public Object(); 所有类的构造方法中都会默认调用super() 会逐级调…

C#里在子窗口与父窗口之间进行数据传送

在C#里经常需要在子窗口与父窗口之间进行数据传送,或者调用,虽然有很多方法可以实现,但是采用委托还是比较简单和直接的方式。 所以这次针对委托来演示一下怎么样实现这种功能。 下面先来创建一个带两窗口的例子,如下图所示: 接着来看一下,创建父窗口的代码: namespace…

【C++笔试强训】第十一天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 &#x1f4a6; &…

vite基础知识-1

为什么选择vite&#xff1f; 讲vite之前&#xff0c;我们先来了解一下webpack的原理。 webpack支持多种模块化&#xff08;浏览器端和服务端都可以运行&#xff09;。比如&#xff1a; // index.js const lodash require("lodash"); // commonjs规范 import React…

win10 docker desktop 报 docker desktop stopped

win10电脑安装doker deskto遇到一些问题解决过程记录 报 docker desktop stopped 没过多会, docker desktop就自动退出了, 要以理解为闪退 网上查了一下原因, 虚拟化可能没设置 进入bios, 发现笔记本电脑没有这个设置 重启电脑后, 弹出消息 WSL 2 installation is incompl…