C语言之小游戏集合(新添五子棋)

2024-02-12 16:48

本文主要是介绍C语言之小游戏集合(新添五子棋),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明
此篇博客将会不定期更新,不断添加C编写的小游戏

这里写目录标题

  • 三子棋实现
  • 扫雷游戏
    • 1、如何存储
    • 2、对于用户棋盘和布雷棋盘的初始化
    • 3、布雷
    • 4、格式化输出检测
    • 5、用户开始扫雷
  • 五子棋
    • 1、如何存储
    • 2、对棋盘的初始化
    • 3、用户开始对战
    • 4、如何判断结果
    • 5、游戏主体调用过程

注意:所有游戏都是通过多文件实现,有对应的.c.h文件,main()函数的调用在文章的最末尾呈现

三子棋实现

这个游戏我单独写了一篇博客,具体详细思路与完整代码见

链接: https://editor.csdn.net/md/?articleId=117386293.

在这里就不做详细介绍了,但在文末会附上三子棋的代码

扫雷游戏

相信各位读者对于扫雷都不陌生,这里就不再详细介绍。
主要分析一下实现思路:

1、如何存储

既然是一款游戏,那必然少不了数据的存储,扫雷给我们的第一感觉就是用二维数组来存储了。
但是存储之后我们要进行判断时就会发现,这张表格(棋盘)的中间格子周围有8个其他格子,而边角位置就不一样了。这样对于我们编写函数得到某一格子周围有几颗雷就显得有些困难了。
所以我们应该定义一个二维数组没错,但是要定义一个比预留要用的棋盘更大的二维数组,这样上面所说的函数就会适用于每一个格子。
在这里插入图片描述
还有一个问题:
扫雷时用户看到的是自己输入坐标后对应的二维表,表中的数据都是周围未选择的STYLE已经选择了的对应周围雷的个数,这样一来,我们布置雷的棋盘就不能在对应的位置显示了,因为会产生冲突。
所以:我们应该选用一张与对用户显示表完全相同的表来布置雷的位置
综上所述
第一:选择比预期更大一点的二维数组存储数据
例如:10*10的扫雷区域

#define ROW1 12
#define COL1 12
char Show_board[ROW1][COL1];

第二:雷的布置用同样规格的另一张表存储

char Mine_board[ROW1][COL1];

2、对于用户棋盘和布雷棋盘的初始化

#define STYLE '*'
memset(Show_board, STYLE, sizeof(Show_board));
memset(Mine_board, '0', sizeof(Mine_board));

注意:memset为C语言内置的库函数,在头文件string.h下。
在这里插入图片描述
具体作用:将规定字节长度的数据按照传入的value值替换(按字节操作)

3、布雷

此操作在二维数组Mines_board[ROW1][COL1]下进行

#define NUM 20
static void SetMines(char Mine_board[][COL1], int row, int col)
{int count = NUM;while (count){int x = rand() % (ROW1 - 2) + 1;int y = rand() % (COL1 - 2) + 1;if (Mine_board[x][y] == '0'){Mine_board[x][y] = '1';count--;}}
}

4、格式化输出检测

static void showline(int col)
{for (int i = 0; i <= col - 2; i++){printf("----");}printf("\n");
}
static void ShowBoard(char Show_board[][COL1], int row, int col)
{printf("   ");for (int i = 1; i <= col - 2; i++){printf("%3d ", i);}printf("\n");showline(col);for (int i = 1; i <= row - 2; i++){printf("%-2d |", i);for (int j = 1; j <= col - 2; j++){printf(" %c |", Show_board[i][j]);}printf("\n");showline(col);}
}

5、用户开始扫雷

void FindMines()
{srand((unsigned long)time(NULL));char Show_board[ROW1][COL1];char Mine_board[ROW1][COL1];memset(Show_board, STYLE, sizeof(Show_board));memset(Mine_board, '0', sizeof(Mine_board));SetMines(Mine_board, ROW1, COL1);//count表示用户需要扫雷成功的次数//只有完成规定的次数用户才能赢int count = (ROW1 - 2)*(COL1 - 2) - NUM;while (count){system("cls");ShowBoard(Show_board, ROW1, COL1);int x = 0;int y = 0;printf("Please Enter Your Choose<x,y>#");scanf("%d %d", &x, &y);if (x<1 || x>(ROW1 - 1) || y<1 || y>(COL1 - 1)){printf("Your Choose Is Error! Please Try Again\n");continue;}if (Show_board[x][y] != STYLE){printf("Your Choose Is Error! Please Try Again\n");continue;}if (Mine_board[x][y] == '1'){printf("Game over!\n");break;}//此条语句表示相对应的位置写入周围的雷数Show_board[x][y] = CountMines(Mine_board, x, y);count--;}ShowBoard(Mine_board, ROW1, COL1);
}

== CountMines(Mine_board, x, y)==求<x,y>周围的雷的个数

static char CountMines(char Mine_board[][COL1], int x, int y)
{//求出周围雷的个数,转换成字符表示//例如有6颗雷就返回字符‘6’char count = Mine_board[x - 1][y - 1] + Mine_board[x - 1][y] + Mine_board[x - 1][y + 1] + Mine_board[x][y + 1] \+ Mine_board[x + 1][y + 1] + Mine_board[x + 1][y] + Mine_board[x + 1][y - 1] + Mine_board[x][y - 1] - 7 * '0';return count;
}

扫雷完整代码如下:
FindMines.h

#pragma once#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <stdlib.h>#define ROW1 12
#define COL1 12
#pragma warning(disable:4996)
#define STYLE '*'
#define NUM 20
extern void FindMines();

FindMines.c

#include "FindMines.h"static void SetMines(char Mine_board[][COL1], int row, int col)
{int count = NUM;while (count){int x = rand() % (ROW1 - 2) + 1;int y = rand() % (COL1 - 2) + 1;if (Mine_board[x][y] == '0'){Mine_board[x][y] = '1';count--;}}
}static void showline(int col)
{for (int i = 0; i <= col - 2; i++){printf("----");}printf("\n");
}
static void ShowBoard(char Show_board[][COL1], int row, int col)
{printf("   ");for (int i = 1; i <= col - 2; i++){printf("%3d ", i);}printf("\n");showline(col);for (int i = 1; i <= row - 2; i++){printf("%-2d |", i);for (int j = 1; j <= col - 2; j++){printf(" %c |", Show_board[i][j]);}printf("\n");showline(col);}
}
static char CountMines(char Mine_board[][COL1], int x, int y)
{char count = Mine_board[x - 1][y - 1] + Mine_board[x - 1][y] + Mine_board[x - 1][y + 1] + Mine_board[x][y + 1] \+ Mine_board[x + 1][y + 1] + Mine_board[x + 1][y] + Mine_board[x + 1][y - 1] + Mine_board[x][y - 1] - 7 * '0';return count;
}void FindMines()
{srand((unsigned long)time(NULL));char Show_board[ROW1][COL1];char Mine_board[ROW1][COL1];memset(Show_board, STYLE, sizeof(Show_board));memset(Mine_board, '0', sizeof(Mine_board));SetMines(Mine_board, ROW1, COL1);int count = (ROW1 - 2)*(COL1 - 2) - NUM;while (count){system("cls");ShowBoard(Show_board, ROW1, COL1);int x = 0;int y = 0;printf("Please Enter Your Choose<x,y>#");scanf("%d %d", &x, &y);if (x<1 || x>(ROW1 - 1) || y<1 || y>(COL1 - 1)){printf("Your Choose Is Error! Please Try Again\n");continue;}if (Show_board[x][y] != STYLE){printf("Your Choose Is Error! Please Try Again\n");continue;}if (Mine_board[x][y] == '1'){printf("Game over!\n");break;}Show_board[x][y] = CountMines(Mine_board, x, y);count--;}ShowBoard(Mine_board, ROW1, COL1);
}

三子棋完整代码
ThreeGmae.h

# pragma once
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <stdlib.h>#define ROW 3
#define COL 3
#define INIT ' '
#define WHITE 'X'
#define BLACK 'O'
#define NEXT 'D'
#define DRAW 0extern void ThreeGame();

ThreeGame.c

#include "ThreeGame.h"//初始化棋盘
static void Init(char board[][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = INIT;}}
}
static void Showbard(char board[][COL], int row, int col)
{system("cls");printf(" ");for (int i = 0; i <col; i++){printf("%4d", i + 1);}printf("\n----------------\n");for (int i = 0; i < row; i++){printf("%-2d", i + 1);for (int j = 0; j < col; j++){printf("| %c ", board[i][j]);}printf("\n----------------\n");}
}
static void PlayerMove(char board[][COL], int row, int col)
{int x = 0;int y = 0;while (1){printf("Please Enter Your  Position<x,y>#\n");scanf("%d %d", &x, &y);if (x<1 || x>3 || y<1 || y>3){printf("Enter Error! Try Again\n");continue;}if (board[x - 1][y - 1] == INIT){board[x - 1][y - 1] = WHITE;break;}else{printf("This position is not empty,please enter again!\n");}}
}static char IsEnd(char board[][COL], int row, int col)
{//判断行for (int i = 0; i < row; i++){if (board[i][0] == board[i][1] && \board[i][1] == board[i][2] && \board[i][0] != INIT){return board[i][0];}}//判断列for (int j = 0; j < col; j++){if (board[0][j] == board[1][j] && \board[1][j] == board[2][j] && \board[0][j] != INIT){return board[0][j];}}//判断对角线if (board[0][0] == board[1][1] && \board[1][1] == board[2][2] && \board[1][1] != INIT){return board[1][1];}if (board[0][2] == board[1][1] && \board[1][1] == board[2][0] && \board[1][1] != INIT){return board[1][1];}return NEXT;
}static void ComputerMove(char board[][COL], int row, int col)
{while (1){int x = rand() % ROW;int y = rand() % COL;if (board[x][y] == INIT){board[x][y] = BLACK;break;}}
}void ThreeGame()
{srand((unsigned long)time(NULL));char board[ROW][COL];Init(board, ROW, COL);char result = 0;while (1){Showbard(board, ROW, COL);PlayerMove(board, ROW, COL);result = IsEnd(board, ROW, COL);if (result != NEXT){break;}Showbard(board, ROW, COL);ComputerMove(board, ROW, COL);result = IsEnd(board, ROW, COL);if (result != NEXT){break;}}Showbard(board, ROW, COL);switch (result){case WHITE:printf("You Win\n");break;case BLACK:printf("You lose\n");break;case DRAW:printf("you == computer\n");break;default:printf("Bug!\n");break;}
}

五子棋

日常玩的小游戏,话不多说,直接进行思路分析!!
这与三子棋的实现方式基本相似,但又有不同!

1、如何存储

选用二维数组int board[ROW][COL]存储信息,其中ROW和COL为宏定义,分别表示行和列

2、对棋盘的初始化

将二维数组初始化为全零,在输出时判断若为0输出 .,如下图所示;

int board[ROW2][COL2] = { 0 };

在这里插入图片描述

3、用户开始对战

用户1与用户2分别通过输入坐标<x,y>系统在对应位置board[x][y]填入对应的信息。此篇文章中,用户1 2的定义如下

#define PLAYER1 1
#define PLAYER2 2

对于用户的每一次输入,我们都要判断输入坐标的合法性,具体通过函数PlayerMove()函数来实现

static void PlayerMove(int board[][COL2], int row, int col,int who)
{while (1){printf("Please Enter Your Position<x,y>[player%d]#", who);scanf("%d %d", &x, &y);if (x<0 || x>ROW2 - 1 || y<0 || y>COL2 - 1){printf("This Position is Error,Please Enter Again\n");continue;}else{if (board[x][y] == 0){board[x][y] = who;break;}else{printf("This Position is not empty, Please Enter Again\n");}}}	
}

此函数的参数传入who是什么原因呢?
答案是:确定目前是哪一位玩家在输入。具体作用下面揭晓

4、如何判断结果

和三子棋一样,落完一子后结果无非就是四种,用户1赢,用户2赢,平局和继续。
那如何判断呢?
很简单,只需要判断上一个落子位置的八个方向有没有出现五子连珠的情况,若有,则说明上一个落子的玩家获胜。若没有,就判断有无平局的情况出现(这里平局说明棋盘落子已满,但未出现有一方有五子连珠的情况),剩下的就是对局未结束,继续落子。
到这里,读者就应该发现PlayerMove()函数传入参数who的作用了(为了方便判断输赢)
具体细节见代码:

static int ChessCounts(int board[][COL2], int dir)
{int _x = x;int _y = y;int count = 0;while (1){switch (dir){case UP:_x--;break;case RIGHT_UP:_x--, _y++;break;case RIGHT:_y++;break;case RIGHT_DOWN:_x++, _y++;break;case DOWN:_x++;break;case LEFT_DOWN:_x++, _y--;break;case LEFT:_y--;break;case LEFT_UP:_x--, _y--;break;default :printf("Error\n");break;}if (_x<0 || _x>ROW2 - 1 || _y<0 || _y>COL2 - 1){break;}else{if (board[x][y] != 0 && board[x][y] == board[_x][_y]){count++;}else{break;}}}return count;
}static int Judge(int board[][COL2], int row, int col)
{int count = 0;count = ChessCounts(board, UP) + ChessCounts(board, DOWN)+1;if (count >= 5){return board[x][y];}count = ChessCounts(board, RIGHT_UP) + ChessCounts(board, LEFT_DOWN) + 1;if (count >= 5){return board[x][y];}count = ChessCounts(board, LEFT) + ChessCounts(board, RIGHT) + 1;if (count >= 5){return board[x][y];}count = ChessCounts(board, LEFT_UP) + ChessCounts(board, RIGHT_DOWN) + 1;if (count >= 5){return board[x][y];}for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] != 0){return NEXT2;}}}return DRAW2;
}

其中ChessCounts()函数的作用是
计算每一组方向与上次落子相同的棋子个数。
这里的每一组方向指的是上下,左右,左上右下。左下右上

5、游戏主体调用过程

void Gobang()
{int board[ROW2][COL2] = { 0 };int result = 0;while (1){ShowBoard(board, ROW2, COL2);PlayerMove(board, ROW2, COL2,PLAYER1);result = Judge(board, ROW2, COL2);if (result != NEXT2){break;}ShowBoard(board, ROW2, COL2);PlayerMove(board, ROW2, COL2,PLAYER2);result = Judge(board, ROW2, COL2);if (result != NEXT2){break;}}ShowBoard(board, ROW2, COL2);switch (result){case PLAYER1:printf("Player1 win!\n");break;case PLAYER2:printf("Player2 win!\n");break;case DRAW2:printf("Draw!\n");break;default:break;}
}

五子棋完整代码
Gobang.h

#pragma once 
#include <stdio.h>
#include <windows.h>
extern void Gobang();
#define ROW2 10
#define COL2 10#define PLAYER1 1
#define PLAYER2 2
#define NEXT2 3
#define DRAW2 4
#define UP 10
#define RIGHT_UP 11
#define RIGHT 12
#define RIGHT_DOWN 13
#define DOWN 14
#define LEFT_DOWN 15
#define LEFT 16
#define LEFT_UP 17
#pragma warning(disable:4996)

Gobang.c

#include "Gobang.h"
int x = 0;
int y = 0;static void ShowBoard(int board[][COL2], int row, int col)
{system("cls");printf("   ");for (int i = 0; i < COL2; i++){printf("%3d",i);}printf("\n");for (int i = 0; i < ROW2; i++){printf("%-2d |",i);for (int j = 0; j < COL2; j++){if (board[i][j] == 0){printf(" . ");}else if (board[i][j] == PLAYER1){printf(" o ");}else if (board[i][j] == PLAYER2){printf(" x ");}}printf("\n");}
}
static void PlayerMove(int board[][COL2], int row, int col,int who)
{while (1){printf("Please Enter Your Position<x,y>[player%d]#", who);scanf("%d %d", &x, &y);if (x<0 || x>ROW2 - 1 || y<0 || y>COL2 - 1){printf("This Position is Error,Please Enter Again\n");continue;}else{if (board[x][y] == 0){board[x][y] = who;break;}else{printf("This Position is not empty, Please Enter Again\n");}}}	
}static int ChessCounts(int board[][COL2], int dir)
{int _x = x;int _y = y;int count = 0;while (1){switch (dir){case UP:_x--;break;case RIGHT_UP:_x--, _y++;break;case RIGHT:_y++;break;case RIGHT_DOWN:_x++, _y++;break;case DOWN:_x++;break;case LEFT_DOWN:_x++, _y--;break;case LEFT:_y--;break;case LEFT_UP:_x--, _y--;break;default :printf("Error\n");break;}if (_x<0 || _x>ROW2 - 1 || _y<0 || _y>COL2 - 1){break;}else{if (board[x][y] != 0 && board[x][y] == board[_x][_y]){count++;}else{break;}}}return count;
}static int Judge(int board[][COL2], int row, int col)
{int count = 0;count = ChessCounts(board, UP) + ChessCounts(board, DOWN)+1;if (count >= 5){return board[x][y];}count = ChessCounts(board, RIGHT_UP) + ChessCounts(board, LEFT_DOWN) + 1;if (count >= 5){return board[x][y];}count = ChessCounts(board, LEFT) + ChessCounts(board, RIGHT) + 1;if (count >= 5){return board[x][y];}count = ChessCounts(board, LEFT_UP) + ChessCounts(board, RIGHT_DOWN) + 1;if (count >= 5){return board[x][y];}for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] != 0){return NEXT2;}}}return DRAW2;
}
void Gobang()
{int board[ROW2][COL2] = { 0 };int result = 0;while (1){ShowBoard(board, ROW2, COL2);PlayerMove(board, ROW2, COL2,PLAYER1);result = Judge(board, ROW2, COL2);if (result != NEXT2){break;}ShowBoard(board, ROW2, COL2);PlayerMove(board, ROW2, COL2,PLAYER2);result = Judge(board, ROW2, COL2);if (result != NEXT2){break;}}ShowBoard(board, ROW2, COL2);switch (result){case PLAYER1:printf("Player1 win!\n");break;case PLAYER2:printf("Player2 win!\n");break;case DRAW2:printf("Draw!\n");break;default:break;}
}

游戏主函数
这里依旧采用多文件编程,日后会在此篇博客的基础之上进行新游戏的添加,各位看官常来回访~~

#include "ThreeGame.h"
#include "FindMines.h"
#include "Gobang.h"void Menu()
{printf("+----------------------+\n");printf("|      1.ThreeGame     |\n");printf("|      2.Findmines     |\n");printf("|      3.Gobang        |\n");printf("|      0.Exit          |\n");printf("+----------------------+\n");
}int main()
{int quit = 0;while (!quit){Menu();int select = 0;printf("Please Enter Your Choose#");scanf("%d", &select);switch (select){case 1:ThreeGame();break;case 2:FindMines();break;case 3:Gobang();break;case 0:printf("ByeBye!\n");quit = 1;break;default:printf("Bug!\n");break;}}system("pause");return 0;
}

这篇关于C语言之小游戏集合(新添五子棋)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/703085

相关文章

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

使用C语言实现交换整数的奇数位和偶数位

《使用C语言实现交换整数的奇数位和偶数位》在C语言中,要交换一个整数的二进制位中的奇数位和偶数位,重点需要理解位操作,当我们谈论二进制位的奇数位和偶数位时,我们是指从右到左数的位置,本文给大家介绍了使... 目录一、问题描述二、解决思路三、函数实现四、宏实现五、总结一、问题描述使用C语言代码实现:将一个整

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st

Go语言中最便捷的http请求包resty的使用详解

《Go语言中最便捷的http请求包resty的使用详解》go语言虽然自身就有net/http包,但是说实话用起来没那么好用,resty包是go语言中一个非常受欢迎的http请求处理包,下面我们一起来学... 目录安装一、一个简单的get二、带查询参数三、设置请求头、body四、设置表单数据五、处理响应六、超

C语言中的浮点数存储详解

《C语言中的浮点数存储详解》:本文主要介绍C语言中的浮点数存储详解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、首先明确一个概念2、接下来,讲解C语言中浮点型数存储的规则2.1、可以将上述公式分为两部分来看2.2、问:十进制小数0.5该如何存储?2.3 浮点