一 . 准备环境
1,Visual Studio下载好,创建出 .c 后缀的源文件
2. 启动 —— 创建新项目——创建c++空项目——快捷键(CTRL + SHIFT + A)添加新项
—— 把文件后缀的 .cpp 改为 .c
3.如果用的是搜狗输入法, 建议打开中文时使用英文标点
2,复制下面代码在最前面
#define _CRT_SECURE_NO_WARNINGS 1 //防止报错
#include<stdio.h> //头文件, 调用库函数需要的
// 是注释, 程序在执行的时候会忽视 //后面的东西, 可以随便写
二 . 准备知识
1.数据类型
char字符型:如:‘×’ ‘¥’ ‘2’ ‘P’,用单引号引起来表示字符型的数据
char c = '*';
//创建了一个字符变量c,c的值是'*'
//不同的字符对应不同的ASCII码值, int型的2,和字符型的'2'只是看起来一样。
// ; 就是程序中的句号, 代表一句话结束
int整型:整数类型,如:1,-5,78,666……
int a = 666;
//创建了一个整型变量 a,a的值是666
2.数组
数组是一组相同元素的集合,下面的代码是两个不同类型数组初始化的例子
char arr[5] = {'1', '2', '3', '4', '5'};
//在char类型的数组arr里面放了5个元素, 分别是'1' '2' '3' '4' '5', 每个元素的类型是char型
int brr[3] = {1, 2, 3};
//整型数组brr里面放了三个元素, 分别是 1 2 3 , 元素类型是int型
数组元素存放好了之后, 我希望找到里面的元素, 怎么办呢? 数组的每个元素都有它的下标, 数组下标从0开始的. 在int brr[3]数组里,
brr[0] == 1
brr[1] == 2
brr[2] == 3 (= 可以理解为 "让它等于" , == 可以理解为 "是不是等于")
同理, 在char arr数组里面, arr[2] 就代表数组里面的 '3'
如果说一维数组就是一行m个相同元素的集合, 二维数组就是n行m列相同元素的集合,
一维数组代表线, 二维数组就是面, 多了一个维度. 以下是二维数组的初始化.
int crr[3][5] = {1, 2, 3, 4, 5,
2, 3, 4, 5, 6
3, 4, 5, 6, 7}; //写成一排不用换行也可以
char drr[2][2] = {'*', ' ', ' ', '*'}; //第二第三个元素是空格, 空格也是字符类型的一种
二维数组的使用和一维数组一样也是通过下标来访问的, 我们习惯的行和列都是从1开始的, 而二维数组里的行和列下标都是从0开始的, 所以使用下标的时候要减1.
在int crr[3][5]里 第二行第二列的元素3就是 crr[1][1]
第三行第四列的元素6就是 crr[2][3]
第三行第五列的元素7就是 crr[2][4]
在char drr[2][2]里 第三个元素是 ' ' (空格) 虽然是写成一排, 但实际上还是两行两列
所以第三个元素的位置是第二行第一列, 就是 drr[1][0]
注意:在表示数组的时候前面要加上数组的元素类型(char / int), 如果不加表示的其实是数组里面的元素。
3.函数
函数是解决特定任务的一段代码, int main()这个就是一个函数, 也叫main(梦)函数, C语言中代码是从main函数的第一句开始执行的, 梦开始的地方嘛~
main函数前面的 int 代表main函数的返回类型是int这种数据类型
main(), 小括号里面什么都没有, 说明没有参数
库函数就是已经写好了的函数, 如 printf 输出, (CTRL+F5)运行
#include<stdio.h>
int main(){
printf("hello world!\n");
// \n代表换行
return 0;
//return 0; 就是返回0的意思, 当函数的返回类型是void时, 就不需要return
}
printf 双引号里面的内容可以直接打印出来, 实际输出hello word (换行)
到这里, 终于可以开始做扫雷游戏的第一步了, 第一步就应该是开始的界面, 能够选择游戏开始或者游戏结束这样一个界面. 我们写一个新函数menu来实现这个功能, 这个menu函数就是自定义函数,
#define _CRT_SECURE_NO_WARNINGS 1 //防止报错
#include<stdio.h> //头文件, 调用库函数需要的
void menu(){ //void代表空的返回类型
printf("*************************************\n");
printf("************* 1. paly *************\n");
printf("************* 0. exit *************\n");
printf("*************************************\n");
}
int main(){
menu();
return 0;
}
接下来, 我们需要与这个程序互动, 来决定是要开始游戏还是结束游戏, 我们需要scanf函数. 这时候出现一个问题, scanf函数如何判断我的输入的数据类型呢? 这里需要用到 占位符
如果输入类型是int , 占位符需要%d,
如果输入的类型是char, 占位符需要%c,
如果输入类型是字符串(由多个字符组成的串), 占位符需要%s, 双引号括起来的其实就是字符串
%d后面的&input, "&" 的名字叫"取地址"
新的两段代码的意思是: 把刚刚创建的input变量的值改变为我自己输入的值
int main(){
menu();
int input = 0;
scanf("%d", &input);
return 0;
}
我们已知printf会打印双引号里面的内容, 而如何通过占位符, 打印我们刚刚输入的input呢 ?
int main(){
int input = 0;
scanf("%d", &input);
printf("%d\n", input);
return 0;
}
在上述代码中, scanf和printf函数的参数是什么呢?
scanf 有两个参数, 一个是 "%d", 一个是 &input, 两个参数用逗号相连
printf有两个参数, 一个是"%d\n", 一个是input
4.if_else和do_while
回到我们的游戏的menu函数打印的菜单我们发现, 1是开始游戏, 0是退出游戏, 这是两种不同选择,
如果我们的input是1, 我们去执行开始游戏的代码,
如果我们的input是0, 我们去执行结束游戏的代码,
在c语言中如何实现呢?
int main(){
menu();//menu代码放在main函数的上面就不展示了
int input = 0;
scanf("%d", &input);
if(input == 1){
printf("开始游戏\n");
}
else(input == 0){
printf("游戏结束\n");
}
return 0;
}
这个if _ else 语句有两个分支, 可是如果我输入的既不是1也不是0, 输错了, 想重新输入一次怎么办呢? 只要再加上一个分支就好了, 这时候就需要 if__else if__ else了
int main(){
menu();
int input = 0;
scanf("%d", &input);
if(input == 1){
printf("开始游戏\n");
}
else if(input == 0){
printf("游戏结束\n");
}
else{
printf("重新输入\n");
}
return 0;
}
这样就新添加了一个分支, 可是时间运行发现, 当输入其他值的时候, 只是打印了"重新输入"四个字, 程序并没有返回上面的scanf让我们重新输入, (else后面没有条件是代表除了上述两个条件以外的其他所有情况)
我们需要让它循环起来, 这里使用do_while循环, do就是执行, 当while后面的条件不满足的时候就跳出循环
input != 0 意思是 input 不等于 0 ,
程序从上往下执行的时候
当input不等0这个条件满足的时候, 就继续循环, 跳回到do后面,
当input不等0这个条件不满足的时候, 就跳出循环, 也就是input等于0时循环结束,
int main(){
int input = 0;
do{
menu();
scanf("%d", &input);
if(input == 1){
printf("开始游戏\n");
}
else if(input == 0){
printf("游戏结束\n");
}
else{
printf("重新输入\n");
}
} while(input != 0)
return 0;
}
三 . 游戏逻辑
1.game函数
当我们输入1的时候, 程序只是苍白的打印了一下"开始游戏", 显然我们需要一个game函数来实现我们的扫雷游戏
扫雷游戏都需要什么步骤呢?
1.首先我需要打印一下我们的游戏界面, 创造函数DisplayBoard()
2.然后我们需要在棋盘里面随机布置雷, 创造函数SetMine()
3.最后我们要排查雷, 判断游戏胜利与否, 创造函数FindMine()
只要在我们能game函数里实现这些函数, 我们的扫雷游戏也就实现了
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void game() {
//打印棋盘
DisplayBoard();
//随机布置雷
SetMine();
//排查雷
FindMine();
}
void menu() {
printf("*************************************\n");
printf("************* 1. paly *************\n");
printf("************* 0. exit *************\n");
printf("*************************************\n");
}
int main() {
int input = 0;
do {
menu();
scanf("%d", &input);
if (input == 1) {
printf("游戏开始\n");
game();
}
else if (input == 0) {
printf("游戏退出\n");
}
else {
printf("请重新输入\n");
}
} while (input != 0);
return 0;
}
我们的游戏棋盘是什么样子的呢? 如果我希望让它9*9, 里面全都是'*' 如图
不难发现这其实是一个char类型的二维数组 里面所有的元素都是'*'那就创建这个二维数组 char show[9][9] , 不过怎么初始化呢? 难道要打上去9*9==81个'*'嘛?
这时候为了方便就不得不引入另一种循环 ----> for循环
2.for循环
for循环的基本格式为:
for ( 初始化 ; 判断 ; 调整) { 中间以分号相连
循环体;
}
int main(){ int i = 0; for(i = 0; i < 10; i++) //i++是 i = i + 1的意思, 循环每次自增1 { printf("哎, 你好, 哈哈\n"); } return 0; }
i = 0 初始化决定了循环在哪里开始
i < 10 判断决定了循环在哪里结束 当 i 不满足判断 i < 10 (即 i >= 10) 的时候跳出循环
i++ 调整 决定了循环是因为什么结束的
可是我们的char show[9][9]是二维数组, 我们就需要循环嵌套循环来进行初始化, i从0到8的每一个i值, 都有j从0到8的9次循环, 一共进行了9*9 == 81次循环,
我们先不完全初始化 char show[9][9] = {0}; 当不完全初始化的时候,其他的元素默认是0
在用for循环进行81次循环让show数组里面的所以元素都变成 ' * '
int i = 0; int j = 0; for(i = 0; i < 9; i++){ for(j = 0; j < 9; j++) { show[i][j] = '*'; } }
我们打印棋盘的时候也可以利用这种格式, 有一些小调整, 打印的每个数组元素之间多一个空格, 分散一点, 并且在每一行元素打印完之后, 加一个\n换行.
int i = 0; int j = 0; for(i = 0; i < 9; i++){ for(j = 0; j < 9; j++) { printf("%c ", show[i][j]) } printf("\n"); }
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void DisplayBoard(char show[9][9]){
int i = 0; int j = 0;
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++)
{
printf("%c ", show[i][j]);
}
printf("\n");
}
}
void game() {
char show[9][9]= {0};
int i = 0; int j = 0;
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++)
{
show[i][j] = '*';
}
}
//打印棋盘
DisplayBoard(show);
//随机布置雷
//SetMine();
//排查雷
//FindMine();
}
void menu() {
printf("*************************************\n");
printf("************* 1. paly *************\n");
printf("************* 0. exit *************\n");
printf("*************************************\n");
}
int main() {
int input = 0;
do {
menu();
scanf("%d", &input);
if (input == 1) {
printf("游戏开始\n");
game();
}
else if (input == 0) {
printf("游戏退出\n");
}
else {
printf("请重新输入\n");
}
} while (input != 0);
return 0;
}
3.优化1
优化一下目前的代码, 能不能在行和列前面都加上一排数字, 方便我们查找坐标, 这边直接贴出来我的方案,
void DisplayBoard(char show[9][9]) { int i = 0; int j = 0; printf("------------------------------------\n"); for (i = 0; i <= 9; i++) { printf("%d ", i); } printf("\n"); for (i = 0; i < 9; i++) { printf("%d ", i+1); for (j = 0; j < 9; j++) { printf("%c ", show[i][j]); } printf("\n"); } }
我觉得9*9的棋盘太大了, 我能不能更改一下棋盘的大小?
代码里面这么多9, 能不能一口气全改了?
VS里数组在初始化的时候[]里面不能填变量, 这时候就需要用到我们的define了
#define ROW 5 //定义数组的行是5 #define COL 5 //定义数组的列是5
这时候把所有代表行的都换成ROW, 把所有列的都换成COL, 需要更改的时候改一下后面的数字就可以了
4.游戏逻辑的思考
我们的目标是:
输入一个坐标, 像(1,1) (3,5) 这样的, 游戏可以判断我这个位置是不是雷,
如果是雷就返回 "游戏失败" . 如果不是雷, 就返回周围雷的个数, 以便判断雷的位置.
把所有不是雷的地方找出来, 返回 "游戏胜利"
而且我每一次输入1开始游戏, 雷的位置要随机变化
问题
1.怎么随机布置雷?
2.我数组里面如何即存储字符 ' * ' , 又存储里面是不是雷的信息呢?3.如果我访问到我的数组边缘怎么办? 数组边缘的周围一圈的信息里面有我不知道的信息呀, 数组大小就是9*9, 你去访问9行9列后面的或者下面的元素, 程序不就出错了吗?
回答
1.C语言提供srand函数可以产生随机数, 通过学习这个函数布置随机雷
2.显然是不可能同时存储两个信息的, 但是我们可以创建一个一摸一样的二维数组专门用来存放雷的信息, 这样在一个位置通过访问不同的数组就可以找到不同的信息了
3.我们可以创造大一圈的二维数组, 也就是11*11的数组, 而找雷的时候只找内圈的9*9, 这样就不怕越界访问啦
有关后面的具体实现我们下期再聊~~
下一期地址: C语言零基础速通扫雷游戏(下)-CSDN博客