追寻童年回忆~三子棋【C语言】

在这里插入图片描述

大家好呀!我是小杨。小杨今天利用C语言中前面学习的函数,数组等一系列知识自己动手制作了我们大家童年时代都比较热衷的小游戏–三子棋。虽然这个小游戏的游戏比较简单,但是却是我们童年美好的回忆,带给了我们无尽欢乐!今天小杨就带领小伙伴们一起制作这个我们童年时代的经典小游戏–三子棋(初阶版),让大家重新体验一下童年时代的快乐!


文章目录

1,游戏前期准备
2,游戏流程设计
3,游戏功能实现
  3.1,游戏菜单实现
  3.2,棋盘初始化
  3.3,棋盘打印
  3.4,玩家下棋
  3.5,电脑下棋
  3.6,判断输赢
4,游戏整体实现
  4.1,游戏逻辑主体~test.c
  4.2,游戏代码实现~game.c
  4.3,游戏代码声明~game.h
5,游戏运行效果


1,游戏前期准备

 当我们写一个项目时,为了实现代码美观和操作便捷,我们常常不直接在一个文件里进行书写代码,而是将这个项目分为多个不同的文件,在不同的文件里分别书写不同版块内容代码,从而避免出现因代码过长和代码逻辑顺序混乱而导致的阅读体验极差以及代码修改优化操作的难度加大等一系列问题。为了避免出现上述问题,小杨在设计这个游戏时,将该项目分为3个文件进行代码书写,分别为game.h,game.c,test.c。

各文件功能如下:
追寻童年回忆~三子棋【C语言】_第1张图片
注:三子棋的实现需要多个模块的功能相互串联,这三个文件可以分别处理各自模块的功能,能更好处理各个模块之间的逻辑并且便于后期调试,也使得代码的可读性提高。


2,游戏流程设计

 游戏流程大致可以分为以下:

1,需要设计出游戏菜单,供玩家选择
2,玩家选择开始游戏后,棋盘界面出现
3,玩家根据棋盘界面输入棋盘坐标进行落子操作
4,玩家落子后进行是否获胜判断操作,并打印棋盘
5,电脑在玩家落子操作后,自动进行随机落子操作
6,电脑落子后进行是否获胜判断操作,并打印棋盘
7,玩家和电脑依次进行落子操作,直至一方获胜或者平局结束


3,游戏功能实现

  3.1,游戏菜单实现

//游戏菜单实现
void Menu()
{
	printf("***********************\n");
	printf("***** 1.开始游戏  *****\n");
	printf("***** 0.退出游戏  *****\n");
	printf("***********************\n");
}

说明:游戏菜单规定:选择1表示开始游戏,选择2表示退出游戏,玩家根据需要来进行选择。


  3.2,棋盘初始化

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

说明:每次游戏的开始之前我们都要进行初始化棋盘操作,先建立空棋盘的雏形,在这里我们利用二维数组来替代棋盘上的位置,空格符号来代表此时棋盘上没有棋子落子。此时就是一个空棋盘,每次开始之前都要置空。


  3.3,棋盘打印

//打印棋盘
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)//条件过滤
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//条件过滤
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

说明:棋盘游戏的开始如果只有棋子,整体会看起来比较单一 ,所以我们通过两横两竖来打印一个简单的棋盘,棋盘的参数可以用define(宏)来定义,修改参数很方便,如果要做更大的棋盘,只需要修改参数,棋盘打印的细节很少,需要注意的是每打印一行注意跳行,且打印的时候要把之前棋盘定义的“空格”打印上,这样之后才能落子。


  3.4,玩家下棋

//玩家下棋
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 > 0 && x <= row && y > 0 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,不能下棋,请选择其他位置\n");
			}
		}
		else
		{
			printf("该坐标不合法,请重新输入\n");
		}
	}
}

说明:玩家下棋操作里,要站在玩家的角度上考虑,为了让玩家知道轮到自己该下棋了,游戏界面应提示玩家进行下棋操作并输入下棋坐标,同时也要对玩家输入的坐标进行判断是否合法,若不合法则提示重新输入。因二维数组的下标是以0开始的,玩家对此并不知情,为了玩家游戏顺利进行和游戏体验,游戏系统内部要对玩家输入的x,y坐标进行-1操作,从而规避了此类问题。


  3.5,电脑下棋

//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	while (1)
	{
		int x = 0;
		int y = 0;
		x = rand() % 3;//0~2
		y = rand() % 3;//0~2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}	
}

说明:电脑下棋相对就没有那么多的限制,当玩家落子操作后,电脑自动在棋盘上未下棋子的地方进行随机落子操作,这里的处理时通过取余的方式来保证落在规定的行列里面。因该随机性导致电脑比较迟钝,这时的电脑可以被理解为”人工智障“,要想提高该游戏获胜的难度,主要通过改变电脑下棋的操作来解决,从而让电脑变得更聪明,知道”堵人“,哪怕无法获胜也平局,大大提高获胜的概率,实现从人工智障到人工智能的一大转变。


  3.6,判断输赢

//判断棋盘是否满了,若满了,返回1,否则返回0
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;
}

//判断输赢
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];
		}
	}

	//列判断
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[2][j] == board[0][j] && board[0][j] != ' ')
		{
			return board[0][j];
		}
	}
	
	//对角线判断
	if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[2][0] != ' ')
	{
		return board[1][1];
	}
	
	//平局判断
	if (IsFull(board, row, col))
	{
		return 'Q';
	}
	return 'C';
}

说明:判断游戏输赢是该游戏中最重要的一步操作,该游戏程序要结束,就得有输有赢,或者平局。对于三子棋这个游戏,我们要考虑到横三竖三斜三,此时在书写判断条件需要注意,条件判断不能连等,否则是错误的,并且我们知道这只是一个函数,不能直接判断输赢,需要通过他传递的信息来判断,所以它是一个有返回值的函数,当有三个相同棋子相连,则返回次棋子的字符,而游戏平局和游戏继续的标志在这里分别对应Q和C。游戏平局的标志是棋盘满了无法进行下棋操作但胜负未分。


4,游戏整体实现

  4.1,游戏逻辑主体~test.c

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//游戏菜单打印
void Menu()
{
	printf("***********************\n");
	printf("***** 1.开始游戏  *****\n");
	printf("***** 0.退出游戏  *****\n");
	printf("***********************\n");
}
//游戏逻辑主体
void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋操作
	while(1){
		//玩家下棋
		PlayerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
		//电脑下棋
		ComputerMove(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisplayBoard(board, ROW, COL);
	}
	if (ret == '*')
	{
		printf("玩家获胜\n");
	}
	else if (ret == '#')
	{
		printf("电脑获胜\n");
	}
	else
	{
		printf("游戏平局\n");
	}
}
//游戏主函数
int main()
{
	srand((unsigned int)time(NULL));//设置随机数生成起点的//时间戳

	int input = 0;
	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;
}

  4.2,游戏代码实现~game.c

#define _CRT_SECURE_NO_WARNINGS

#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;
	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)//条件过滤
		{
			int j = 0;
			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 > 0 && x <= row && y > 0 && 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");
	while (1)
	{
		int x = 0;
		int y = 0;
		x = rand() % 3;//0~2
		y = rand() % 3;//0~2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}	
}

//判断棋盘是否满了,若满了,返回1,否则返回0
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;
}

//判断输赢
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];
		}
	}
	
	//列判断
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[2][j] == board[0][j] && board[0][j] != ' ')
		{
			return board[0][j];
		}
	}
	
	//对角线判断
	if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[2][0] != ' ')
	{
		return board[1][1];
	}

	//平局判断
	if (IsFull(board, row, col))
	{
		return 'Q';
	}
	return 'C';
}

  4.3,游戏代码声明~game.h

#pragma once

#include
#include
#include

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

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

char IsWin(char board[ROW][COL], int row, int col);

5,游戏运行效果

追寻童年回忆~三子棋【C语言】_第2张图片


结语

小伙伴们,小杨今天利用C语言数组,函数相关知识制作的三子棋小游戏就介绍到这里就结束,你们应该学会到了挺多东西以及对数组,函数这些知识的掌握更加深刻了吧!今天带大家一起制作的三子棋小游戏是个初阶版,因电脑下棋是在棋盘空的地方随机落子,所以导致电脑比较迟钝,游戏难度小。后续小杨有时间会对该游戏进行升级,让电脑变得更聪明,知道”堵人“,哪怕无法获胜也平局,从而实现从人工智障到人工智能的一大转变。
追寻童年回忆~三子棋【C语言】_第3张图片


你可能感兴趣的:(C语言项目实战,小杨带你玩转C语言【初阶】,c语言,学习,游戏,后端,程序人生)