C语言:简单【三子棋】代码实现

一、三子棋代码实现思路

今天我们来使用C语言实现一个简单的小游戏三子棋。
这里在实现三子棋代码时,我将会把三子棋代码的主函数,函数以及头文件声明,其他函数主体分别放在三个不同的文件中:

test.c
//主函数,以及基本函数
game.h
//功能函数的实现
game.c
//头文件引用以及功能函数的声明

1.在界面上打印菜单

首先,我们需要在界面上打印菜单,以提供选项给玩家来选择是否进行三子棋游戏,这里可以直接使用printf()函数在界面上直接输出菜单:

#include <stdio.h>

void menu()
{
    
    
	printf("************************\n");
	printf("****     1.play     ****\n");
	printf("****     0.exit     ****\n");
	printf("************************\n");
}
int main()
{
    
    
	menu();//菜单
}

打印出来的菜单就是这样:在这里插入图片描述
在这里我们根据菜单设计,当玩家输入‘1’时,进入游戏,当玩家输入‘0’时,退出游戏,当玩家不慎输入其他值时,提醒一下玩家输入有误,并使玩家重新输入选项。根据这样的需求这里就需要使用到switch选择语句和do while循环语句进行实现。

main函数内部代码修改

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);
	return 0;
}

在这里插入图片描述
这样玩家就可以进行是否进行游戏的选择了


2.创建3*3的棋盘

第二步,就是要创建一个3*3的棋盘来提供给玩家来下棋,在这里我们可以使用,上一节刚讲过的二维数组来创建棋盘,但是创建数组是需要初始化的,但我们需要的棋盘又需要拿落子不能存在其他内容,其实我们可以把棋盘创建成一个二维字符数组,并把内容都初始化为空格(因为空格在屏幕上打印是看不见的),这样玩家在下棋时在棋盘上就不会看见其他无关内容了

代码实现:,这里先在main函数里的case1:语句内定义一个game()函数

case 1:
			game();

然后在game()函数中创建棋盘并使用一个Initboard()函数进行初始化

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	}

这里二维数组在定义时,数组的大小使用了宏定义,这样方便以后对数组大小的修改,同时宏定义是放在game.h文件中的:

#define ROW 3//行
#define COL 3//列

初始化棋盘的代码放在game.c的文件里实现:

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] = ' ';
		}
	}
}

3.在界面上打印棋盘

当我们创建好棋盘后就需要在屏幕上给玩家打印一下棋盘
这里假设我们要打印的棋盘是这样的:在这里插入图片描述
对这个棋盘的构成进行分析:
在这里插入图片描述
这里我们就清楚了,我们在打印棋盘是时都有哪些元素需要被打印
代码实现:在game()函数中使用一个Displayboard()函数来打印

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
}

打印棋盘的代码放在game.c的文件里实现:

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++)
		{
    
    
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
    
    
				printf("|");
			}
		}printf("\n");
		if (i < row - 1)
		{
    
    
			for (j = 0; j < col; j++)
			{
    
    
				printf("---");
				if (j < col - 1)
				{
    
    
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

在这里插入图片描述
这里我们就成功打印出了我们需要的棋盘


4.下棋

当我们的棋盘打印好后,就需要玩家和电脑相继进行下棋了
这里我们设定玩家的棋子为’*‘,电脑的棋子为’#’

玩家落子

我们在game()函数内部使用PlayerMove()函数来实现玩家下棋

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	//玩家下棋
	PlayerMove(board, ROW, COL);
}

这里我们假设,当玩家输入要下棋的坐标后,棋盘上对应位置将会出现玩家的棋子,同时下棋是多次要进行的重复步骤,当我们每一次下棋时,如果输入的坐标上有棋子或者该坐标超出棋盘范围时,这时我们就需要提醒一下玩家输入的坐标异常,并让玩家重新输入
玩家下棋的代码放在game.c的文件里实现:

void PlayerMove(char board[ROW][COL], int row, int col)
{
    
    
	int x = 0;
	int y = 0;
	while (1)
	{
    
    
		printf("玩家走:>\n");
		printf("请输入下棋的坐标:>");
		scanf("%d %d",&x,&y);
		//判断坐标合法性
		if (1 <= x && x <= row && 1 <= y && y <= col)
		{
    
    
			//下棋
			//坐标是否被占用
			if (board[x - 1][y - 1] == ' ')
			{
    
    
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
    
    
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
    
    
			printf("坐标非法,请重新输入\n");
		}
	}
}

在这里插入图片描述


电脑落子

这里对电脑下棋的算法代码不进行复杂的设计,我们现阶段只通过让电脑生成随机的坐标来进行下棋就行。

我们在game()函数内部使用ComputerMove()函数来实现玩家下棋

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	//玩家下棋
	PlayerMove(board, ROW, COL);
	//电脑下棋		
	ComputerMove(board, ROW, COL);
}

在电脑生成随机坐标时,我们需要调用rand()函数,使用rand()函数时,还需要srand()函数配合使用,srand()函数只需要调用一次即可,所以可以放在main函数的内部,上述两个函数使用需要的头文件:

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

电脑下棋的代码放在game.c的文件里实现:

void ComputerMove(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;
		}
	}
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/97332a0d9df54c69a3dc2069aad80052.png


5.判断输赢

三子棋的规则是:

两名选手在棋盘上轮流下棋。当有一名选手率先在行、列或者斜线上连续组成了 3 个自己的棋子时,即为获胜。如果棋盘下满也没有胜者,则为平局。

根据上述规则,我们在game()函数内部使用Iswin()函数来实现输赢的判断,并且我们将Iswin()函数的返回值作为判断的结果,这里我们假设:

玩家赢返回 ’*‘ ;
电脑赢返回’ #‘ ;
平局返回 ’Q‘ ;
棋局未结束则返回 ’C’ ,以便下一轮的下棋。

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	//玩家下棋
	PlayerMove(board, ROW, COL);
	//判断输赢结果
	char ret = 0;
	ret = Iswin(board, ROW, COL);
}

输赢判断的代码放在game.c的文件里实现:

//判断是否棋盘是否满
int IsFUll(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 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][1];
		}
	}
	//判断三竖行
	for (i = 0; i < col; i++)
	{
    
    
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
    
    
			return board[1][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];
	}
	//判断平局
	//棋盘满了返回1,不满返回0
	int ret = IsFUll(board, ROW, COL);
	if (ret == 1)
	{
    
    
		return 'Q';
	}
	//继续
	return 'C'; 
}

当每一次玩家下棋后和电脑下棋后,都需要对棋盘进行一次判定,看是否有胜者产生,并且玩家和电脑下棋的动作是多次的,所以这里我们就需要使用while循环来实现玩家和电脑轮流下棋的操作,将game()函数内的代码进行优化:

void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	char ret = 0;
	while (1)
	{
    
    
		//玩家下棋
		PlayerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢结果
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')
		{
    
    
			break;
		}
		//电脑下棋		
		ComputerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		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);
}

二、最终完整三子棋代码

test.c

#include "game.h"

void menu()
{
    
    
	printf("************************\n");
	printf("****     1.play     ****\n");
	printf("****     0.exit     ****\n");
	printf("************************\n");
}
void game()
{
    
    
	//1.创建棋盘
	char board[ROW][COL];
	//初始化
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	char ret = 0;
	while (1)
	{
    
    
		//玩家下棋
		PlayerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢结果
		ret = Iswin(board, ROW, COL);
		if (ret != 'C')
		{
    
    
			break;
		}
		//电脑下棋		
		ComputerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		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.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//头文件包含
#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 PlayerMove(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢 - *
//电脑赢 - #
//平局 - Q
//继续 - C
char Iswin(char board[ROW][COL], int row, int col);

game.c

#include "game.h"

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] = ' ';
		}
	}
}

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++)
		{
    
    
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
    
    
				printf("|");
			}
		}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 x = 0;
	int y = 0;
	while (1)
	{
    
    
		printf("玩家走:>\n");
		printf("请输入下棋的坐标:>");
		scanf("%d %d",&x,&y);
		//判断坐标合法性
		if (1 <= x && x <= row && 1 <= y && 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");
	while (1)
	{
    
    
		int x = rand() % row;
		int y = rand() % col;
		//判断占用
		if (board[x][y] == ' ')
		{
    
    
			board[x][y] = '#';
			break;
		}
	}
}

//判断是否满
int IsFUll(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 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][1];
		}
	}
	//判断三竖行
	for (i = 0; i < col; i++)
	{
    
    
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
    
    
			return board[1][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];
	}
	//判断平局
	//棋盘满了返回1,不满返回0
	int ret = IsFUll(board, ROW, COL);
	if (ret == 1)
	{
    
    
		return 'Q';
	}
	//继续
	return 'C'; 
}

思考:
当我们完整写出三子棋的代码后,对该代码是否有优化的空间呢?
这里提出几点可优化的地方,仅供参考:

  • 电脑下棋的算法是否可以更加智能
  • 输赢的判断规则,是否可以跟随棋盘的大小变化而不断变化(如:五子棋等)

对于这几点问题,你可以自己思考思考,并能否通过代码进行优化一下。
博主后期可能会出相关优化的博客进行讲解,希望各位读者点个关注,以便后期能及时看到优化代码。
这里再次感谢各位的阅读,有什么想法可以在评论区留言以及私聊我哦,那我们下期再见吧!谢谢!

猜你喜欢

转载自blog.csdn.net/ks_wyf/article/details/129461575