当前位置: 首页 > article >正文

关于我重生到21世纪学C语言这件事——三子棋游戏!

与诸君共进步!!!

文章目录

  • 前言
  • 1. 游戏规则
  • 2. 多个文件实现链式访问
  • 3. 打印菜单
  • 4. 游戏核心内容的实现
    • 4.1 棋盘初始化
    • 4.2 棋盘展示
    • 4.3 玩家下棋
    • 4.4 电脑下棋
    • 4.5 胜负的判断
  • 5. 附源码的多个文件

前言

c语言三子棋是对大家对数组,函数,循环与分支等内容的考察。通过本篇文章你将学会如何制作出三子棋,坚持一段时间的复习相信你肯定能够掌握三子棋!!!

1. 游戏规则

1、人机双方轮流在格子里落子棋子,先连成三棋一线者视为胜利
2、棋盘被摆满棋子仍未分出胜利,视为平局

在这里插入图片描述

2. 多个文件实现链式访问

三子棋并不是一项容易的代码,需要我们进行分文件编写。
什么是分文件编写?

就是把我们的程序代码划分成多个文件,这样就不会把所有的代码都放在main.c里面,采用分模块的编程思想,进行功能划分,把每个功能不一样的单独放在一个c文件里,然后写头文件把它封装成可调用的一个函数,在主函数调用这个封装好的函数,编译的时候一起编译即可。

这样的好处就是:
1.功能被划分到各个文件
2.便于调试
3.使主程序简洁

来让给我们看看具体操作如下:

  • 头文件中创建game.h ----用来声明函数
  • 源文件中创建game.c—函数具体实现 / test.c—主题流程

3. 打印菜单

先创建一个菜单以展示进入退出游戏功能:

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

do…while 循环实现菜单使用,switch语句进行菜单选择

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入0 或 1  ,别输错了 ");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("人机,玩不起别玩\n");
			break;
		default:
			printf("这都能输错,你是人机吗?\n");
			break;
		}
	} while (input);
}

4. 游戏核心内容的实现

在 game()函数中实现整个游戏

4.1 棋盘初始化

在game.h中定义行和列为3

#define ROW 3
#define COL 3

game.h 中声明初始化函数Initboard

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

game.c 中实现初始化函数,创造三行三列的空格

void init_board(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++)
		{
			board[i][j] = ' ';
		}
	}
}


这时候我们的棋盘初始化就完成了

4.2 棋盘展示

接下来就是我们的棋盘打印了
game.h 文件中声明打印棋盘

void print_board(char board[ROW][COL], int row, int col)

game.c 文件中实现棋盘打印函数

void print_board(char board[ROW][COL], int row, int col)
{

	int i = 0;
	for (i = 0; i < row; i++)
	{
		//printf("%c | %c | %c \n", board[i][0], board[i][1], board[i][2]);  使用循环的方法来解决这个问题

		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		if (i < col - 1)
		{
			//printf("---|---|---\n");  使用循环的方法来解决这个问题

			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

棋盘打印完成

4.3 玩家下棋

game.h 声明玩家下棋函数

void player_move(char board[ROW][COL], int row, int col);

game.h 中实现玩家下棋函数。玩家所在下棋子不能出棋盘否则坐标非法重新下,所下棋子必须在无棋子格子中否则坐标备占有重新下,while实现玩家下错棋子重新下直到下正确退出循环

void player_move(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	printf("输入下棋坐标,记得中间有空格:>\n");
	int x = 0;
	int y = 0;
	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] = '*';

		}
		else
		{
			printf("这个位置已经被下了,天才,重新输一个\n");
		}
	}
	else
	{
		printf("坐标非法了,人机\n");
	}
}

这个时候我们玩家下棋的逻辑就完成了

4.4 电脑下棋

game.h 声明电脑下棋函数

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);

在game.c文件中实现电脑下棋函数。电脑随机下棋需要随机坐标引头文件#include <stdlib.h>,随机数生成需要头文件#include <time.h>。将电脑所下棋控制在棋盘内然后判断是否下在空棋盘内否则重下,while实现玩家下错棋子重新下直到下正确退出循环

oid computer_move(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;
		}
	}
}

4.5 胜负的判断

game.h 中声明胜负判断函数。

//判断游戏的胜负
char is_win(char board[ROW][COL], int row, int col);

game.c 中实现胜负判断函数。每次下棋结果共有四种1.玩家嬴 2.电脑嬴 3.平局 4.继续游戏
for循环实现行列三点成直线,if判断玩家或电脑三点成直线打印**‘ * ’‘ # ’**

char is_win(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 (is_full(board, row, col))
	{
		return 'Q';
	}

	//继续
	//没有玩家或者电脑赢,也没有平局,游戏继续
	return 'C';
}

5. 附源码的多个文件

1. game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
//初始化棋盘
void init_board(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++)
		{
			board[i][j] = ' ';
		}
	}
}



//打印棋盘
void print_board(char board[ROW][COL], int row, int col)
{

	int i = 0;
	for (i = 0; i < row; i++)
	{
		//printf("%c | %c | %c \n", board[i][0], board[i][1], board[i][2]);

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


//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	printf("输入下棋坐标,记得中间有空格:>\n");
	int x = 0;
	int y = 0;
	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] = '*';

		}
		else
		{
			printf("这个位置已经被下了,天才,重新输一个\n");
		}
	}
	else
	{
		printf("坐标非法了,人机\n");
	}
}



//人机下棋
void computer_move(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;
		}
	}
}


//判断棋盘是否满了
int is_full(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;
}



char is_win(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 (is_full(board, row, col))
	{
		return 'Q';
	}

	//继续
	//没有玩家或者电脑赢,也没有平局,游戏继续
	return 'C';
}

2. game.h

#pragma once

#include <stdio.h>

#define ROW 3
#define COL 3

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

//打印棋盘
void print_board(char board[ROW][COL], int row, int col);



//玩家下棋
void player_move(char board[ROW][COL], int row, int col);

//人机下棋
void computer_move(char board[ROW][COL], int row, int col);

char is_win(char board[ROW][COL], int row, int col);

3. test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

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



void game()
{
	char board[ROW][COL];

	char ret = 0;//返回结果 # * Q C判断输赢

	//初始化棋盘
	init_board(board, ROW, COL);

	//打印棋盘
	print_board(board, ROW, COL);

	//开始玩游戏
	while (1)
	{
		//people 下棋
		player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		//computer 下棋
		computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

	}
	if (ret == '#')
		printf("人机电脑都下不赢,真的cai\n");
	else if (ret == '*')
		printf("YOU WIN\n");
	else if (ret == 'Q')
		printf("我勒个平局啊,能不能把电脑赢下来!\n");

}


void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请输入0 或 1  ,别输错了 ");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("人机,玩不起别玩\n");
			break;
		default:
			printf("这都能输错,你是人机吗?\n");
			break;
		}
	} while (input);
}



int main()
{
	test();
	return 0;
}

这个三子棋游戏还是有些许的 bug ,就比如如果下同一个位置,所以我的建议是直接整一个 player1 和 player2 的对战。
最后就是一句话:天道酬勤,地道酬善,人道酬诚,商道酬信,业道酬精
我一直都相信勤能补拙,加油吧!!!


http://www.kler.cn/a/386580.html

相关文章:

  • linux,一、部署LNMP环境二、配置动静分离三、地址重写四、编写systemd Unit文件
  • Linux 实现自动登陆远程机器
  • STM32学习笔记-----UART的概念
  • Docker compose部署portainer
  • Ubuntu配置阿里云docker apt源
  • git下载慢下载不了?Git国内国外下载地址镜像,git安装视频教程
  • Java打造智能语音陪聊软件?提升用户体验的新路径
  • 【数据集】【YOLO】【目标检测】树木倒塌识别数据集 9957 张,YOLO道路树木断裂识别算法实战训练教程!
  • 让AI帮我用java实现EasyExel读取图片—支持WPS嵌入图片
  • python externally-managed-environment 外部管理环境
  • Kotlin 协程使用及其详解
  • 【go从零单排】结构嵌套struct embedding
  • C# 独立线程
  • 【Qwen2技术报告分析】解读模型架构 pre/post数据构建和模型评估
  • [Android] Graphic Buffer 的申请
  • C++:线程(thread)的创建、调用及销毁
  • Halcon resistor.hedv 使用多个对焦级别提取深度
  • .NET 黑名单上传 突破WAF防护的SoapShell (免杀版)
  • MySQL数据库专栏(五)连接MySQL数据库C API篇
  • Unity3D ASTC贴图压缩格式详解
  • MacOs上如何彻底卸载DevEco Studio?
  • VSCode 多工程联合调试
  • PythonBase02
  • MFC图形函数学习06——画椭圆弧线函数
  • EDUCODER头哥 SpringBoot 异常处理
  • UE5.4 PCG 自定义PCG蓝图节点