【C语言】三子棋游戏(超详解+源码)

🍉🍉前言

🕸️🕸️大家好!我是BIGPIG🐖,一个想要和大家共同进步的博主🌞。

👉👈游戏介绍

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

🐬部分游戏展示

🤖🤖实现游戏思路

1.创建一个游戏菜单

2.创建一个棋盘

3.玩家下棋落子,电脑下棋落

4.判断输赢

☕☕打印游戏菜单

🌳打印游戏菜单并让玩家选择是否进行游戏,比较简单,大家自行发挥。代码如下参考

#include "三子棋game.h"//此处是创建了一个头文件将我们游戏需要的头文件放在里面,后续都会提到
//上述头文件暂时包含了<stdio.h>
void menu()//自行创建的函数来打印菜单
{
	printf("****************\n");
	printf("*****1.play*****\n");
	printf("*****0.exit*****\n");
	printf("****************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();调用函数打印菜单
		printf("请选择.>");
		scanf("%d", &input);//玩家进行选择
		switch (input)//对玩家的选择进行判断---游戏是开始还是退出游戏
		{
		case 1:
			printf("开始游戏,祝你好运\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);//如果玩家选择为1就开始执行上述代码
}

上述代码我们用到了do while循环和switch语句来选择是否进行游戏。后续会在上述代码中添加游戏具体运行的代码。

🥥🥥创建一个棋盘

三子棋的棋盘创建我们可以用一个二维数组来实现。创建一个源文件来存放我们所创建的函数,这样在管理代码和反复调用函数时提供的便利。

 ☘️效果图

eb989ee93d0e430e855afc5f38632ea8.png

 🌻代码展示

#include "三子棋game.h"//此处是创建了一个头文件将我们游戏需要的头文件放在里面,后续都会提到
//上述头文件暂时包含了<stdio.h>
void menu()//自行创建的函数来打印菜单
{
	printf("****************\n");
	printf("*****1.play*****\n");
	printf("*****0.exit*****\n");
	printf("****************\n");
}
void game()//创建一个函数,来实现游戏的运行规则
{
	char ret = 0;
	char board[ROW][COL];
	//创建一个棋盘,初始化
	chessBoard(board, ROW, COL);
}
int main()
{
	int input = 0;
	do
	{
		menu();调用函数打印菜单
		printf("请选择.>");
		scanf("%d", &input);//玩家进行选择
		switch (input)//对玩家的选择进行判断---游戏是开始还是退出游戏
		{
		case 1:
			printf("开始游戏,祝你好运\n");
            game();//调用函数,开始运行游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);//如果玩家选择为1就开始执行上述代码
}

 上述代码中具体实现打印棋盘和初始化棋盘的过程是在自定义game()函数中实现,并且后续的游戏运行过程,都是在game()函数中实现,文章下面的部分就会省略上述代码,具体讲述game()函数

🐣创建打印棋盘并初始化棋盘的函数

下棋我们用' * '代表玩家,' # '代表电脑。很简单的首先我们需要一个二维数组来存放这些字符' char board[ROW][COL] '。然后创建一个另外的源文件(game.c)来写游戏具体运行函数。最后前面所提到的三子棋game.h文件,我们将函数的申明放在这里👍👍👍

我们可将棋盘的打印分为三个部分的打印 ,在下面代码的注释中会详细的讲解

3d564f8f97874eb4a7505f5df6d6d3f4.png

三子棋game.h文件

这里将所需要的全部头文件类型和函数的申明都在这里一次性展示,以免后面文章的部分过于冗长

#pragma once
#define ROW 3
#define COL 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//初始化棋盘
void chessBoard(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 win(char board[ROW][COL], int row, int col);

game()函数

void game()
{
	char ret = 0;
	char board[ROW][COL];//ROW为行数,COL为列数
	//创建一个棋盘,初始化
	chessBoard(board, ROW, COL);
    //打印棋盘
	DisplayBoard(board, ROW, COL);
}

game.c文件

#include "三子棋game.h"
void chessBoard(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;
	int j = 0;
	for (i = 0; i < row; i++)//实现分别打印三个部分
	{
		for (j = 0; j < col; j++)//进行一个部分上半部打印
		{
			if (j < col - 1)//棋盘一行的结尾不需要'|'
				printf(" %c |", board[i][j]);
			else
				printf(" %c", board[i][j]);
		}
		printf("\n");//完成一个部分的上半部打印,换行
		if (i < row - 1)//进行一个部分的下半部的打印,且棋盘最后的打印不需要进行该过程
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//一行的下半部分最后不需要'|'
					printf("|");
			}
			printf("\n");
		}
	}
}

以上的代码让我们完成了对棋盘的初始化与打印,运用的都是简单的if语句,for循环,及自定义函数,进行逻辑上合理的组合,理清思路,拆分步骤,一步一步的实现。

🖥️🖥️玩家与电脑对弈

我们玩家先手下棋,电脑后手。首先玩家下棋子' * ',打印出棋盘,然后电脑下棋打印棋盘。上述是一个回合的思路,我们会发现玩家和电脑下棋的过程其实也是一个循环,在一个循环中等达到获胜条件或者出现平局时让程序自动的检测判定来跳出循环,实现游戏效果。

🤺玩家下棋

我们来创建一个玩家下棋的函数,方便之后游戏进行时不断的调用

//玩家下棋
void playermove(char board[ROW][COL], int row, int col);
//电脑下棋
void computermove(char board[ROW][COL], int row, int col);
//判断输赢
char win(char board[ROW][COL], int row, int col);

 🦏玩家下棋函数代码展示

void playermove(char board[ROW][COL], int row, int col)
{
	int a = 0;
	int b = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入坐标>");
		scanf("%d%d", &a, &b);
		if (a >= 1 && a <= row && b >= 1 && b <= col)//确保玩家输入棋子坐标范围合法
		{
			if (board[a - 1][b - 1] == ' ')//保证这一格没有棋子可以落子
			{                              //由于数组的下标是从零开始,而棋盘的坐标则是
				board[a - 1][b - 1] = '*'; //从一开始,所以我们需要减1
				break;
			}
			else
				printf("该棋格已被占有,请重新输入坐标\n");
		}
		else
			printf("坐标输入非法,请重新输入坐标\n");
	}
}

🖥️电脑下棋

代码示例

void computermove(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		int a = rand() % row;//使生成的随机数范围在0-2(包含0和2)
		int b = rand() % col;
		if (board[a][b] == ' ')
		{
			printf("电脑下棋\n");
			board[a][b] = '#';
			break;
		}
	}
}

上述代码的逻辑和玩家下棋是差不多的,只不过想要完成电脑的自动下棋我们需要srand()函数来生成一个随机数坐标让电脑实现自动下棋,不过只能做到对现有可落子棋格的随机下棋,不能实现智能化的电脑,而我们这次也只是初步实现自动下棋功能,想要让该电脑棋手更加”智慧“大家以后自行了解吧

电脑自动落子

调用srand()函数,给rand()传递一个时刻变化的值,rand()再通过特殊的算法形成一个随机值。而形成一个随机值我们需要借助时间戳(从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。),随时间变化给srand传递一个不断变化的值,使rand()能生成一个随机坐标

srand((unsigned)time(NULL));//随时间变化生成一个数字

✔️❎判断游戏胜负

创建一个函数,对棋局的输赢判断

//玩家赢返回'*'
//电脑赢返回'#'
//游戏继续返回'c'
//平局返回'z'

👏代码示例

char win(char board[ROW][COL], int row, int col)
{
	//一行连成三个
	int i = 0;
	int j = 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[0][0] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (deuce(board, row, col))//返回值为1,游戏平局。返回值为0,游戏继续
	{
		return 'z';
	}
	return 'c';
}

上述代码中对于平局的判断使用了另一个自定义函数的判断

平局判断代码

//判断平局
int deuce(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;//有棋格下,返回0;
			}
		}
	}
	return 1;//没有棋格下,返回1
}

🐳🐳游戏代码组合

当玩家下棋后进行判断输赢,电脑下棋后判断输赢,并打印输赢的结果。这个过程也是一个循环的过程

void game()
{
	char ret = 0;
	char board[ROW][COL];
	//创建一个棋盘,初始化
	chessBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	while (1)
	{
		playermove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);//打印棋盘
		//游戏是否继续
		ret = win(board, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
		computermove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);//打印棋盘
		//游戏是否继续
		ret = win(board, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
	}
//利用win()函数的返回符号判断游戏结果
	if (ret == '*')
	{
		printf("玩家赢 congratulation\n");
	}
	if (ret == '#')
	{
		printf("电脑赢\n");
	}
	if (ret == 'z')
		printf("平局\n");
}

 ⚔️⚔️源码

头文件---三子棋game.h

#pragma once
#define ROW 3
#define COL 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//初始化棋盘
void chessBoard(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 win(char board[ROW][COL], int row, int col);

源文件---三子棋游戏.c

#include "三子棋game.h"//此处是创建了一个头文件将我们游戏需要的头文件放在里面,后续都会提到
//上述头文件暂时包含了<stdio.h>
void menu()//自行创建的函数来打印菜单
{
	printf("****************\n");
	printf("*****1.play*****\n");
	printf("*****0.exit*****\n");
	printf("****************\n");
}
void game()
{
	char ret = 0;
	char board[ROW][COL];
	//创建一个棋盘,初始化
	chessBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	while (1)
	{
		playermove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);//打印棋盘
		//游戏是否继续
		ret = win(board, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
		computermove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);//打印棋盘
		//游戏是否继续
		ret = win(board, ROW, COL);
		if (ret != 'c')
		{
			break;
		}
	}
//利用win()函数的返回符号判断游戏结果
	if (ret == '*')
	{
		printf("玩家赢 congratulation\n");
	}
	if (ret == '#')
	{
		printf("电脑赢\n");
	}
	if (ret == 'z')
		printf("平局\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();调用函数打印菜单
		printf("请选择.>");
		scanf("%d", &input);//玩家进行选择
		switch (input)//对玩家的选择进行判断---游戏是开始还是退出游戏
		{
		case 1:
			printf("开始游戏,祝你好运\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);//如果玩家选择为1就开始执行上述代码
}

源文件---game.c

#include "三子棋game.h"
void chessBoard(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;
	int j = 0;
	for (i = 0; i < row; i++)//实现分别打印三个部分
	{
		for (j = 0; j < col; j++)//进行一个部分上半部打印
		{
			if (j < col - 1)//棋盘一行的结尾不需要'|'
				printf(" %c |", board[i][j]);
			else
				printf(" %c", board[i][j]);
		}
		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 a = 0;
	int b = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入坐标>");
		scanf("%d%d", &a, &b);
		if (a >= 1 && a <= row && b >= 1 && b <= col)//确保玩家输入棋子坐标范围合法
		{
			if (board[a - 1][b - 1] == ' ')//保证这一格没有棋子可以落子
			{                              //由于数组的下标是从零开始,而棋盘的坐标则是
				board[a - 1][b - 1] = '*'; //从一开始,所以我们需要减1
				break;
			}
			else
				printf("该棋格已被占有,请重新输入坐标\n");
		}
		else
			printf("坐标输入非法,请重新输入坐标\n");
	}
}
void computermove(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		int a = rand() % row;//使生成的随机数范围在0-2(包含0和2)
		int b = rand() % col;
		if (board[a][b] == ' ')
		{
			printf("电脑下棋\n");
			board[a][b] = '#';
			break;
		}
	}
}
//判断平局
int deuce(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;//有棋格下,返回0;
			}
		}
	}
	return 1;//没有棋格下,返回1
}
char win(char board[ROW][COL], int row, int col)
{
	//一行连成三个
	int i = 0;
	int j = 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[0][0] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (deuce(board, row, col))//返回值为1,游戏平局。返回值为0,游戏继续
	{
		return 'z';
	}
	return 'c';
}

🌞🌞总结

该游戏所运用的知识点,有分支和循环语句,函数,数组。实现该游戏最主要的是有清晰的逻辑思维,将游戏的实现拆分为小的板块,分步实现,最后进行逻辑的组合最后实现。最后如果有不足之处请大家交流指点👏👏👏。

如果你喜欢该篇文章或者是对你有一些帮助,那么请大家动动发财的小手点个赞吧👍👍👍。

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值