【C语言入门游戏】三子棋的实现———【保姆级教学】

发布于:2022-11-09 ⋅ 阅读:(2) ⋅ 点赞:(0) ⋅ 评论:(0)

目录

1、何为三子棋,三子棋的规则如何?

2、 游戏的整体框架

2.1 创建游戏菜单 

test.c 

game.h

​编辑

2.2 初始化棋盘 

game.c

2.3 打印棋盘

2.4 玩家下棋 

2.5 电脑下棋 

2.6 判断输赢

game.c

3、整个游戏代码


🌱🌱 到目前为止,初阶C语言已经学了一半,相信大家学完了选择循环,函数,数组,一直想找些题目来练练手,今天就让我们来实现一下三子棋。也当做是复习之前学过的内容。

1、何为三子棋,三子棋的规则如何?

三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。 

2、 游戏的整体框架

该游戏我们采用分模块去实现:

  • test.c  ----  测试游戏
  • game.h  ----  函数的声明
  • game.c  ----  游戏函数的实现

 

2.1 创建游戏菜单 

  • test.c 

首先肯定有main函数,做游戏时,main函数里面的东西尽量要少,因为是分模块写。

回到游戏设计本身,main函数里面包含一个test函数,这个test函数是通过你输入的值来进行菜单的选择,究竟是玩还是不玩,得看玩家自己。这里的选择采用switch。当然了,一个游戏的开始必然离开不了菜单,在此之前,还要打印menu函数。这里的开始整体逻辑与猜数字是一样的。猜数字我在之前的文章里写过,不熟悉的同学可以先去看看猜数字。下面放一下猜数字那篇博客的链接:http://t.csdn.cn/Z9JJD

#include <stdio.h>

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



void test()
{
	int input = 0;
	do
	{
		menu();
		
		printf("请输入:1/0->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("sanziqi\n");
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("重新选择!\n");
		}
	} while (input);
}


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

 接下来测试一下目前游戏代码是否能正常运行:

 我们目前发现游戏代码没有错误,下面只需在switch(1)里面放置game(),来实现游戏的基本逻辑。

接下来我们来到game()函数里面,写三子棋,肯定要先有棋盘,没有棋盘,游戏根本无法进行。这个棋盘(3*3)不就是我们学过的数组嘛。

  • game.h

这里在创建的过程中,数组的行列需要从game.h里面导入,由于后面的game.c也需要从game.h中导入。所以为了避免代码的冗余,我们直接将#include <stdio.h>直接放到game.h里面。这里选用宏定义,其实也是对这个游戏的优化,我们可以将他改成10*10。 

2.2 初始化棋盘 

有了棋盘之后,第一步是清空棋盘,也就是对数组进行初始化。这里我们采用InitBoard()函数来表示初始化。 这里InitBoard( )里面的参数,我们传数组名,行,列。

  • game.c

 而InitBoard( )真正实现的代码放在“game.c”这个文件里面,注意“game.c”要包括“game.h”这个头文件。

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

2.3 打印棋盘

 棋盘初始化后我们需要打印出棋盘来看看。不妨用DisplayBoard( )来表示棋盘的打印函数,

 上图是我们最终要打印出来的棋盘。打印棋盘分为两个步骤,一个是打印数据,我们采用“ %c ”+“|”,但注意到最后一列是没有必要打印出“|”,所以这里用if语句判断一下。另一个是打印分割行,为了跟数据对齐,我们采用“---”+“|”,同理跟打印数据一样,最后一列无需打印“|”。注意,打印完一行要记得换行!接下来在game.c文件里面实现打印棋盘的代码:

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

到了这里,可以先检测一下目前的代码是否能正常运行:

2.4 玩家下棋 

有了棋盘并且还能将他打印出来,接下来就是游戏的核心之一——玩家下棋。

这里需要注意的是,玩家不是程序猿,他们不知道数组是从0下标开始的,所以在设计的过程中,需要对行列进行减一的操作。另外对于输入的值还要进行判断是否合法,比如说要考虑该坐标是否被占用,没被占用的话,不妨令玩家落子的符号规定为'*',被占用或者超出范围的话要提醒玩家。

PlayerMove(char board[ROW][COL],int row, int col)
{
	printf("玩家走->:");
	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");
	}

}

 注意玩家下完棋之后要打印棋盘,否则会看不到你想要的结果,下面给出运行结果:

2.5 电脑下棋 

该游戏的另一个核心就是电脑下棋,为了实现电脑下棋这个功能,我们需要创建随机数,

就需要在game.h里面包括以下两个头文件:1.<stdlib>, 2.<time.h>

 此外我们还需要通过时间戳来随机下棋:

1.srand((unsigned int)time(NULL))—进行初始化(建议放在test(),这个只需运行一次即可)

2.x=rand%row, y=rand%col——生成随机数

我们用ComputerMove来表示电脑下棋。

和玩家下棋,电脑下棋需要判断是否被占用,如果没有被占用,就返回‘#’。

ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

2.6 判断输赢

由于该游戏规则的特殊性,每当玩家和电脑对弈一次后就需要判断是否已经产生输赢。来回下棋就需要while(1)来死循环,直到找到跳出循环条件,我们需要用Iswin()函数来判断,这个时候需要定义一些返回值来判断:

  • 玩家赢——返回'*'
  • 电脑赢——返回'#'
  • 平局——返回'Q'
  • 游戏继续——返回'C'

自然而然的,又需要定义一个char类型的变量来接受返回值

void game()
{
	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");
		}
	
	

}
  • game.c

接下来game.c里面完成Iswin函数的实现:

1.判断行

2.判断列

3.判断对角线

4.判断棋盘是否已满(又需要引用Isfull函数来判断)

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][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[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
		return board[0][2];

	//平局
	if (Isfull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

接下来是Isfull函数的实现:

int Isfull(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//棋盘未满
			}
		}
	}
	return 1;//棋盘满了
}

3、整个游戏代码

  • test.c
#include "game.h"

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

void game()
{
	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");
		}
	
	

}




void test()
{

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

	do
	{
		menu();
		
		printf("请输入:1/0->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("重新选择!\n");
		}
	} while (input);
}




int main()
{

	test();
	return 0;
}
  • game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 3
#define COL 3

InitBoard(char board[ROW][COL], int row, int col);
DisplayBoard(char board[ROW][COL], int row, int col);
PlayerMove(char board[ROW][COL], int row, int col);
ComputerMove(char board[ROW][COL], int row, int col);
int Isfull(char board[ROW][COL], int row, int col);
  • game.c
#include "game.h"

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


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


PlayerMove(char board[ROW][COL],int row, int col)
{
	printf("玩家走->:");
	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");
	}

}

ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

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][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[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
		return board[0][2];

	//平局
	if (Isfull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

int Isfull(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//棋盘未满
			}
		}
	}
	return 1;//棋盘满了
}

下面来试玩一下吧: