三子棋怎么写

三子棋需要有的功能以及实现

1. 初始棋盘

创建一个3*3的数组,由于一开始玩家没有输入,数组为空白,相对应的每一个数组单元存放内容为空格

//初始棋盘
void init_board(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] = ' '; //一开始的时候,数组没有输入数字,无法对其,所以初始化棋盘,让数组一开始是空格
		}
	}
}

2. 玩家移动

玩家移动所需要的注意事项:

- 选择的格子没有棋子

首先玩家不会考虑数组下标,玩家输入位置的范围只能在1到row和1到col

但是在数组内,我们有个0下标所以需要把玩家输入的坐标都减1

如果该位置有棋子,显示坐标被占用

如果该位置越界,显示坐标非法

void player_move(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	printf("请输入坐标:");
	
	//判断坐标的合法性,有没有越界
	//坐标是否被占用
	while (1)
	{
		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] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
}

 

3. 电脑自动移动

在现阶段我们暂时不考虑电脑智能化的移动,比如想办法赢和想办法堵,我们让电脑随机下棋

使用rand以及srand来求随机行和列

注意:使用rand和srand要引用对应的库函数

将rand() 模3出来的结果是0-2

原因:rand()函数会产生范围为0至32767的随机数,让它与3求余,变成0至2的随机数,余数不会超过3因为我们的row是3,如果余数超过3可以进1

//电脑随机下棋
void computer_move(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;
		}
		//不用else因为电脑不需要提示,直接回到while继续生成随机数
	}

}

4. 棋盘满了

我们这里先来讨论棋盘满了情况,有助于之后思考赢,输,平局

如果棋盘满了返回1
不满返回0

如果数组中有一个元素是空格,表示没满,其他情况下都是满了

//如果棋盘满了返回1
//不满返回0
int is_full(char board[ROW][COL], int row, int col) //不用在头文件声明,因为只在game.c 这个文件中运行,不在其他文件里运行
{
	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,这一个loop直接不运行,不存在return的覆盖
			}
		}
	}
	return 1;
}

 

5. 自动判断输赢平局

三子棋有三种情况:

1) 电脑赢 - 横着,竖着,斜着赢

2) 玩家赢 -横着,竖着,斜着赢

3)棋盘满了,平局

4) 棋盘没满,继续游戏

由于1)和 2) 逻辑相似,我们只要写一种情况,让他们返回不同的值就能知道是电脑赢还是玩家赢

所以我们返回的都是棋盘中的符号

Q代表平局

C代表继续

//判断状态
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][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][1] != ' ') //分析行
		{
			return board[i][0];//直接返回棋盘里的值,不用重新写了
		}
	}
	//斜着赢
	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 (is_full(board, row, col) == 1) //看的是board这个数组,判断状态时得到的是小写row,col
	{
		return 'Q';
	}

	//继续
	return 'C';
	
}

6. 显示给玩家

除了将棋盘打印下来,我们还要实现可以动态调整行和列的棋盘。

简单来说就是使代码更灵活,随时可以改变棋盘格数,行和列。这里我们可以是使用for loop来实现

注意:由于数组下标是从0开始的,我们在循环中i<row, j<col

//可以动态调整行和列的棋盘
void display_board(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]); //写死了,只能是三列,想让他变的灵活
		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)
		{
			//printf("---|---|---\n");//第三行分割线有点多余
			for (j = 0; j < col; j++)
			{
				printf("---");
				if(j<col-1)
				  printf("|");
			}
			printf("\n");
		}
			
	}
}

问题:

三子棋中,为什么要分大写ROW和小写row呢、

- 他们本质上没有区别,ROW是被定义过的精确数值

-在main函数中,当我们想要引用其他函数要写:

init_board(board,ROW,COL);

这个时候我们是要引用这个函数,不需要明确定义它里面的参数是什么类型的,我们只要把我们要用到的参数写进去即可

void init_board(char board[ROW][COL], int row, int col)

这个是在函数定义以及说明的时候用到的

在这里需要明确定义每一个形式参数的类型以及名称

如果以上两个代码是相关联的,我们把ROW 的值给到row,COL 的值给到col

我看了一圈感觉只有ROW被定义成数字3,row没有被定义为什么也能使用?(上面回答了)

棋盘满了,且没人赢部分为什么用的是小写row,col?

我们这里(is_full函数)用到的实参是从is_win函数里来的,is_win函数里只有小写row,col,所以is_full里也是小写

 test.c 里面主要是main函数以及菜单的打印,比较简单在这里就不介绍了

有问题的话大家可以给我留言~

代码汇总:

//头文件放函数声明
#pragma once

#define ROW 3 //行是3
#define COL 3 //列是3
#include<stdio.h>
#include<stdlib.h> //rand
#include<time.h> //srand

//初始化棋牌
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void display_board(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
#include "game.h"

//初始棋盘
void init_board(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 display_board(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]); //写死了,只能是三列,想让他变的灵活
		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)
		{
			//printf("---|---|---\n");//第三行分割线有点多余
			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)
{
	printf("玩家下棋\n");
	printf("请输入坐标:");
	
	//判断坐标的合法性,有没有越界
	//坐标是否被占用
	while (1)
	{
		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] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
}

//电脑随机下棋
void computer_move(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");

	while (1)
	{
		int x = rand() % row;//模3出来的结果是0-2,rand()函数会产生范围为0至32767的随机数
	//% 让它与3求余,变成0至2的随机数,余数不会超过3因为我们的row是3,如果余数超过3可以进1
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
		//不用else因为电脑不需要提示,直接回到while继续生成随机数
	}

}

//如果棋盘满了返回1
//不满返回0
int is_full(char board[ROW][COL], int row, int col) //不用在头文件声明,因为只在game.c 这个文件中运行,不在其他文件里运行
{
	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,这一个loop直接不运行,不存在return的覆盖
			}
		}
	}
	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][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][1] != ' ') //分析行
		{
			return board[i][0];//直接返回棋盘里的值,不用重新写了
		}
	}
	//斜着赢
	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 (is_full(board, row, col) == 1) //看的是board这个数组,判断状态时得到的是小写row,col
	{
		return 'Q';
	}

	//继续
	return 'C';
	
}

test.c

#define _CRT_SECURE_NO_WARNINGS 

#include "game.h"

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

void game()
{
	char ret = 0;
	printf("三子棋\n");
	char board[ROW][COL] = { 0 };
	init_board(board, ROW, COL);
	display_board(board, ROW, COL);//告诉他是3*3
	//玩游戏
	while (1)
	{
		player_move(board, ROW, COL);
		display_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;

		/*display_board(board, ROW, COL);*/
		computer_move(board, ROW, COL);
		display_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;

		/*display_board(board, ROW, COL);*/
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else if (ret == 'Q')
	{
		printf("平局\n");
	}
}

//玩家赢 - '*'
//电脑赢 - '#'
//平局,棋盘满了-‘Q’
//游戏继续-‘C'

	int main()
	{
		int input = 0;
		srand((unsigned int)time(NULL)); //随机下棋
		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;
	}
		

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值