目录
一.修炼必备
二.三子棋详解
三.扫雷详解
四.三子棋和扫雷的完整代码
!!!恭喜你,成功突破至筑基四层!!!
一.修炼必备
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;//没有遇到雷,排查量少1count++;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;//排雷成功,排查量少1count++;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;
}