数组、函数都学了...你不会还不会做三子棋这个小游戏吧

  数组学过了对吧?函数学过了对吧?行,那接下来就试试写一个三子棋小游戏.

  这次就不先搬代码给你们看了,我们先想一下如果你要做一个三子棋游戏,需要对这个游戏如何布局。

  简单来说,就是欢迎界面与游戏过程,欢迎界面并不难,随随便便一个设计,printf啪一下就打印上了。难的是自身对这个游戏过程的理解,即你设计这个游戏的逻辑。这篇博客的重点也就是对设计这个游戏的逻辑进行重点解释。

这里我先把代码初步框架在这里解释一下:

1、我们将游戏逻辑代码放入test.c这个源文件中(以下就称其为逻辑代码)

#define _CRT_SECURE_NO_WARNINGS 1

#include "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];
	//开始的时候,数组的内容应该是全部空格
	InitBoard(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	//下棋
	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");
	}
}

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

2、game.c源文件中的函数定义

#define _CRT_SECURE_NO_WARNINGS 1

#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]);
//		}
//		printf("\n");
//	}
//}

//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//	int i = 0;
//	int j = 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");
//	}
//}


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;
	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;
			}
			else
			{
				printf("该坐标被占有,请输入其他坐标\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

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

	int x = 0;
	int y = 0;

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


static 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;
}

//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- 'Q'
//游戏继续-'C'

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][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[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 (IsFull(board, row, col))
	{
		return 'Q';
	}

	return 'C';
}

3、game.h头文件中对game函数中所需函数的声明以及整个逻辑函数所需头文件的包括

#pragma once

#include <stdio.h>
#pragma once

#include <stdio.h>
#include <time.h>
#include <stdlib.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 ComputerMove(char board[ROW][COL], int row, int col);

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

在逻辑代码中,game函数是这个游戏的核心,我们将game函数中所用到的函数在game.c这个源文件中定义,将game函数所需函数的函数声明以及整个逻辑函数所需要的头文件放在game.h这个头文件中。这样一来,不仅极大的提高了我们代码的规范程度,而且也使我们在写代码的过程中减少了不必要的错误,提高写代码的效率。

下面步入正题:

一、菜单

这个你真的可以根据自己的喜好来设计,把自己想的写成一个菜单函数即可,这里不把这个当成重点,就一码带过啦

void menu()

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

打印出来的结果为:

 二、对棋盘的设计

 1.初始化棋盘

由图我们可以看的出来,棋盘是一个3×3的结构,并且下棋时输入坐标即可在自己所想的地方下棋。所以这里我们可以选择二维数组arr[3][3]来构造棋盘的下棋位置,这样当玩家输入其要下棋的坐标,我们就可以经过小小的变换就可以在棋盘上显示玩家的棋子。由于刚开始棋盘的各个位置都是空出没有棋子的,空出的位置我们用空格代替。所以我们将二维数组arr[3][3]各个元素都初始化为空格字符。

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

	}
}

运用多个for循环语句是因为,我们不局限于3×3的框架,无论你想让ROW(行)、COL(列)为多少,你都可以你想要的框架搞出来,甚至可以从三子棋变成五子棋!

三、玩家与电脑之间的博弈

1、玩家下棋:

void PlayerMove(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;
			}
			else
			{
				printf("该坐标被占有,请输入其他坐标\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

这里的关键就是对棋位是否有棋子进行判断,如果没有,玩家即可下棋。这里玩家的棋子用*表示,当玩家想在某个位置下棋时,输入该位置的坐标,就可以从二维数组中找到并将原来的空格字符替换成*

2、电脑随机下棋

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

	int x = 0;
	int y = 0;

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

电脑随机下棋,这里就先搞一个笨电脑陪大家”博弈“ ,下篇博客出电脑升级版。

我们这里用rand函数来让电脑随机生成数字,并将数字控制到正确范围,这里的%便是,因为row、col都是3,rand函数随机产生一个数字,无论是多少,对row、col取模后只能是0,1,2,这便可以精准表示棋位。

在使用rand函数之前要使用srand(种子)设置随机数,我们一般将time函数放入种子,这样便可以随机生成数啦。

这里的rand、srand函数要用到#include<stdlib.h>这个头文件,time函数要用到#include<time.h>这个头文件。

这样我们玩家便可跟电脑博弈啦。

四、判断输赢
static 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;
}

//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- 'Q'
//游戏继续-'C'

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][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[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 (IsFull(board, row, col))
	{
		return 'Q';
	}

	return 'C';
}

我们用'*'来表示玩家赢,用'#'来表示电脑赢,用'Q'来表示游戏平局,用'C'来表示游戏继续,玩家和电脑每下一次棋都要进行判断,用if语句判断结果。这里的Iswin()函数来判断结果,首先我们要想清楚什么样的情况下才会赢、输、平局、继续。

继续很简单,只要我们胜负未分,就可一直继续,所以我们把这个“继续”当作关键点,当不再继续时,便开始判断结果。

赢的情况也很简单,三行、三列或两个对角线上的元素都相等时,便会有一方赢。这里你也许会发现将'*'设置为玩家赢,'#'设置为电脑赢的巧妙之处,当有赢的结果产生时,会返回三个相等元素中的一个元素来判断是玩家赢还是电脑赢。

平局即为九个棋位都满了时,仍未出现赢中任意一个条件,便会判断为平局。这里用IsFull()函数来判断是否满格,当没有一个条件满足赢时,就会执行IsFull函数判断是继续还是平局,当用两个for循环只要查看出其中有一个元素为空格字符时,IsFull函数便会返回0,进而IsWin函数中if(IsFull())中IsFull()函数的返回值为0,则IsWin便会返回C,则继续,同理可知,当查看出所有的元素都已经不是空格字符时,IsFull函数返回1,IsWin函数返回Q,则平局。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值