用数组实现三子棋小游戏——纯C


作者:Shining-point
作者的博客主页:Shining-point的博客
如果觉得博主的博客写的不错或者有所收获的话,希望大家多多🚀点赞 🚀评论🚀收藏。你们的支持是我的最大动力,不驰于空想,不骛于虚声,我们一起加油!!!
博文内容有误均可在评论中指出,教学相长!!!
对了对了,如果对猜数字游戏感兴趣的话,不妨看看博主的这一篇:C语言和猜数字小游戏,好啦,让我们开始吧!

在这里插入图片描述

🌟写在前面

  C语言编程学完数组能写什么,不妨来写一个三子棋小游戏吧,一方面巩固所学知识,另一方面锻炼自己的逻辑思维和编程能力。不过我想这对编程初学者还是有一定难度的,所以这一次就让我来带你们写写看吧,多多指教啦!

Ⅰ.游戏规则

三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时候会出现和棋的情况。相信这是多数人的童年回忆,那么用代码如何实现呢?

Ⅱ.游戏逻辑

逻辑顺序:
1.打印菜单,玩家选择开始或者退出游戏
2.初始化棋盘
3.打印棋盘
4.玩家下棋并打印棋子
5.电脑下棋并打印棋子
6.判断输赢

Ⅲ.游戏具体代码实现

ⅰ.编写代码前的准备

创建test.c文件(用于测试游戏逻辑)
创建game.c文件(用于实现游戏功能)
创建game.h文件(用于自定义头文件和函数声明)

ⅱ.打印菜单

//该代码位于test.c文件中//

void menu()	//使用自定义menu()函数来打印菜单,不需返回值故使用void
{
	printf("****************************************\n");
	printf("**************** 1.play ****************\n");	//选择1开始游戏
	printf("**************** 0.exit ****************\n");	//选择0退出游戏
	printf("****************************************\n");
}

ⅲ.开始或退出游戏

//该代码位于test.c文件中//

#include "game.h"	//将所需的头文件和函数声明置于game.h文件中,故此处引用game.h文件即可

int main()
{
	srand((unsigned int)time(NULL));//设置随机数的生成起点
	int input = 0;
	do	//游戏至少要玩一次,故使用do while循环
	{
		menu();	 //此处调用自定义menu函数用于打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)	//switch语句用于选择开始游戏or退出游戏
		{
		case 1:
			game();	 //调用自定义game函数执行游戏主逻辑
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while(input);
	return 0;
}

ⅳ.初始化棋盘

//该代码位于test.c文件中//

void game()	 //自定义game函数,不需返回值故使用void
{
	char board[ROW][COL] = { 0 };
	
	//自定义初始化棋盘的函数initboard
	initboard(board, ROW, COL);
}
//该代码位于game.c文件中//

#include "game.h"	//自定义包含game.h头文件,因为要用到它声明的函数
					//使用define定义的常量ROW和COL,使棋盘的大小可以自定义
void initboard(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] = ' ';
		}
	}
}
//该代码位于game.h文件中//

#pragma once	//编译器自动添加,用于防止头文件被重复包含

#include <stdio.h>	  //该处已包含头文件,故下文不在重复包含
#include <stdlib.h>   //该处已包含头文件,故下文不在重复包含
#include <time.h>	  //该处已包含头文件,故下文不在重复包含

//define定义ROW的值为3,COL的值为3,即定义了一个3✖3的棋盘,要想更改棋盘大小只需更改此处即可
#define ROW 3
#define COL 3

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

ⅴ.打印棋盘

//该代码位于test.c文件中//

void game()
{
	char board[ROW][COL] = { 0 };
	
	//自定义打印棋盘的函数displayboard
	displayboard(board, ROW, COL);
}
//该代码位于game.c文件中//
#include "game.h"

void displayboard(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++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)	//最后一列不打印,所以j<col-1
			{
				printf("|");
			}
		}
		printf("\n");	//打印完一行换行
		if (i < row - 1)	//最后一行不打印,所以i<row-1
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");	最后一列不打印,所以j<col-1
				}
			}
			printf("\n");	//打印完一行换行
		}
	}
}
//该代码位于game.h文件中//

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

ⅵ.玩家下棋并打印棋子

//该代码位于test.c文件中//

void game()
{
	while(1)	//一直下直到决出胜负
	{
		//自定义玩家下棋的函数playermove
		playermove(board, ROW, COL);
		//打印棋子
		displayboard(board, ROW, COL);		
	}
}
//该代码位于game.c文件中//

void playermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)	//判断棋子是否落在棋盘内
		{
			if (board[x - 1][y - 1] == ' ')	 //判断落子位置是否已有棋子
			{								 //x-1,y-1是为了如果玩家输入1,1,则在二维数组0,0处落子
				board[x - 1][y - 1] = '*';	 //打印玩家棋子 *
				break;	//跳出循环
			}
			else
			{
				printf("该处已经被下过咯,请选择其他位置\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}
//该代码位于game.h文件中//

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

ⅶ.电脑下棋并打印棋子

//该代码位于test.c文件中//

void game()
{
	while(1)	//一直下直到决出胜负
	{
		//自定义电脑下棋的函数computermove
		computermove(board, ROW, COL);
		//打印棋子
		displayboard(board, ROW, COL);		
	}
}
//该代码位于game.c文件中//

void computermove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		//生成棋盘大小范围内的随机数,随机落子
		x = rand() % row;	
		y = rand() % col;
		if (board[x][y] == ' ')	 //判断落子位置是否已有棋子
		{
			board[x][y] = '#';	 //打印电脑棋子 #
			break;	 //跳出循环
		}
	}
}
//该代码位于game.h文件中//

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

ⅷ.判断输赢

//该代码位于test.c文件中//

void game()
{
	char ret = 0;
	while(1)
	{
		//自定义判断输赢函数iswin
		ret = iswin(board, ROW, COL);
		//每一步都要判断是否继续下棋,输、赢、平局均跳出循环
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
	displayboard(board, ROW, COL)	//一局结束,重新打印棋盘
}
//该代码位于game.c文件中//

//自定义判断棋盘是否满的函数isfull
//满了返回1
//不满返回0
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;
}

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][1] != ' ')
		{
			return board[i][1];	 //该处是谁的棋子谁就赢
		}
	}

	//再判断列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];	 //该处是谁的棋子谁就赢
		}
	}

	//最后判断对角线
	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))
	{
		return 'Q';
	}

	//游戏继续
	//棋盘未满且未决出胜负
	return 'C';
}
//该代码位于game.h文件中//

//判断输赢
//玩家赢 - 输出'*'
//电脑赢 - 输出'#'
//平局 - 输出'Q'
//继续 - 输出'C'
char iswin(char board[ROW][COL], int row, int col);

Ⅳ.游戏完整代码

ⅰ.test.c内代码

#include "game.h"

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

}

void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };

	initboard(board, ROW, COL);
	displayboard(board, ROW, COL);

	while (1)
	{
		playermove(board, ROW, COL);
		ret = iswin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);

		computermove(board, ROW, COL);
		ret = iswin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);
	}

	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}

	displayboard(board, ROW, COL);
}

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;

	do
	{
		menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while(input);

	return 0;
}

ⅱ.game.c内代码

#include "game.h"

void initboard(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 displayboard(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++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1)
		{
			int j = 0;
			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 x = 0;
	int y = 0;
	printf("玩家下棋:>\n");
	while (1)
	{
		printf("请输入坐标:>");
		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] = '*';
				break;
			}
			else
			{
				printf("该处已经被下过咯,请选择其他位置\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

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

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;
}

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

	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
	}

	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))
	{
		return 'Q';
	}

	return 'C';
}

ⅲ.game.h内代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 3
#define COL 3

void initboard(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 iswin(char board[ROW][COL], int row, int col);

Ⅴ.游戏玩法视频

三子棋游戏玩法

Ⅵ.该三子棋存在的缺陷

⚠ 首当其冲的便是电脑的随机落子,这会导致电脑无法对玩家做出有效的拦截,一切全凭运气,也就是所谓的人工智障,优化需要更加高级的算法

⚠ 其二是对三子棋输赢的判断,该处把判断部分的代码写死了,导致只能判断3×3棋盘上三子棋的输赢

⚠ 其三是对平局的判断,只有当棋盘下满了才会判为平局,这没什么问题,只是有时候不需要下满就已经知道是平局了,属于优化代码吧

当然了,博主的这篇三子棋充当闲暇时的消遣还是够的,毕竟谁不喜欢人工智障呢(doge),博主后期有想法了会对代码进行优化的,学习就是积累的过程嘛!😆😆😆

🌟写在最后

或许我们走那么远,不是为了看风景,而是为了去天地的尽头会一会自己。因为只有在那样遥远的地方,你才能把喧嚣的人世抛在身后。

在这里插入图片描述

  • 36
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shining-point

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值