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

相关文章

C语言逗号运算符和逗号表达式的使用小结

《C语言逗号运算符和逗号表达式的使用小结》本文详细介绍了C语言中的逗号运算符和逗号表达式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 在C语言中逗号“,”也是一种运算符,称为逗号运算符。 其功能是把两个表达式连接其一般形式为:表达

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

GO语言中gox交叉编译的实现

《GO语言中gox交叉编译的实现》本文主要介绍了GO语言中gox交叉编译的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、安装二、使用三、遇到的问题1、开启CGO2、修改环境变量最近在工作中使用GO语言进行编码开发,因

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse