C언어로 된 간단하고 이해하기 쉬운 5가지 게임에 대한 자세한 설명

머리말

C 언어에 대한 이해를 강화하기 위해 이해하기 쉬운 5가지 미니 게임을 사용합니다. 공부 후 신나는 게임을 해보자!

1. 준비

우리는 5개의 작은 게임을 만들 예정이며 5개의 작은 게임 각각에 대한 헤더 파일과 소스 파일을 만들어야 합니다 . 그들은 game1.h/game1.c, game2.h/game2.c, game3.h/game3.c, game4.h/game4.c, game5.h/game5.c입니다. 이것의 목적은 향후 미니 게임의 재구성과 같은 작업을 용이하게 하기 위해 각 게임을 별도로 빌드하는 것입니다. 또한 이 5개의 작은 게임의 헤더 파일을 포함하려면 main.c가 필요합니다. 메인 함수는 호출만 담당하며, 모든 미니 게임 코드 함수를 다른 파일에 구현하고 정적으로 데코레이션하여 사용자가 게임 함수를 사용하여 간접적으로 미니 게임 코드를 호출할 수 있도록 합니다.

2. 게임 메뉴

먼저 main.c를 빌드해 보겠습니다.
1. 5개의 작은 게임의 헤더 파일을 포함해야 합니다.
2. 기본 기능을 빌드합니다.

#include"game1.h"//包含小游戏1的头文件
#include"game2.h"//包含小游戏2的头文件
#include"game3.h"//包含小游戏3的头文件
#include"game4.h"//包含小游戏4的头文件
#include"game5.h"//包含小游戏5的头文件
#include<time.h>
int main()
{
    
    
	srand((unsigned int)time(NULL));//用来生成随机数
	do
	{
    
    
		int optional = 0;//创建一个接收选择的变量
		menu();
		printf("请输入你的选项:\n");
		scanf("%d", &optional);
		switch (optional)
		{
    
    
		case 1:
			game1();
			break;
		case 2:
			game2();
			break;
		case 3:
			game3();
			break;
		case 4:
			game4();
			break;
		case 5:
			game5();
			break;
		case 0:
			printf("感谢你的游玩,欢迎下次使用。\n");
			exit(0);
		default:
			printf("你的选项输入有误,请重新输入:\n");
			break;
		}
	} while (1);
}

우리는 메인 함수에서 do-while 루프를 사용합니다. 그 목적은 사용자가 선택을 할 수 있도록 하는 것이며 사용자는 사용자가 종료를 선택하거나 엉망이 될 때까지 종료하지 않습니다.
scanf 함수는 위험합니다.사용자가 입력 문자를 엉망으로 만들면 버퍼 예외가 발생합니다. 그래서 우리는 루프에 받고자 하는 선택 변수를 넣고 사용자가 문자를 입력할 때 프로그램이 종료되도록 초기값 0을 지정합니다.
srand 함수는 난수를 생성하는 데 사용됩니다. rand 함수만 사용하면 생성된 난수가 변경되지 않고 그대로 유지되어 반복 플레이 경험이 악화됩니다.
우리는 사용자가 플레이할 게임을 선택할 수 있도록 이러한 게임 모음에 대한 메뉴를 만들고 있습니다.

void menu()
{
    
    
	printf("*****************************\n");
	printf("*****1.猜数字   2.三子棋*****\n");
	printf("*****3.扫  雷   4.五子棋*****\n");
	printf("*****5.飞行棋   0.退  出*****\n");
	printf("*****************************\n");
}

기본 메뉴가 준비되었습니다. 각 미니 게임의 메뉴로 들어갑니다.
먼저 미니 게임의 헤더 파일을 만들어 보겠습니다.

#pragma once
#include<stdio.h>
#include<stdlib.h>
void game1();

미니게임은 미니게임의 헤더 파일에 있는 게임에 해당하는데, 미니게임 1을 예로 들었는데, 다른 4개의 미니게임도 이와 비슷합니다.
그런 다음 각각에 대한 소스 파일을 만듭니다.

#include"game1.h"
static void menu1()
{
    
    
	printf("*****************************\n");
	printf("*****      猜数字       *****\n");
	printf("***** 1.Start the game ******\n");
	printf("***** 0.Exit the game  ******\n");
	printf("*****************************\n");
}
void game1()
{
    
    
	int optional = 0;//创建一个接收选择的变量
	do
	{
    
    
		optional = 0;
		menu1();
		printf("请输入你的选项:\n");
		scanf("%d", &optional);
		switch (optional)
		{
    
    
		case 1:
			//game();
			break;
		case 0:
			printf("猜数字小游戏以退出。\n");
			break;
		default:
			printf("你的选项输入有误,请重新输入:\n");
			break;
		}
	} while (optional);
}

여전히 game1을 예로 들면 다른 미니 게임의 옵션은 game1과 동일하며 메뉴 기능에서 미니 게임의 이름만 변경됩니다. 루프의 게임 함수는 이 작은 게임에서 컴포지션 함수를 호출하는 데 사용됩니다.
이제 실행하여 코드가 우리가 예상한 것과 같은지 테스트해 봅시다 테스트는
여기에 이미지 설명 삽입
우리의 아이디어에 따라 정상적으로 수행될 수 있습니다.

3. 게임 내용

1. 숫자를 맞춰보세요

아이디어: 시스템이 무작위로 임의의 숫자를 생성합니다.입력한 숫자와 생성된 숫자를 비교하여 너무 크거나 작은지 추측할 수 있는 프롬프트를 제공합니다.

static void game()
{
    
    
	int num = rand() % 100 + 1;//创建一个变量,用来存放随机数。
	int guess = 0;//创建一个变量,用来存放所猜的数字。	
	//rand函数是用来生成随机数的,我们用rand函数生成的随机数对100取模并加1,可以产生1~100的随机数
	while(1)
	{
    
    
		printf("请输入你猜测的数字:");
		scanf("%d", &guess);
		if (guess == num)
		{
    
    
			printf("恭喜你,猜对了!\n");
			break;
		}
		else if (guess > num)
		{
    
    
			printf("你猜的数字过大,请重新猜测吧!\n");
		}
		else if (guess < num)
		{
    
    
			printf("你猜的数字过小,请重新猜测吧!\n");
		}
	}
	return;
}

간단히 실행해 봅시다!
여기에 이미지 설명 삽입
잘 작동하고 반복해서 재생할 수 있습니다.

2. 주사위 놀이

아이디어: 배열을 사용하여 체스 말을 저장하고 승패를 판단합니다.
1. 체스판을 인쇄합니다
. 2. 플레이어가 체스를 둡니다
. 3. 플레이어가 이겼는지 여부를 결정합니다
. 4. 컴퓨터가 체스를 두었습니다.
5. 컴퓨터가 이겼는지 여부를 결정합니다
. 먼저 두 개의 매크로를 정의합니다. 설정할 수 있는 체스판의 크기를 결정하는 데 사용됩니다.

#define ROW 3  //行
#define COL 3  //列

게임 아이디어를 지원하는 데 필요한 모듈을 확인하기 위해 게임 기능을 구축하기 시작합니다.

static void game()
{
    
    
	char win;//创建一个变量,存放判段获胜条件的字符。
	//我们把C代表继续,D代表平局,*代表玩家获胜,#代表电脑获胜
	char checkerboard[ROW][COL] = {
    
     0 };//创建一个数组,用来存放棋盘信息
	initialization(checkerboard,ROW,COL);//初始化数组,把数组中的每个元素初始化为空格
	ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	while(1)
	{
    
    
		Player(checkerboard, ROW, COL, '*');//玩家下棋,玩家的标志为 *
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		ptintinitialization(checkerboard, ROW, COL);//打印棋盘
		Computer(checkerboard, ROW, COL, '#');//电脑下棋,电脑的标志为 #
		win = Iswin(checkerboard, ROW, COL);
		if (win != 'C')
		{
    
    
			break;
		}
		ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	}
	if (win == 'D')
	{
    
    
		printf("平局\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
	else if (win == '*')
	{
    
    
		printf("恭喜你获得胜利\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
	else
	{
    
    
		printf("很遗憾,你输掉了比赛\n");
		ptintinitialization(checkerboard, ROW, COL);
	}
}

먼저 우리가 사용하는 배열과 승패를 판단할 수 있는 변수를 생성하고 배열을 초기화하고 출력하여 플레이어에게 체스를 할 수 있는 위치를 알려줍니다. 기능과 컴퓨터의 체스 기능. .
배열 함수 초기화:

static void initialization(char arr[ROW][COL],int row,int col)//初始化数组
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			arr[i][j] = ' ';//把数组中的每个元素赋值为空格
		}
	}
}

바둑판 인쇄 기능:

static void ptintinitialization(char arr[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 (j < col - 1)
			{
    
    
				printf(" %c |", arr[i][j]);//打印棋盘,如果为列中的最后一个元素,则不打印|
			}
			else
			{
    
    
				printf(" %c ", arr[i][j]);
			}
		}
		printf("\n");
		if(i < row-1)//打印棋盘,如果为行中的最后一个元素,则不打印---
		{
    
    
			for (j = 0; j < col; j++)
			{
    
    
				if (j < col)
				{
    
    
					printf("--- ");
				}
			}
		}
		printf("\n");
	}
}

여기에 이미지 설명 삽입
인쇄 효과는 그림에 나와 있습니다.
매크로를 다음과 같이 변경할 때:

#define ROW 9  //行
#define COL 9  //列

여기에 이미지 설명 삽입
인쇄된 체스판이 확장되는 것을 볼 수 있습니다. 이것이 각 함수의 값을 수정할 필요가 없는 매크로의 이점입니다. 체스판의 크기를 변경하려면 매크로에 의해 정의된 값을 변경하기만 하면 됩니다.

플레이어 체스 기능:

static void Player(char arr[ROW][COL], int row, int col, char ch)//玩家下棋函数
{
    
    
	int x = 0;
	int y = 0;
	while(1)
	{
    
    
		printf("请输入你要下棋的坐标:");
		scanf("%d %d", &x, &y);
		if (x<1 || x>row || y<1 || y>col)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (arr[x - 1][y - 1] != ' ')//判断输入坐标是否被占用
		{
    
    
			printf("你输入的坐标已被占用,请重新输入。\n");
		}
		else
		{
    
    
			arr[x - 1][y - 1] = ch;//数组下标从0开始,所以玩家的真实坐标要进行减1
			break;
		}
	}
}

컴퓨터 체스 기능:

static void Computer(char arr[ROW][COL], int row, int col, char ch)
{
    
    
	while (1)
	{
    
    
		int x = rand() % 3;//产生0~2的数字
		int y = rand() % 3;
		if (arr[x][y] == ' ')//如果坐标未被占用,则电脑下棋,否则产生新的坐标进行判断
		{
    
    
			arr[x][y] = ch;//电脑的坐标的下标和数组下标对应,不需要进行减1操作
			break;
		}
	}
}

기능 우승 여부 판단:

static char Iswin(char arr[ROW][COL], int row, int col)//判断是否获胜
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//判断每一排中是否有人获胜
	{
    
    
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][1] != ' ')
		{
    
    
			return arr[i][1];
		}
	}
	for (i = 0; i < col; i++)//判断每一列中是否有人获胜
	{
    
    
		if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[1][i] != ' ')
		{
    
    
			return arr[1][i];
		}
	}
	if ((arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ') || 
		(arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' '))//判断对角线上是否有人获胜
	{
    
    
		return arr[1][1];
	}
	for (i = 0; i < row; i++)
	{
    
    
		for (j = 0; i < col; i++)
		{
    
    
			if (arr[i][j] == ' ');//判断是否还有空位
			{
    
    
				return 'C';
			}
		}
	}
	return 'D';
}

그것을 실행하고 결과를 보자!
여기에 이미지 설명 삽입
참고:
1. 우리가 사용하는 scanf는 안전하지 않습니다.안전하지 않은 이유를 이해하려면 해당 솔루션을 찾을 수 있습니다.
2. 사용하는 배열을 초기화할 때 간격에 주의 배열 매개변수를 전달할 때 형식 매개변수와 실제 매개변수의 유형이 일치하는지 주의하십시오 char 유형의 배열을 사용합니다. 형식 매개변수는 int? 누구나 내려가서 시도해 볼 수 있습니다.
3. 이 코드를 리팩터링할 수 있으며 모두가 서로 대결할 수 있습니다. 여기서는 인간-기계 전투만 표시됩니다. 이를 리팩터링하고 인간-기계 전투에 참여해 봅시다.
형식 매개변수가 int에 의해 승인되면 배열이 범위를 벗어나고 스택 오류가 발생합니다.

3. 지뢰 찾기

아이디어: 배열을 사용하여 광산 정보를 저장하고 조사를 통해 광산이 없는 곳을 찾습니다.
1. 지도 인쇄
2. 플레이어가 지뢰 찾기 수행
3. 플레이어가 지뢰를 밟았는지 확인
4. 지도 업데이트
분석:
여기에 그림 설명 삽입 여기에 이미지 설명 삽입
위 그림은 9*9 지뢰 찾기 지도입니다. 장소, 우리는 주변 지역을 판단해야합니다. 범위를 벗어난 접근을 일으킬 수밖에 없습니다. 이 문제를 해결하는 방법?
배열을 위, 아래, 왼쪽, 오른쪽으로 한 줄씩 확장하여 판단으로 인해 배열이 범위를 벗어나지 않도록 합니다. 코드를 통해 인쇄 배열의 문제를 분석해 봅시다.
하나는 지도 정보를 저장하는 데 사용하고 다른 하나는 플레이어에게 표시하는 데 사용하는 두 개의 배열을 설정합니다.플레이어에게 표시되는 배열은 지도 정보의 배열을 저장하여 지도에서 안전한 위치를 판단해야 합니다.
먼저 5개의 매크로를 정의합니다. 각각 설정할 수 있는 지도의 크기와 인쇄된 지도의 크기를 결정하고 마지막 매크로는 나중에 테스트하기에도 편리한 지뢰 수를 저장하는 데 사용됩니다.

#define ROW 9  //显示的行
#define COL 9  //显示的列
#define ROWS ROW+2  //真实数组的行
#define COLS COL+2  //真实数组的列
#define MINENUM 10  //地雷的个数

그런 다음 게임 기능을 추가하여 특정 아이디어를 확인합니다.

static void game()
{
    
    
	int winnum = ROW * COL - MINENUM;//设置一个变量,用来存放还有多少个安全的地方
	char minemap[ROWS][COLS] = {
    
     0 };//雷分布的地图
	char showmap[ROWS][COLS] = {
    
     0 };//向玩家展示的地图
	Initialization(minemap, showmap, ROWS, COLS);//初始化数组,把雷分布随机分布在地图中,并且把向玩家展示的地图全部替换为 * 
	//Ptintinitialization(minemap, ROW, COL);//测试代码,用来打印地图
	while (winnum)
	{
    
    
		int x = 0;
		int y = 0;
		Ptintinitialization(showmap, ROW, COL);//打印展示地图
		printf("请输入排雷坐标:");
		scanf("%d %d", &x, &y);
		if (x<1 || x>ROW || y<1 || y>COL)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (showmap[x][y] != '*')//判断坐标是否已被排查过
		{
    
    
			printf("你输入的坐标已被排过雷了,请重新输入。\n");
		}
		else 
		{
    
    
			if (!Determine(minemap, x, y))//!Determine(minemap, x, y)用来判断是否踩到雷
			{
    
    
				Ptintinitialization(minemap, ROW, COL);//打印地雷地图,让玩家知道地雷在哪里。
				break;
			}
			Renewmap(minemap, showmap, x, y);//用来更新向玩家展示的地图
			winnum--;//对安全的地方进行减1
		}
	}
	if(winnum == 0)//当安全地方为0时,证明排雷成功
	{
    
    
		printf("恭喜你排雷成功!\n");
		Ptintinitialization(showmap, ROW, COL);//打印展示地图,让玩家知道自己获胜地图
	}
}

배열 함수 초기화:

static void Initialization(char minemap[ROWS][COLS], char showmap[ROWS][COLS], int rows, int cols)
{
    
    
	int count = MINENUM;//创建一个变量,用来计算放置的雷的数量
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)//把地雷地图全部赋值为字符0
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			minemap[i][j] = '0';
		}
	}
	while (count)//把雷分布随机分布在地雷地图中
	//我们把0代表安全,1代表雷区
	{
    
    
		int x = rand() % ROW + 1;//创建随机变量范围在1~9
		int y = rand() % COL + 1;//创建随机变量范围在1~9
		if (minemap[x][y] == '0')//判断该位置是否已有雷
		{
    
    
			minemap[x][y] = '1';//放置地雷
			count--;
		}
	}
	for (i = 0; i < rows; i++)//把展示地图全部赋值为字符*
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			showmap[i][j] = '*';
		}
	}
}

여기에 이미지 설명 삽입
우리가 보여주는 지도 행은 1 ~ ROW이고 열은 1 ~ COL이므로 생성된 지뢰의 좌표는 이 범위 내에서 제어됩니다.
인쇄 지도 기능:

static void Ptintinitialization(char showmap[ROWS][COLS], int row, int col)//打印地图
{
    
    
	int i = 1;
	int j = 1;
	for (i = 1; i <= row; i++)
	{
    
    
		if (i == 1)//当i为1时,需要多一个空格,目的为了和地图对齐
		{
    
    
			printf(" ");
		}
		printf(" %d", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)//打印我们所需要的地图
	{
    
    
		printf("%d", i);
		for (j = 1; j <= col; j++)
		{
    
    
			printf(" %c", showmap[i][j]);
		}
		printf("\n");
	}
}

우리는 1부터 인쇄를 시작하고, ROW까지 인쇄하고, 필요한 곳에만 인쇄합니다.
내 발을 밟을지 여부를 판단하려면:

static bool Determine(char minemap[ROWS][COLS],int x,int y)
{
    
    
	if (minemap[x][y] == '1')
	{
    
    
		printf("排雷失败,你已死亡!\n");
		return false;
	}
	else
	{
    
    
		return true;
	}
}

표시된 지도를 업데이트합니다.

static void Renewmap(char minemap[ROWS][COLS], char showmap[ROWS][COLS], int x, int y)
{
    
    
	showmap[x][y] = (minemap[x - 1][y - 1] + minemap[x - 1][y] + minemap[x - 1][y + 1]
				  + minemap[x][y - 1] + minemap[x][y + 1]
				  + minemap[x + 1][y - 1] + minemap[x + 1][y] + minemap[x + 1][y + 1]) - 8*'0' + '0';
}

여기에 이미지 설명 삽입
플레이어에게 표시되는 지도를 업데이트하여 주변 지뢰 수를 합산하고 해당 수로 교체합니다. 우리는 문자 1과 문자 0을 저장하는 문자 배열을 사용하고 있으므로 정수를 얻기 위해 ASCLL 코드 값 0을 빼야 하고, 이 사각형 주변 8곳의 지뢰 수를 나타내기 위해 더하고 마지막으로 더해야 합니다. ASCLL 코드 값 0은 해당 문자 번호를 가져옵니다.
테스트해봅시다: 테스트 코드의 주석을 해제하고 매크로에 정의된 지뢰의 수를 더 크게 설정합니다. 먼저 79로 설정했습니다. 실제로 플레이할 때 플레이하고 싶은 난이도에 따라 변경할 수 있습니다. 지뢰 제거 보기
여기에 이미지 설명 삽입
실패가 정상적으로 표시되는지 여부:
여기에 이미지 설명 삽입
지뢰 제거 실패도 정상적으로 표시됩니다.
참고:
1. scanf는 안전하지 않습니다
.
3. 리팩토링 아이디어: 확장된 맵을 추가할 수 있으며(주변 8곳에 지뢰가 없을 때 확장 가능, 그리드 주변에 지뢰가 있다는 것을 알 때까지), 작은 깃발을 추가할 수 있습니다(지뢰가 있는 장소를 대체 작은 깃발이 있는 지뢰로 간주, 작은 깃발만 취소하여 변경) 지뢰 찾기는 해당 위치에서만 수행 가능), 시간 추가(시간이 만료되면 모든 지뢰가 제거되지 않으면 게임 종료) , 등.

4. 주사위 놀이

아이디어: 어떤 플레이어가 5개의 연속 체스 조각을 수행했는지 확인합니다(동일한 체스 조각이 5개 연속되는 행 또는 열 또는 대각선) 1. 보드를 인쇄합니다. 2. 플레이어 1이
체스

합니다
. . 플레이어 2 진행 체스 플레이
5. 플레이어 2가 이겼
는지 여부 결정 우리는 여전히 매크로를 사용하여 보드의 크기를 먼저 정의합니다.

#define ROW 9  //棋盘的行
#define COL 9  //棋盘的列

게임 아이디어를 다시 살펴보십시오.

static void game()
{
    
    
	char win;//创建一个变量,存放判段获胜条件的字符。
	//我们把C代表继续,D代表平局,白棋(@)代表玩家1获胜,黑棋(O)代表玩家2获胜
	char checkerboard[ROW][COL] = {
    
     0 };//棋盘数组
	Initialization(checkerboard, ROW, COL);//初始化数组,把棋盘的所有位置都赋值为 *
	Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	while (1)
	{
    
    
		Player(checkerboard, ROW, COL, '@');//玩家1下棋,玩家1的标志为 @
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
		Player(checkerboard, ROW, COL, 'O');//玩家2下棋,玩家2的标志为 O
		win = Iswin(checkerboard, ROW, COL);//判断是否获胜
		if (win != 'C')
		{
    
    
			break;
		}
		Ptintinitialization(checkerboard, ROW, COL);//打印棋盘
	}
	if (win == 'D')
	{
    
    
		printf("平局\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
	else if (win == '@')
	{
    
    
		printf("玩家1获胜\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
	else
	{
    
    
		printf("玩家2获胜\n");
		Ptintinitialization(checkerboard, ROW, COL);
	}
}

주사위 놀이의 개념은 컴퓨터가 다른 플레이어로 교체된다는 점을 제외하면 주사위 놀이와 완전히 동일합니다. 따라서 게임 기능 코드는 기본적으로 많이 변경되지 않았습니다. 체스를 두는 플레이어의 생각은 같기 때문에 두 플레이어가 체스를 두는 생각을 해결하려면 하나의 함수만 있으면 됩니다.
배열 함수 초기화:

static void Initialization(char arr[ROW][COL], int row, int col)//初始化数组,把棋盘的所有位置都赋值为 *
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)//把展示地图全部赋值为字符*
	{
    
    
		for (j = 0; j < col; j++)
		{
    
    
			arr[i][j] = '*';
		}
	}
}

배열을 초기화하는 아이디어는 지뢰 찾기에서 플레이어에게 표시되는 맵과 정확히 동일합니다.
인쇄 지도 기능:

static void Ptintinitialization(char arr[ROW][COL], int row, int col)//打印棋盘
{
    
    
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
    
    
		if (i == 1)//当i为1时,需要多两个空格,目的为了和地图对齐
		{
    
    
			printf("  ");
		}
		if (i < 9)//当i小于9时,需要多一个个空格,目的为了和地图对齐
		{
    
    
			printf(" %d ", i);
		}
		else//当i大于于9时,不需要多一个个空格
		{
    
    
			printf(" %d", i);
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//打印我们所需要的地图
	{
    
    
		printf("%2d", i + 1);
		for (j = 0; j < col; j++)
		{
    
    
			printf(" %c ", arr[i][j]);//需要多一个个空格,目的为了和地图对齐
		}
		printf("\n");
	}
}

백개먼 지도는 마음대로 확대 및 축소할 수 있으며 지도가 위의 행과 열과 정렬되어 있는지 주의해야 합니다.
플레이어 체스 기능:

int x = 0;//用来接收玩家下棋的坐标
int y = 0;//用来接收玩家下棋的坐标
static void  Player(char arr[ROW][COL], int row, int col, char ch)//玩家下棋函数,通过ch来判断是玩家1还是玩家2
{
    
    
	int player = 0;//创建一个变量来确定是玩家几
	if (ch == '@')//如果ch为白棋(@),则代表玩家1
	{
    
    
		player = 1;
	}
	else//反之则为玩家2
	{
    
    
		player = 2;
	}
	while (1)
	{
    
    
		printf("请玩家 %d 输入要下棋的坐标:",player);
		scanf("%d %d", &x, &y);
		if (x<1 || x>row || y<1 || y>col)//判断坐标是否合法
		{
    
    
			printf("你输入的坐标不合法,请重新输入。\n");
		}
		else if (arr[x - 1][y - 1] != '*')//判断输入坐标是否被占用
		{
    
    
			printf("你输入的坐标已被占用,请重新输入。\n");
		}
		else
		{
    
    
			arr[x - 1][y - 1] = ch;//数组下标从0开始,所以玩家的真实坐标要进行减1
			break;
		}
	}
}

우리는 플레이어의 체스 좌표를 전역 변수로 설정하여 연속으로 다섯 아들의 경우인지 여부를 판단할 수 있습니다.
기능 우승 여부 판단:
여기에 이미지 설명 삽입

enum Direction
{
    
    
	LEFT,
	RIGHT,
	UP,
	DOWN,
	LEFTUP,
	RIGHTDOWN,
	RIGHTUP,
	LEFTDOWN
};
static char Iswin(char arr[ROW][COL], int row, int col)//判断是否获胜
{
    
    
	static chessnum = 0;//创建一个静态变量,用来存放棋盘中使用的格数
	chessnum++;//每进行一次判断调用就对棋盘使用格数进行+1
	int winnum1 = 1 + Wincount(arr, ROW, COL, LEFT) + Wincount(arr, ROW, COL, RIGHT);
	//确定左和右共计多少相同个棋子,需要加上自身的棋子
	int winnum2 = 1 + Wincount(arr, ROW, COL, UP) + Wincount(arr, ROW, COL, DOWN);
	//确定上和下共计多少相同个棋子,需要加上自身的棋子
	int winnum3 = 1 + Wincount(arr, ROW, COL, LEFTUP) + Wincount(arr, ROW, COL, RIGHTDOWN);
	//确定左上和右下共计多少相同个棋子,需要加上自身的棋子
	int winnum4 = 1 + Wincount(arr, ROW, COL, RIGHTUP) + Wincount(arr, ROW, COL, LEFTDOWN);
	//确定右上和左下共计多少相同个棋子,需要加上自身的棋子
	if (winnum1 >= 5 || winnum2 >= 5 || winnum3 >= 5 || winnum4 >= 5)//判断是否获胜
	{
    
    
		return arr[x - 1][y - 1];//返回获胜棋子的字符
	}
	else
	{
    
    
		if (chessnum == ROW * COL)//如果棋盘使用格数等于棋盘的格数,证明平局
		{
    
    
			return 'D';
		}
		else//如果棋盘使用格数不等于棋盘的格数,证明还有空位,继续进行比赛
		{
    
    
			return 'C';
		}
	}
}

이 8방향에서 같은 수의 체스 말을 세어야 합니다. 5연속 * 상황은 없으며, 저장한 주소는 항상 마지막 플레이어의 주소가 됩니다. 8방향을 메뉴타입으로 표현합니다.

static int Wincount(char arr[ROW][COL], int row, int col, enum Direction dir)
{
    
    
	int count = 0;//记录相同棋子个数
	int _x = x - 1;//要对坐标进行减1,因为我们的棋盘从1开始,数组下标从0开始
	int _y = y - 1;//要对坐标进行减1,因为我们的棋盘从1开始,数组下标从0开始
	//用局部变量保存,避免在这里修改全局变量的值
	while (1)
	{
    
    
		switch (dir)
		{
    
    
		case LEFT:
			_y--;//对中心坐标的列坐标进行减1
			break;
		case RIGHT:
			_y++;//对中心坐标的列坐标进行加1
			break;
		case UP:
			_x++;
			break;
		case DOWN:
			_x--;
			break;
		case LEFTUP:
			_y--;
			_x++;
			break;
		case RIGHTDOWN:
			_y++;
			_x--;
			break;
		case RIGHTUP:
			_y++;
			_x++;
			break;
		case LEFTDOWN:
			_y--;
			_x--;
			break;
		default:
			break;
		}
		if (_x < 0 || _x > ROW || _y < 0 || _y>COL)//判断位置是否合法
		{
    
    
			return count;
		}
		else if(arr[_x][_y] != arr[x-1][y-1])//判断是否和上一个玩家的棋子相同
		{
    
    
			return count;
		}
		else
		{
    
    
			count++;
		}
	}
}

같은 방향의 특정 수의 체스 말을 판단하기 위해 무한 루프로 설정했습니다. 메뉴 유형은 우리가 전달하는 매개변수와 다르기 때문에 스위치 분기에서 다른 경로를 사용합니다.
참고:
범위를 벗어난 배열입니다.
Wuzilianzhu 판단을 위한
아이디어 재구성 : 네트워크에 가입할 수 있고, 온라인 전투를 실현할 수 있으며, 유감 체스 기능을 추가할 수 있습니다.

5. 루도

게임 방법: 1. 시작 위치가 동일한 것을 제외하고 나머지 플레이어의 위치가 다른 플레이어의 위치와 같을 때 스탬피드가 발생합니다.
2. 플레이어가 소품을 밟으면 해당 소품 작업을 수행합니다.
3. 끝에 먼저 도달한 플레이어가 이기는
아이디어입니다.
1. 배열을 사용하여 지도 정보 저장
2. 구조를 사용하여 플레이어 정보 구성
3. 사용 플레이어 정보를 저장하는 구조 배열
4. 무작위 함수를 사용하여 체 작업 시뮬레이션
먼저 게임 아이디어를 구성해 보겠습니다.

int map[100];//创建一个地图大小为100的地图。并且把地图元素全部初始化为0
//为了对数组进行方便的操作,我们把数组设置为全局变量,使每个函数可以直接访问数组
static void game()
{
    
    
	struct Player play[2];//创建一个玩家数组,里面存放玩家信息
	Initializationmap();//初始化地图数组,把地图相应位置填上道具元素,
	//我们把地图数组设置为了全局函数,所以不要需要传参
	Initializationplay(play);//初始化玩家数组,加入玩家信息,并把玩家位置置于地图开始位置
	Ptintinitialization(play);//打印棋盘,地图数组为全局函数,所以不要对地图传参。
	//需要玩家信息来判断地图要填的字符,所以要对玩家进行传参
	while (1)//使玩家交替进行游玩,直到产生胜利者
	{
    
    
		if (play[0].flags == false)//判断玩家1是否处于暂停回合。
		{
    
    
			Play(&play[0], &play[1],play);//玩家1进行游戏
			Ptintinitialization(play);//打印棋盘
		}
		else//处于暂停回合,把暂停回合改为继续
		{
    
    
			play[0].flags = false;
		}
		if (play[0].position >= 99)//判断玩家1是否获胜
		{
    
    
			printf("%s侥幸赢了%s\n", play[0].name, play[1].name);
			break;
		}
		if (play[1].flags == false)//判断玩家2是否处于暂停回合。
		{
    
    
			Play(&play[1], &play[0],play);//玩家2进行游戏
			Ptintinitialization(play);//打印棋盘
		}
		else
		{
    
    
			play[1].flags = false;//更改暂停选项
		}
		if (play[1].position >= 99)//判断玩家2是否获胜
		{
    
    
			printf("%s侥幸赢了%s\n", play[1].name, play[0].name);
			break;
		}
	}
}

편의상 맵 배열을 전역 배열로 설정하여 매개변수 전달을 줄입니다. 그리고 초기화 후에 배열을 변경할 필요가 없습니다. 또한 플레이어 정보(위치, 일시 중지 위치에 있는지 여부)를 저장하기 위한 구조 배열을 설정합니다.
지도 기능을 초기화합니다.

static void Initializationmap()//初始化地图数组
//地图数组中
//0代表什么都没有
//1代表道具1(幸运轮盘),2代表道具2(地雷),3代表道具3(暂停),4代表道具4(时空隧道)
{
    
    
	int luckyturn[] = {
    
    1, 20, 45, 60, 75, 90};//在相应的位置放入 幸运轮盘
	for (int i = 0; i < sizeof(luckyturn) / sizeof(luckyturn[0]); i++)
	//sizeof(luckyturn) / sizeof(luckyturn[0])用来求出数组元素的个数
	{
    
    
		map[luckyturn[i]] = 1;
	}
	int Landmine[] = {
    
     3, 6, 19, 25, 36, 49, 69, 70, 80 };//在相应的位置放入 地雷
	for (int i = 0; i < sizeof(Landmine) / sizeof(Landmine[0]); i++)
	{
    
    
		map[Landmine[i]] = 2;
	}
	int puse[] = {
    
     2, 11, 26, 35, 44, 59, 71, 88 };//在相应的位置放入 暂停
	for (int i = 0; i < sizeof(puse) / sizeof(puse[0]); i++)
	{
    
    
		map[puse[i]] = 3;
	}
	int timetunnel[] = {
    
     5, 15, 30, 50, 77 };//在相应的位置放入 时空隧道
	for (int i = 0; i < sizeof(timetunnel) / sizeof(timetunnel[0]); i++)
	{
    
    
		map[timetunnel[i]] = 4;
	}
}

초기 맵 작업을 통해 적절한 소품을 원하는 위치에 배치할 수 있으며 소품의 위치는 선호도에 따라 변경할 수 있습니다.
플레이어 기능 초기화:

static void Initializationplay(struct Player *play)
{
    
    
	printf("请输入玩家A的姓名\n");
	scanf("%s", &(play[0].name));
	while (!strcmp(play[0].name,""))//判断玩家A的姓名是否为空
	{
    
    
		printf("玩家姓名不能为空,请重新输入玩家A的姓名\n");
		scanf("%s", &(play[0].name));
	}
	printf("请输入玩家B的姓名\n");
	scanf("%s", &(play[1].name));
	while (1)
	{
    
    
		if (!strcmp(play[1].name, ""))//判断玩家B的姓名是否为空
		{
    
    
			printf("玩家姓名不能为空,请重新输入玩家B的姓名\n");
			scanf("%s", &(play[1].name));
		}
		else if(!strcmp(play[1].name, play[0].name))//判断玩家B的姓名和玩家A是否相同
		{
    
    
			printf("玩家姓名不能一致,请重新输入玩家B的姓名\n");
			scanf("%s", &(play[1].name));
		}
		else
		{
    
    
			break;
		}
	}
	play[0].position = 0;//把玩家A的位置置于0位置(地图开始位置)
	play[0].flags = false;//把玩家A的暂停条件置为假。
	play[1].position = 0;//把玩家B的位置置于0位置(地图开始位置)
	play[1].flags = false;//把玩家B的暂停条件置为假。
}


이 함수에서 문자열 비교를 수행했습니다. 문자열 비교에 ==를 직접 사용할 수 없습니다. map 함수를 표시하려면 strcmp 함수를 사용해야 합니다 .

extern char Drawstrmap(const struct Player* play, int i);//对Drawstrmap函数进行声明
static void Ptintinitialization(const struct Player* play) //打印棋盘
//由于不会对玩家信息进行更改,我们把参数设置为const,防止在函数中误改
{
    
    
		printf("图例:幸运轮盘:#    地雷:@    暂停:I     时空隧道:>     \n");//向玩家展示道具信息
		//第一段
		for (int i = 0; i < 30; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");
		//第一竖列
		for (int i = 30; i < 35; i++)
		{
    
    
			for (int j = 0; j <= 28; j++)
			{
    
    
				printf("  ");
			}
			printf("%c ", Drawstrmap(play, i));
			printf("\n");
		}
		//第二段
		for (int i = 64; i >= 35; i--)//地图为从前向后打打印
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");
		//第二数列
		for (int i = 65; i <= 69; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
			printf("\n");
		}
	    //第三行竖列
		for (int i = 70; i <= 99; i++)
		{
    
    
			printf("%c ", Drawstrmap(play, i));
		}
		printf("\n");//画完地图换行
}

static char Drawstrmap(const struct Player* play, int i)//打印地图元素
{
    
    
	char ch;
	if (play[0].position == play[1].position && play[0].position == i)
	//当玩家1和玩家2的位置处于起始位置时
	{
    
    
		ch = 'M';
	}
	else if (play[0].position == i)//当玩家1位于当前位置时
	{
    
    
		ch = 'A';
	}
	else if (play[1].position == i)//当玩家2位于当前位置时
	{
    
    
		ch = 'B';
	}
	else
	{
    
    
		switch (map[i])
		{
    
    
		case 0://地图数组元素为0时
			ch = 'O';
			break;
		case 1:
			ch = '#';
			break;
		case 2:
			ch = '@';
			break;
		case 3:
			ch = 'I';
			break;
		case 4:
			ch = '>';
			break;
		}
	}
	return ch;
}

여기에 이미지 설명 삽입
여기서 우리는 Drawstrmap 함수를 구성합니다. 목적은 맵 배열의 정수 요소를 필요한 문자 요소로 구성하는 것입니다. 맵의 위치를 ​​전달하여 인쇄할 문자를 결정하고 맵 배열을 변경하지 않습니다.
재생 기능:

static void Play(struct Player *play1, struct Player* play2, struct Player* play)
//play1为当前玩家,play2为另一名玩家,play为玩家数组,传玩家数组方便进行位置判断
{
    
    
	int points = rand() % 6 + 1;//设置随机变量,范围为1~6
	printf("%s请按任意键开始致筛子\n", play1->name);
	system("pause");//暂停屏幕
	printf("%s筛到了%d,前进%d格,", play1->name, points, points);
	system("pause");
	play1->position += points;//对玩家位置进行更新
	Weizhi(play);//判断玩家位置是否在合法的范围内
	if (play1->position == play2->position)//现在玩家的位置和另一名玩家位置相同时
	{
    
    
		printf("%s踩到了%s,%s退6格,", play1->name, play2->name, play2->name);
		system("pause");
		play2->position -= 6;//对另一名玩家位置进行更新
		Weizhi(play);//判断玩家位置是否在合法的范围内
		printf("%s已退6格,", play2->name);
		system("pause");
	}
	else
	{
    
    
		switch (map[play1->position])//检查本位玩家是否进行到道具位置
		{
    
    
		case 0:
			printf("%s踩到了方块,安全,", play1->name);
			system("pause");
			break;
		case 1:
		{
    
    
			printf("%s踩到了幸运转盘,1————交换位置,2————轰炸对方,请选择按键\n", play1->name);
			int a = 0;//用来接收用户的选择
			scanf("%d", &a);
			while (1)
			{
    
    
				if (a == 1)
				{
    
    
					printf("%s选择了交换位置,", play1->name);
					system("pause");
					int b = play1->position;
					play1->position = play2->position;
					play2->position = b;
					Weizhi(play);//判断玩家位置是否在合法的范围内
					printf("交换完成,");
					system("pause");
					break;
				}
				else if (a == 2)
				{
    
    
					printf("%s选择了轰炸对方,%s向后退6格,", play1->name, play2->name);
					system("pause");
					play2->position -= 6;
					Weizhi(play);
					printf("执行成功,\n");
					system("pause");
					break;
				}
				else
				{
    
    
					printf("输入不正确,请重新输入");
					int ch;
					while ((ch = fgetc(stdin)) != EOF && ch != '\n');
					//清除缓冲区,防止缓冲区问题使程序不能正常进行
					scanf("%d", &a);
				}
			}
		}
			break;
		case 2:
			printf("%s踩到了地雷,退6格,", play1->name);
			system("pause");
			play1->position -= 6;
			Weizhi(play);
			break;
		case 3:
			printf("%s踩到了暂停,下一回合禁止行动", play1->name);
			system("pause");
			play1->flags = true;
			break;
		case 4:
			printf("%s踩到了时空隧道,前进十格", play1->name);
			system("pause");
			play1->position += 10;
			Weizhi(play);
			break;
		}
	}
	Weizhi(play);
	system("cls");//清除屏幕
}

체를 시뮬레이션하고 play 함수에서 소품을 사용합니다. scanf 함수 버퍼 문제를 해결하고 무한 루프를 피하기 위해 클리어 버퍼를 설정했습니다.
참고:
범위를 벗어난 배열입니다. 우리는 각 플레이어의 위치가 맵 내에 있는지 확인하고 싶습니다.
문자열 비교
재구성을 위한 아이디어: 1. 온라인 전투를 실현하기 위해 네트워크에 가입할 수 있습니다.. 2. 행운의 룰렛을 함수로 별도로 캡슐화합니다. 3. 소품을 더 추가합니다. 4. 다른 플레이어와 함께하세요. 5포인트를 추가할 수 있으며, 포인트는 소품으로 교환할 수 있습니다.

요약하다

5개의 미니 게임이 모두 완료되었습니다. 스몰 게임을 만들 때 주의할 점은 다음과 같습니다.
scanf 함수는 안전하지 않습니다. 이를 대체할 안전한 함수를 찾거나 scanf 의 보안 문제를 해결할 수 있습니다.
유형 배열뿐만 아니라 정수 배열도 주의하십시오. 범위를 벗어난 배열을 사용하고 배열 매개변수에 주의하십시오.
자주 사용하는 코드를 함수로 구성하여 코드 중복을 줄입니다.

추천

출처blog.csdn.net/2301_76986069/article/details/130986103