C语言 | 三子棋游戏

C语言实现《三子棋》小游戏

1-需求分析

1️⃣ 游戏规则介绍: 双方轮流下子,直到三个子连成一条线,横、竖、斜线都可以,谁先达到这个要求就获胜,或者说棋盘满了,则游戏平局结束[1]

2️⃣ 需求分析:

  1. 菜单界面必不可少,用户可以手动选择进行游戏或退出游戏

  2. 如果用户选择进行游戏,则需要打印出棋盘

  3. 玩家先下,下完打印出来方便观察

  4. 电脑后下,下完也得打印棋盘

  5. 要保证每一方下在可以下子的地方,需要对应的控制机制

  6. 每一方下完需要判断目前棋局状态,玩家赢了?电脑赢了?平局?还是应该游戏继续?

  7. 除非用户选择退出游戏,否则游戏应该可以一直玩。

通过上述模拟游戏的过程,可以总结出以下需求:

  1. 控制游戏可循环直到用户选择退出
  2. 菜单界面
  3. 接收用户输入,控制走向(进入游戏/退出游戏)
  4. 实时打印棋盘
  5. 接收用户输入转换为棋盘落子
  6. 电脑自动落子
  7. 判断棋局状态(谁赢?平局?继续)

2-准备工作

  1. test.c 执行主函数
  2. game.h 头文件,用于定义函数和常量
  3. game.c 用来完成各个函数功能

3-功能实现

  1. 进入游戏首先需要打印菜单
void menu()
{
	printf("*********************\n");
	printf("*****  1.play    ****\n");
	printf("*****  0.exit    ****\n");
	printf("*********************\n");	
}
  1. do-while循环控制游戏可循环地玩,直到用户选择退出
do
{
	//打印菜单
	menu();
	
	printf("Please enter your choice(1/0):>");
	scanf("%d", &input);
	switch(input)
	{
		case 1:
			printf("Welcome!\n");
			game();
			break;
		case 0:
			printf("Exit.\n");
			break;
		default:
			printf("Unvalidated input, please input again.\n");
			break;
	}
	
}while(input);

  1. 进入游戏之后,首先应该初始化一个棋盘,棋盘可以用二维数组表示,为了程序泛化性,可以在头文件game.h里指定棋盘地行数和列数,以防需要修改:
//定义符号
#define ROW 3
#define COL 3

//定义函数
//初始化棋盘
void Initboard(char board[ROW][COL], int row, int col);

初始化棋盘就是将数组值置为空格,在game.c里实现:

void Initboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for(int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

  1. 接下来打印出棋盘

game.h 里定义:

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

game.c里实现:

void Printboard(char board[ROW][COL], int row, int col)
{
	for (int 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");
	}
}
  1. 用户玩:可以输入坐标,转化为数组下标,判断合法即打印出新棋盘,如果位置已经被占或者输入位置超出棋盘范围,需要提示并可以重新输入

game.h 里定义:

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

game.c里实现:

void Player(char board[ROW][COL], int row, int col)
{
	int x,y;
	while(1)
	{
		printf("Please enter the coordinates:>");
		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("The location is occupied, please re-enter.\n");
			}
			
		}else
		{
			printf("Invalid input, please enter again.\n");
		}
	}
}
  1. 电脑下:简单起见,直接随机生成坐标,判断合法即打印出新棋盘

game.h 里定义:

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

game.c里实现:

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

有关生成随机数的rand函数需要搭配srand()一起用,方可实现真正的随机,详细内容可参考官方文件关于rand()函数的解释,也可以参考网上博客
使用随机数需要用到的标准库,在game.h里声明

#include <stdlib.h>
#include <time.h>
  1. 判断输赢的函数应该返回此时棋局状态,不妨进行如下设计:

game.h 里定义:

//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
/* 
返回值含义:
'*' -> 玩家赢
'#' -> 电脑赢
'Q' -> 平局
'C' -> 游戏继续
*/

game.c里实现:分情况逐一判断:

逐行判断有没有一行值相同且值不是空格,如果有则返回改行的值,该值即代表赢家(玩家下子用,电脑用#,所以如果返回则玩家赢)。
逐列判断,逻辑和上述行判断一样;
主对角线判断,同上述逻辑;
次对角线判断,同上述逻辑;
如果上述过程都没有返回值,再判断是否平局:此时棋盘被占满则返回Q(平局);
否则,返回C(继续游戏)。

char IsWin(char board[ROW][COL], int row, int col)
{
	//判断行
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int flag = 1;
		int j = 0;
		for (j = 0; j < col -1; j++)
		{
			if (board[i][j] != board[i][j+1])
			{
				flag = 0;
				break;
			}
		}
		if (flag == 1 && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	
	//判断列
	for (i = 0; i < col; i++)
	{
		int flag = 1;
		int j = 0;
		for (j = 0; j < row -1; j++)
		{
			if (board[j][i] != board[j+1][i])
			{
				flag = 0;
				break;
			}
		}
		if (flag == 1 && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	//判断对角线
	int flag = 1;
	for (i = 0; i < row-1; i++)
	{
		if (board[i][i] != board[i+1][i+1])
		{
			flag = 0;
			break;
		}
	}
	if (flag == 1 && board[0][0] != ' ')
	{
		return board[0][0];
		
	}
	//对角线2
	flag = 1;
	int j = col - 1;
	for (i = 0; i < row-1; i++, j--)
	{
		if (board[i][j] != board[i+1][j-1])
		{
			flag = 0;
			break;
		}
	}
	if (flag == 1 && board[0][col-1] != ' ')
	{
		return board[0][col-1];
	}
	//平局
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 'C'; //游戏继续
			}
		}
	}
	return 'Q'; //平局
}
  1. 主函数根据上述过程返回的棋局状态做出反应,继续游戏则继续进行下子-判断棋局-下子的循环过程,否则需要终止本局并打印最终棋盘:
void game()
{
	//初始化棋盘
	char board[ROW][COL];
	Initboard(board,ROW,COL);
	//打印棋盘
	Printboard(board,ROW,COL);
	
	char ret = 'C'; //记录棋局状态
	while(1)
	{
		//玩家下
		Player(board,ROW,COL);
		Printboard(board,ROW,COL);
		//判断赢家
		ret = IsWin(board,ROW,COL);
		if (ret != 'C')
		{
			break;
		}
		
		//电脑下
		Computer(board,ROW,COL);
		Printboard(board,ROW,COL);
		//判断赢家
		ret = IsWin(board,ROW,COL);
		if (ret != 'C')
		{
			break;
		}
		//游戏继续
	}
	
	if (ret == '*') //玩家赢了
	{
		printf("======Player win!======\n");
		Printboard(board,ROW,COL);
		
	}else if (ret == '#') //电脑赢了
	{
		printf("======Computer win!======\n");
		Printboard(board,ROW,COL);
		
	}else if (ret == 'Q')//平局
	{
		printf("======Tie game.======\n");
		Printboard(board,ROW,COL);
		
	}
	
}
  1. 整合各个项目代码:
1-test.c
#include "game.h"

int main(int argc, char **argv)
{
	srand((unsigned int)time(NULL));
	void menu();
	void game();
	int input;
	
	do
	{
		//打印菜单
		menu();
		
		printf("Please enter your choice(1/0):>");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				printf("Welcome!\n");
				game();
				break;
			case 0:
				printf("Exit.\n");
				break;
			default:
				printf("Unvalidated input, please input again.\n");
				break;
		}
		
	}while(input);
		
	return 0;
}

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

void game()
{
	//初始化棋盘
	char board[ROW][COL];
	Initboard(board,ROW,COL);
	//打印棋盘
	Printboard(board,ROW,COL);
	
	char ret = 'C'; //记录棋局状态
	while(1)
	{
		//玩家下
		Player(board,ROW,COL);
		Printboard(board,ROW,COL);
		//判断赢家
		ret = IsWin(board,ROW,COL);
		if (ret != 'C')
		{
			break;
		}
		
		//电脑下
		Computer(board,ROW,COL);
		Printboard(board,ROW,COL);
		//判断赢家
		ret = IsWin(board,ROW,COL);
		if (ret != 'C')
		{
			break;
		}
		//游戏继续
	}
	
	if (ret == '*') //玩家赢了
	{
		printf("======Player win!======\n");
		Printboard(board,ROW,COL);
		
	}else if (ret == '#') //电脑赢了
	{
		printf("======Computer win!======\n");
		Printboard(board,ROW,COL);
		
	}else if (ret == 'Q')//平局
	{
		printf("======Tie game.======\n");
		Printboard(board,ROW,COL);
		
	}
	
}

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

//玩家下
void Player(char board[ROW][COL], int row, int col);
//电脑下
void Computer(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
/* 
返回值含义:
'*' -> 玩家赢
'#' -> 电脑赢
'Q' -> 平局
'C' -> 游戏继续
*/

3-game.c
#include "game.h"

void Initboard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for(int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

void Printboard(char board[ROW][COL], int row, int col)
{
	for (int 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");
	}
}

void Player(char board[ROW][COL], int row, int col)
{
	int x,y;
	while(1)
	{
		printf("Please enter the coordinates:>");
		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("The location is occupied, please re-enter.\n");
			}
			
		}else
		{
			printf("Invalid input, please enter again.\n");
		}
	}
}

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

char IsWin(char board[ROW][COL], int row, int col)
{
	//判断行
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int flag = 1;
		int j = 0;
		for (j = 0; j < col -1; j++)
		{
			if (board[i][j] != board[i][j+1])
			{
				flag = 0;
				break;
			}
		}
		if (flag == 1 && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	
	//判断列
	for (i = 0; i < col; i++)
	{
		int flag = 1;
		int j = 0;
		for (j = 0; j < row -1; j++)
		{
			if (board[j][i] != board[j+1][i])
			{
				flag = 0;
				break;
			}
		}
		if (flag == 1 && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	//判断对角线
	int flag = 1;
	for (i = 0; i < row-1; i++)
	{
		if (board[i][i] != board[i+1][i+1])
		{
			flag = 0;
			break;
		}
	}
	if (flag == 1 && board[0][0] != ' ')
	{
		return board[0][0];
		
	}
	//对角线2
	flag = 1;
	int j = col - 1;
	for (i = 0; i < row-1; i++, j--)
	{
		if (board[i][j] != board[i+1][j-1])
		{
			flag = 0;
			break;
		}
	}
	if (flag == 1 && board[0][col-1] != ' ')
	{
		return board[0][col-1];
	}
	//平局
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 'C'; //游戏继续
			}
		}
	}
	return 'Q'; //平局
}

4-功能测试

点击即可查看
*********************
*****  1.play    ****
*****  0.exit    ****
*********************
Please enter your choice(1/0):>1
Welcome!
   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

Please enter the coordinates:>2 3
   |   |   
---|---|---
   |   | * 
---|---|---
   |   |   

Computer input:
   |   |   
---|---|---
   | # | * 
---|---|---
   |   |   

Please enter the coordinates:>1 3
   |   | * 
---|---|---
   | # | * 
---|---|---
   |   |   

Computer input:
   |   | * 
---|---|---
   | # | * 
---|---|---
   |   | # 

Please enter the coordinates:>1 1
 * |   | * 
---|---|---
   | # | * 
---|---|---
   |   | # 

Computer input:
 * |   | * 
---|---|---
 # | # | * 
---|---|---
   |   | # 

Please enter the coordinates:>1 2
 * | * | * 
---|---|---
 # | # | * 
---|---|---
   |   | # 

======Player win!======
 * | * | * 
---|---|---
 # | # | * 
---|---|---
   |   | # 

*********************
*****  1.play    ****
*****  0.exit    ****
*********************
Please enter your choice(1/0):>1
Welcome!
   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

Please enter the coordinates:>3
3
   |   |   
---|---|---
   |   |   
---|---|---
   |   | * 

Computer input:
   |   |   
---|---|---
   |   | # 
---|---|---
   |   | * 

Please enter the coordinates:>2 2
   |   |   
---|---|---
   | * | # 
---|---|---
   |   | * 

Computer input:
   | # |   
---|---|---
   | * | # 
---|---|---
   |   | * 

Please enter the coordinates:>1 1
 * | # |   
---|---|---
   | * | # 
---|---|---
   |   | * 

======Player win!======
 * | # |   
---|---|---
   | * | # 
---|---|---
   |   | * 

*********************
*****  1.play    ****
*****  0.exit    ****
*********************
Please enter your choice(1/0):>1
Welcome!
   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

Please enter the coordinates:>1 3
   |   | * 
---|---|---
   |   |   
---|---|---
   |   |   

Computer input:
 # |   | * 
---|---|---
   |   |   
---|---|---
   |   |   

Please enter the coordinates:>2 3
 # |   | * 
---|---|---
   |   | * 
---|---|---
   |   |   

Computer input:
 # |   | * 
---|---|---
 # |   | * 
---|---|---
   |   |   

Please enter the coordinates:>3 3
 # |   | * 
---|---|---
 # |   | * 
---|---|---
   |   | * 

======Player win!======
 # |   | * 
---|---|---
 # |   | * 
---|---|---
   |   | * 

*********************
*****  1.play    ****
*****  0.exit    ****
*********************
Please enter your choice(1/0):>1
Welcome!
   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

Please enter the coordinates:>2 2
   |   |   
---|---|---
   | * |   
---|---|---
   |   |   

Computer input:
   |   |   
---|---|---
   | * |   
---|---|---
 # |   |   

Please enter the coordinates:>1 2
   | * |   
---|---|---
   | * |   
---|---|---
 # |   |   

Computer input:
   | * | # 
---|---|---
   | * |   
---|---|---
 # |   |   

Please enter the coordinates:>2 3
   | * | # 
---|---|---
   | * | * 
---|---|---
 # |   |   

Computer input:
   | * | # 
---|---|---
   | * | * 
---|---|---
 # |   | # 

Please enter the coordinates:>2 1
   | * | # 
---|---|---
 * | * | * 
---|---|---
 # |   | # 

======Player win!======
   | * | # 
---|---|---
 * | * | * 
---|---|---
 # |   | # 

*********************
*****  1.play    ****
*****  0.exit    ****
*********************
Please enter your choice(1/0):>0
Exit.


  1. 参考:C语言三子棋小游戏开发详细解析 ↩︎

posted @ 2022-11-24 22:16  万国码aaa  阅读(308)  评论(0编辑  收藏  举报