目录
一.修炼必备
二.三子棋详解
三.扫雷详解
四.三子棋和扫雷的完整代码
!!!恭喜你,成功突破至筑基四层!!!
一.修炼必备
1.入门必备:VS2019社区版,下载地址:Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com)
2.趁手武器:印象笔记/有道云笔记
3.修炼秘籍:牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)
4.雷劫必备:leetcode 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
注:遇到瓶颈怎么办?百度百科_全球领先的中文百科全书 (baidu.com)
二.三子棋详解
1.先看一个思维导图,理清思路
2.前提工作 —— 头文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 3 //行
#define COL 3 //列
3.框架
1)框架一般我们使用do-while循环进行解决,因为我们需要先使用一次,然后再进行判断
2)菜单
3)代码实现
void menu()
{
printf("**********************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("**********************************\n");
}
int main()
{
int option = 0;
//设置随机数种子
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &option);
switch (option)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("你选择错误,请重新选择~\n");
break;
}
} while (option);
return 0;
}
4.游戏函数概览
void game()
{
char board[ROW][COL];
char ch = '0';
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//玩家下棋
PlayerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
//电脑下棋
ComputerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
}
5.棋盘初始化:使用' '进行初始化
1)为什么需要棋盘初始化?
—— 防止数组中存储了未知值
2)为什么棋盘初始化要用' '而不用其他的字符
—— 美观且为了排版正确,使用其他字符会导致排版不正确,如使用数字等字符
3)棋盘初始化的两种方式
i.循环初始化
ii.memset初始化
4)代码实现
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
//初始化法1:循环
/*for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}*/
//初始化法2:取board数组的首地址,然后把数组中的所有字符置为''
memset(&board[0][0], ' ' , sizeof(board[0][0]) * row * col);
}
6.打印棋盘
1)棋盘模样
2)遍历方法
i.每行遍历法:一行一行的打印
ii.规律法:找出棋盘的规律,可以按照规律进行打印,
3)代码实现
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
//打印棋盘法1:直接每行每行输出
/*for (int 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");
}*/
//打印棋盘法2:找规律输出
for (int i = 0; i < row; i++)
{
//先搞定数组的输出位置
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);//把每个字符输出
if (j < col - 1)
printf("|");//最后一个|不输出
}
printf("\n");
//打印的---|要少一行
if (i < row - 1)
{
for (int i = 0; i < row; i++)
{
printf("---");
if (i < row - 1)
printf("|");//最后一个|不输出
}
printf("\n");
}
}
}
7.玩家下棋
1)思路分析
实现思路:玩家从键盘输入要下棋的位置,把玩家输入的坐标放入对应的数组索引中,还需要考虑该位置是否已经被玩家或电脑下过,没有被下过,才能继续进行操作
2)代码实现
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入你要下棋的位置(坐标范围:(1-%d,1-%d)):", row, col);
scanf("%d %d", &x, &y);
//把不存在的情况排除
if (x<1 || x > row || y < 1 || y > col)
{
printf("你输出的坐标错误,请重新输入~\n\n");
continue;
}
//排除坐标已经占用的情况
if (board[x - 1][y - 1] != ' ')
{
printf("该位置已经被占用了,请重新输入坐标~\n\n");
continue;
}
board[x - 1][y - 1] = '*';
break;
}
}
8.电脑下棋
1)思路分析
思路:电脑在没有占用的数组棋盘中进行随机下棋,一定要确保电脑下棋的位置没有被占用
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;
}
}
}
9.判断输赢
1)思路分析
思路:玩家和电脑每走一步的时候,都要进行判断输赢,看看那家已经成功的横着、竖着、×型连成了3个,那家连成了三个那家赢,注意:若是棋盘满了,则平局
2)代码实现
//判断棋盘是否已满
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int 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)
{
//判断横着是否连成3个
for (int 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];
}
//判断竖着是否连成3个
for (int i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
}
//判断交叉线是否连成3个
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
//判断棋盘是否已满
if (IsFull(board, row, col))
{
printf("棋盘已满\n");
return 'q';
}
//都没有的情况
return 'c';
}
10.game函数的总实现
void game()
{
//定义二维数组存储棋盘
char board[ROW][COL];
char ch = '0';
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
if (ch != 'c')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
if (ch != 'c')
break;
}
//判断情况:玩家、电脑赢、输、平局的情况
if (ch == '*')
{
printf("玩家赢\n\n");
}
else if (ch == '#')
{
printf("电脑赢\n\n");
}
else
{
printf("平局\n\n");
}
}
三.扫雷详解
1.看思维导图,理清思路
2.前提工作 —— 头文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 9 //行
#define COL 9 //列
#define ROWS ROW + 2
#define COLS COL + 2
#define MINECOUNT 10 //雷的数量
3.框架
1)我们常使用do-while循环进行项目开发,因为do-while会先执行后再进行判断条件
2)菜单
3)代码实现
void menu()
{
printf("*****************************\n");
printf("******* 1.扫雷游戏 *******\n");
printf("******* 2.退出 *******\n");
printf("*****************************\n");
}
int main()
{
int option = 0;
//设置随机数种子
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &option);
switch (option)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("你的选择有误,请重新选择~\n");
break;
}
} while (option);
return 0;
}
4.扫雷游戏函数具体详细
void game()
{
//设置雷
char mine[ROWS][COLS] = { 0 };
//扫雷过程在此过程进行
char show[ROWS][COLS] = { 0 };
//初始化雷区
//雷是‘1’,非雷‘0’
InitBoard(mine, ROWS, COLS, '0');
//扫雷过程中,使用'*'给初始化
InitBoard(show, ROWS, COLS, '*');
//打印界面
DisplayBoard(show, ROW, COL);
//布置雷
setMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
findMine(mine, show, ROW, COL);
}
5.初始化雷区
1)思路分析
思路:为两个数组分别进行初始化,分别传给两个数组不同的初始化值,给mine数组初始化'0',因为我们要把mine数组设置为种雷的数组,给show数组初始化为'*',因为我们在show数组中进行排雷
2)代码实现
//初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
//初始化法一
/*for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}*/
//初始化法二
memset(&board[0][0], set, sizeof(board[0][0]) * rows * cols);
}
6.打印扫雷界面
1)扫雷界面的图
2)思路分析
思路:我们需要先打印横向的索引,然后再打印每行的*值之前打印竖向的索引
3)代码实现
//打印界面
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
//打印横向索引
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
//打印竖向索引
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("\n");
}
7.布置雷
1)思路分析
思路:我们要再布置雷的数组(mine)中随机布置雷,雷的数量由程序员自己决定
2)代码实现
//布置雷
void setMine(char mine[ROWS][COLS], int row, int col)
{
int i = 0;
//随机设置雷
while (i < MINECOUNT)
{
//随机生成坐标值
int x = rand() % row + 1;
int y = rand() % col + 1;
//判断已经设置过雷
if (mine[x][y] == '1')
{
continue;
}
//设置雷
mine[x][y] = '1';
i++;
}
}
8.玩家排查雷
1)思路分析
思路:
a.遇到雷则游戏结束,则把所有的雷打印
b.没有遇到雷则显示周围的八个格子有多少个雷
c.雷全部排完,则排雷成功
2)代码实现
//判断周围有多少个坐标
int isMine(char mine[ROWS][COLS], int x, int y)
{
//判断周围八个坐标有几个雷
return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
+ mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}
//排查雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row*col - MINECOUNT)
{
printf("请输入你要排查的坐标:");
scanf("%d %d", &x, &y);
//坐标合法性判断
if (x < 1 || x > row || y < 1 || y > col)
{
printf("坐标非法,请重新输入~\n");
continue;
}
//判断该地方是不是雷
if (mine[x][y] == '1')
{
printf("踩到雷了,被炸死~\n");
DisplayBoard(mine, row, col);
break;
}
//获取周围有几个雷
int ret = isMine(mine, x, y) + '0';//+'0'免得ASCII码值对应不上
show[x][y] = ret;
//没有遇到雷,排查量少1
count++;
DisplayBoard(show, row, col);
}
//排雷成功的情况
if (count == row * col - MINECOUNT)
{
printf("恭喜你,排雷成功~\n");
}
}
四.三子棋和扫雷的完整代码
1.三子棋完整代码
1)game.h头文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.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);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
2)game.c源文件
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
//初始化法1:循环
/*for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}*/
//初始化法2:取board数组的首地址,然后把数组中的所有字符置为''
memset(&board[0][0], ' ' , sizeof(board[0][0]) * row * col);
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
//打印棋盘法1:直接每行每行输出
/*for (int 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");
}*/
//打印棋盘法2:找规律输出
for (int i = 0; i < row; i++)
{
//先搞定数组的输出位置
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);//把每个字符输出
if (j < col - 1)
printf("|");//最后一个|不输出
}
printf("\n");
//打印的---|要少一行
if (i < row - 1)
{
for (int i = 0; i < row; i++)
{
printf("---");
if (i < row - 1)
printf("|");//最后一个|不输出
}
printf("\n");
}
}
}
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入你要下棋的位置(坐标范围:(1-%d,1-%d)):", row, col);
scanf("%d %d", &x, &y);
//把不存在的情况排除
if (x<1 || x > row || y < 1 || y > col)
{
printf("你输出的坐标错误,请重新输入~\n\n");
continue;
}
//排除坐标已经占用的情况
if (board[x - 1][y - 1] != ' ')
{
printf("该位置已经被占用了,请重新输入坐标~\n\n");
continue;
}
board[x - 1][y - 1] = '*';
break;
}
}
//判断棋盘是否已满
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int 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)
{
//判断横着是否连成3个
for (int 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];
}
//判断竖着是否连成3个
for (int i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
}
//判断交叉线是否连成3个
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
//判断棋盘是否已满
if (IsFull(board, row, col))
{
printf("棋盘已满\n");
return 'q';
}
//都没有的情况
return 'c';
}
//电脑下棋
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;
}
}
}
3)test.c测试文件
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("**********************************\n");
}
void game()
{
char board[ROW][COL];
char ch = '0';
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
if (ch != 'c')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断输赢
ch = IsWin(board, ROW, COL);
if (ch != 'c')
break;
}
//判断情况:玩家、电脑赢、输、平局的情况
if (ch == '*')
{
printf("玩家赢\n\n");
}
else if (ch == '#')
{
printf("电脑赢\n\n");
}
else
{
printf("平局\n\n");
}
}
int main()
{
int option = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &option);
switch (option)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("你选择错误,请重新选择~\n");
break;
}
} while (option);
return 0;
}
2.扫雷完整代码
1)game.h头文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 9 //行
#define COL 9 //列
#define ROWS ROW + 2
#define COLS COL + 2
#define MINECOUNT 10 //雷的数量
//初始化雷区
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//显示界面
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//设置雷
void setMine(char mine[ROWS][COLS], int row, int col);
//排查雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
2)game.c源文件
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
//初始化法一
/*for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}*/
//初始化法二
memset(&board[0][0], set, sizeof(board[0][0]) * rows * cols);
}
//打印界面
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
//打印横向索引
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
//打印竖向索引
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("\n");
}
//布置雷
void setMine(char mine[ROWS][COLS], int row, int col)
{
int i = 0;
//随机设置雷
while (i < MINECOUNT)
{
//随机生成坐标值
int x = rand() % row + 1;
int y = rand() % col + 1;
//判断已经设置过雷
if (mine[x][y] == '1')
{
continue;
}
//设置雷
mine[x][y] = '1';
i++;
}
}
//判断周围有多少个坐标
int isMine(char mine[ROWS][COLS], int x, int y)
{
//判断周围八个坐标有几个雷
return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
+ mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}
//排查雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row*col - MINECOUNT)
{
printf("请输入你要排查的坐标:");
scanf("%d %d", &x, &y);
//坐标判断
if (x < 1 || x > row || y < 1 || y > col)
{
printf("坐标非法,请重新输入~\n");
continue;
}
//判断该地方是不是雷
if (mine[x][y] == '1')
{
printf("踩到雷了,被炸死~\n");
DisplayBoard(mine, row, col);
break;
}
//获取周围有几个雷
int ret = isMine(mine, x, y) + '0';//+'0'免得ASCII码值对应不上
show[x][y] = ret;
//排雷成功,排查量少1
count++;
DisplayBoard(show, row, col);
}
//排雷成功的情况
if (count == row * col - MINECOUNT)
{
printf("恭喜你,排雷成功~\n");
}
}
3)test.c测试文件
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("*****************************\n");
printf("******* 1.扫雷游戏 *******\n");
printf("******* 2.退出 *******\n");
printf("*****************************\n");
}
void game()
{
//设置雷
char mine[ROWS][COLS] = { 0 };
//扫雷过程在此过程进行
char show[ROWS][COLS] = { 0 };
//初始化雷区
//雷是‘1’,非雷‘0’
InitBoard(mine, ROWS, COLS, '0');
//扫雷过程中,使用'*'给初始化
InitBoard(show, ROWS, COLS, '*');
//打印界面
DisplayBoard(show, ROW, COL);
//布置雷
setMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
findMine(mine, show, ROW, COL);
}
int main()
{
int option = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &option);
switch (option)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("你的选择有误,请重新选择~\n");
break;
}
} while (option);
return 0;
}