C语言小游戏--三子棋

目录

问题描述

逻辑分析

具体实现

1.进入菜单界面

2.初始化棋盘

3.打印棋盘

4.玩家下棋

5.电脑下棋

6.判断输赢

运行结果

完整代码

game.h

game.c

test.c


问题描述

结合C语言所学知识,简单实现一个三子棋小游戏。

逻辑分析

  1. 进入菜单界面
  2. 初始化棋盘
  3. 打印棋盘
  4. 玩家下棋
  5. 判断输赢
  6. 电脑下棋
  7. 判断输赢
  8. 游戏结束

具体实现

1.进入菜单界面

玩家通过输入1或者0来选择进入对应的环节:输入“1”则进入游戏环节;输入“0”则退出游戏;如果输入其他数字,则会提示“选择错误”

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

void test()
{
	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);

}

运行结果:

2.初始化棋盘

棋盘格式设置为3*3的二维数组大小,元素类型为char,初始化为空格,即什么数据也不存储。行列采用宏定义的方式,是为了方便后期对棋盘的大小进行统一修改,同时也为了提高代码的可读性

#define ROW 3
#define COL 3

//初始化棋盘为全空格
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] = ' ';
		}
	}
}

3.打印棋盘

将棋盘进行拆分,第一行为: 字符 | 字符 | 字符 (注意字符前后的空格),第二行我们为:---|---|---。在打印数据时,根据for循环,打印三行数据,也就是三行字符 | 字符 | 字符 ,同时三行数据中穿插着两行---|---|---作为分隔。

//打印棋盘
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)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");

				if (j < col- 1)
					printf("|");
			}
			printf("\n");//换行
		}
	}
}

运行结果:

4.玩家下棋

玩家根据提示输入行列坐标,比如1 1,同时使用’*’表示玩家落子。玩家在落子之前需要对坐标进行合法性的判断,即判断所输入的坐标是否在棋盘规定的范围内以及是否已被占用。玩家要选择在棋盘上空闲的位置进行落子,否则会提示出错。输入坐标合法之后要立即跳出循环,否则会陷入死循环。

//玩家下棋
void player_move(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;//不加break会进入死循环
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

运行结果:

5.电脑下棋

在玩家落子之后,电脑会随机生成行列坐标并在棋盘上空闲的地方进行相应的落子,'#’表示电脑落子。生成随机数之前需要基于当前时间设定“种子”的值srand((unsigned int)time(0))。在调用rand()函数之前,要先在主函数中调用srand函数。如果没有上述准备工作,那么种子的值就会默认为1,会生成相同的随机数序列。

void computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:>\n");

	while (1)
	{
		x = rand() % row;//0-2
		y = rand() % col;//0-2

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;//跳出循环
		}
	}
}

运行结果:

6.判断输赢

在判断输赢时,我们约定:‘*’ 表示玩家赢;‘#’ 表示电脑赢;’ Q’ 表示平局;‘C’ 表示继续

玩家赢:行,列以及两条对角线有三个连续的‘*’则表示玩家赢

电脑赢:行,列以及两条对角线有三个连续的‘#’则表示电脑赢

平局:当棋盘中不存在连续三个‘#’或者‘*’时,并且棋盘已满,则表示平局

继续:当棋盘中不存在连续三个‘#’或者‘*’时,并且棋盘未满,则游戏继续

//判断平局
static int is_full(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 is_win(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];
		}
	}

	//判断列
	for (i = 0; i < col; i++)
	{
		if (board[0][i]==board[1][i] && board[1][i]==board[2][i] && board[1][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];
	}

	//判断平局
	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//继续
	return 'C';
}

运行结果

玩家赢:

 电脑赢:

平局:

完整代码

game.h

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

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

//判断输赢
char is_win(char board[ROW][COL], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS 1

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


//打印棋盘
//版本1.0
//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]);//打印的是棋盘初始化中的空格
//		}
//		printf("\n");
//	}
//}

//版本2.0
//存在缺陷,行数可以改变,但是列数被固定死无法修改
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//	int i = 0;
//	for (i = 0; i < row; i++)
//	{
//		//打印数据
//		printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//存在缺陷,行数可以改变,但是列数被固定死无法修改
//
//		//打印分割行
//		if (i < row - 1)//最后一行的分割行不打印
//		{
//			printf("---|---|---\n");
//		}
//	}
//}

//版本3.0
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)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");

				if (j < col- 1)
					printf("|");
			}
			printf("\n");//换行
		}
	}
}


//玩家下棋
void player_move(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;//不加break会进入死循环
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}


//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:>\n");

	while (1)
	{
		x = rand() % row;//0-2
		y = rand() % col;//0-2

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;//跳出循环
		}
	}
}


//判断平局
static int is_full(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 is_win(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];
		}
	}

	//判断列
	for (i = 0; i < col; i++)
	{
		if (board[0][i]==board[1][i] && board[1][i]==board[2][i] && board[1][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];
	}

	//判断平局
	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//继续
	return 'C';
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include"game.h"


//test.c:测试三子棋游戏的逻辑
//game.c:游戏的实现
//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)
	{
		//玩家下棋
		player_move(board, ROW, COL);
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret=is_win(board,ROW,COL);
		if (ret != 'C')
		{
			break;
		}

		//电脑下棋
		computer_move(board, ROW, COL);//随机下棋,哪里空着,往哪里下
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}

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

	//打印棋盘
	DisplayBoard(board, ROW, COL);
}


//什么情况,游戏就结束了呢?
//玩家赢:'*'
//电脑赢:'#'
//平局:'Q'
//继续:'C'
void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));

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

}


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值