猜数字游戏使用函数 对前面的猜数字游戏引入自定义函数。
将函数的声明放入 function.h 文件中,函数的定义放进 func.c 文件,主函数放在
game.c 中
1 2 3 4 5 6 7 8 9 #pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> void menu () ; void game () ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #define _CRT_SECURE_NO_WARNINGS 1 #include "function.h" ; void menu () { printf ("欢迎来到猜数字游戏!\n" ); printf ("我已经想好了一个1~100之间的数字,你能猜到它是什么吗?\n" ); printf ("按1进入游戏\n" ); printf ("按0退出游戏\n" ); } void game () { srand((unsigned )time(NULL )); int aim = rand() % 100 + 1 ; int limit = 10 ; int guess = 0 ; while (limit) { printf ("请输入你猜的数字:>" ); scanf ("%d" , &guess); if (guess > aim) { printf ("你猜的数字太大了!\n" ); limit--; } else if (guess < aim) { printf ("你猜的数字太小了!\n" ); limit--; } else { printf ("恭喜你,猜对了!\n" ); printf ("\n" ); return ; } printf ("你还有%d次机会!\n" , limit); printf ("\n" ); } printf ("很遗憾,你没有猜对!正确的数字是%d\n" , aim); return ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #define _CRT_SECURE_NO_WARNINGS 1 #include "function.h" int main () { menu(); int input = 0 ; do { scanf ("%d" , &input); switch (input) { case 1 : game(); printf ("按1继续游戏\n" ); printf ("按0退出游戏\n" ); break ; case 0 : printf ("退出游戏!\n" ); break ; default : printf ("输入不合法,请重新输入\n" ); } } while (input); return 0 ; }
到这里只是完成最简单的逻辑。还可拓展如难度选择,输入合法性,图形化界面
等。
扫雷游戏 功能说明
使用控制台实现扫雷游戏
游戏可以通过菜单实现退出或继续游玩
棋盘大小为 9 * 9
默认随机布置10个雷
如果排查位置不是雷,显示周围有几个雷
如果排查位置是雷,游戏结束
胜利条件是把所有非雷的位置找出来
设计与分析 首先游戏需要一个菜单。
其次需要一个棋盘用于存放雷与非雷,这个棋盘可以使用一个二维数组表示。
可以用 0 表示非雷,用 1 表示雷。
扫的非雷位置会显示周围有几个雷,原理就是遍历自己这行与相邻两行有多少个
1。
为防止首行和末行会出现越界问题,棋盘可以设计为 11 * 11,在这个11 * 11的
首行和末行不放雷。
文件结构 这里采用 func.h 存放函数声明, func.c 进行函数实现,test.c 用于测试, game.c
实现最终效果。
菜单 首先需要一个游戏菜单,通过自定义函数 menu 来实现。
1 2 3 4 5 6 7 void menu () { printf ("********************\n" ); printf ("*** 1. play game ***\n" ); printf ("*** 0. exit ***\n" ); printf ("********************\n" ); }
棋盘的实现 棋盘埋雷 生成一个 11 * 11 的二维数组
1 int board[11 ][11 ] = { 0 };
然后需要在这个棋盘上随机埋10个雷。
埋雷的逻辑作为一个函数 Place_landmines。
1 2 3 4 5 6 7 8 void Place_landmines (int board[11 ][11 ]) { srand((unsigned int )time(NULL )); int x = rand() % 9 + 1 ; int y = rand() % 9 + 1 ; board[x][y] = 1 ; }
测试一下是否埋雷成功
1 2 3 4 5 6 7 8 9 10 11 int arr[11 ][11 ] = { 0 };Place_landmines(arr); for (int i = 0 ;i < 11 ;i++){ for (int j = 0 ;j < 11 ;j++) { printf ("%d " , arr[i][j]); } printf ("\n" ); }
形参类型是数组,对形参的操作可以影响到实参。
为了避免重复在同一个坐标埋雷,在 Place_landmines里面增加一个判断。如果
该位置有雷就重新生成埋雷坐标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void Place_landmines (int board[11 ][11 ]) { srand((unsigned int )time(NULL )); int x = rand() % 9 + 1 ; int y = rand() % 9 + 1 ; int flag = 0 ; do { if (board[x][y] == 1 ) { x = rand() % 9 + 1 ; y = rand() % 9 + 1 ; flag = 1 ; } else { board[x][y] = 1 ; return ; } } while (flag); }
去测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int arr[11 ][11 ] = { 0 };int num = 10 ;while (num--){ Place_landmines(arr); } for (int i = 0 ;i < 11 ;i++){ for (int j = 0 ;j < 11 ;j++) { printf ("%d " , arr[i][j]); } printf ("\n" ); }
两个棋盘 然而这个棋盘上哪儿有雷哪儿没雷一目了然,用于游玩的肯定不是这个棋盘。
可以再生成一个 char 类型的 11 * 11 的二维数组,里面全部放 * 字符。用于给用户
看。
1 2 3 4 5 6 7 8 char show[11 ][11 ] = {0 }; for (int i = 0 ;i < 9 ;i++){ for (int j = 0 ;j < 9 ;j++) { show[i][j] = '*' ; } }
排雷的实现 让用户输入要查询的坐标,在对应数组中该坐标的值如果为1直接游戏结束。
如果为 0 则显示以该坐标为中心附近 3 * 3 范围内的雷的个数。而在 show 这个数
组更新后需要重新打印,所以可以将打印 show 这个数组的代码写成一个函数
print_show。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void print_show (char show[11 ][11 ]) { for (int i = 1 ;i < 10 ;i++) { for (int j = 1 ;j < 10 ;j++) { printf ("%c " , show[i][j]); } printf ("\n" ); } }
1 2 3 4 5 6 7 8 9 char show[11 ][11 ] = { 0 }; for (int i = 0 ;i < 11 ;i++){ for (int j = 0 ;j < 11 ;j++) { show[i][j] = '*' ; } } print_show(show);
用一个 No_mines 函数来计算是否排完所有雷
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int No_mines (int board[11 ][11 ]) { int num = 0 ; for (int i = 1 ; i < 10 ;i++) { for (int j = 1 ;j < 10 ;j++) { if (board[i][j] == 2 ) num++; } } if (num == 71 ) { return 0 ; } else { return 1 ; } }
如果要查询的坐标值为2,说明这里已经被排过了,提示重新输入。
将这些功能集成在 clear_mines 函数中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 void clear_mines (int board[11 ][11 ], char show[11 ][11 ]) { int x = 0 ; int y = 0 ; int flag = 0 ; do { printf ("请输入你要翻开的格子的行和列:" ); printf ("输入格式为:x,y\n" ); scanf ("%d,%d" , &x, &y); if (1 <= x && x <= 9 && 1 <= y && y <= 9 ) { if (board[x][y] == 1 ) { printf ("你踩到雷了,游戏结束!\n" ); Sleep(2000 ); system("cls" ); return 0 ; } else if (board[x][y] == 2 ) { printf ("这个格子已经被翻开了,请重新输入!\n" ); return clear_mines(board, show); } else { int count = 0 ; for (int i = x - 1 ;i <= x + 1 ;i++) { for (int j = y - 1 ;j <= y + 1 ;j++) { if (board[i][j] == 1 ) { count++; } } } show[x][y] = count + '0' ; board[x][y] = 2 ; system("cls" ); print_show(show); } } else if (x == 11 && y == 11 ) { flag = 0 ; printf ("开发者模式直接通过!\n" ); system("cls" ); } else { printf ("输入不合法,请重新输入!\n" ); return clear_mines(board, show); } flag = No_mines(board); } while (flag); printf ("游戏胜利!\n" ); Sleep(2000 ); return ; }
游戏逻辑的完整实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int main () { int input = 0 ; do { menu(); printf ("选择游戏还是退出:> " ); scanf ("%d" , &input); switch (input) { case 1 : system("cls" ); game(); break ; case 0 : printf ("退出游戏!\n" ); exit (0 ); default : printf ("输入错误,请重新输入\n" ); } } while (input); return 0 ; }
杂谈 只是简单实现了一个控制台扫雷游戏,为了方便进行测试在代码中留下了部分代码。
代码中还有诸多可以优化的地方。将在后续进行更新。
优化 -引入了宏定义,将棋盘的行列以及地雷的数量用宏定义,
这样修改数值就可以只修改宏定义处的数值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #pragma once #include <stdio.h> #include <time.h> #include <stdlib.h> #define ROW 3 #define COL 3 #define MINES 3; void menu () ;void game () ;int No_mines (int board[11 ][11 ]) ;void print_show (char show[9 ][9 ]) ;void Place_landmines (int board[11 ][11 ]) ;void clear_mines () ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 #define _CRT_SECURE_NO_WARNINGS 1 #define _CRT_SECURE_NO_WARNINGS 1 #include "func.h" void menu () { printf ("********************\n" ); printf ("*** 1. play game ***\n" ); printf ("*** 0. exit ***\n" ); printf ("********************\n" ); } void print_show (char show[ROW + 2 ][COL + 2 ]) { for (int i = 1 ;i <= ROW;i++) { for (int j = 1 ;j <= COL;j++) { printf ("%c " , show[i][j]); } printf ("\n" ); } } void Place_landmines (int board[ROW + 2 ][COL + 2 ]) { srand((unsigned int )time(NULL )); int x = rand() % ROW + 1 ; int y = rand() % COL + 1 ; int flag = 0 ; do { if (board[x][y] == 1 ) { x = rand() % ROW + 1 ; y = rand() % COL + 1 ; flag = 1 ; } else { board[x][y] = 1 ; return ; } } while (flag); } void clear_mines (int board[ROW + 2 ][COL + 2 ], char show[ROW + 2 ][COL + 2 ]) { int x = 0 ; int y = 0 ; int flag = 0 ; do { printf ("请输入你要翻开的格子的行和列:" ); printf ("输入格式为:x,y\n" ); scanf ("%d,%d" , &x, &y); if (1 <= x && x <= ROW && 1 <= y && y <= COL) { if (board[x][y] == 1 ) { printf ("你踩到雷了,游戏结束!\n" ); Sleep(2000 ); system("cls" ); return 0 ; } else if (board[x][y] == 2 ) { printf ("这个格子已经被翻开了,请重新输入!\n" ); return clear_mines(board, show); } else { int count = 0 ; for (int i = x - 1 ;i <= x + 1 ;i++) { for (int j = y - 1 ;j <= y + 1 ;j++) { if (board[i][j] == 1 ) { count++; } } } show[x][y] = count + '0' ; board[x][y] = 2 ; system("cls" ); print_show(show); } } else if (x == 11 && y == 11 ) { flag = 0 ; printf ("开发者模式直接通过!\n" ); break ; } else { printf ("输入不合法,请重新输入!\n" ); return clear_mines(board, show); } flag = No_mines(board); } while (flag); printf ("游戏胜利!\n" ); Sleep(2000 ); system("cls" ); return ; } int No_mines (int board[ROW + 2 ][COL + 2 ]) { int num = 0 ; for (int i = 1 ; i <= ROW;i++) { for (int j = 1 ;j <= COL;j++) { if (board[i][j] == 2 ) num++; } } int total = ROW * COL - MINES; if (num == total) { return 0 ; } else { return 1 ; } } void game () { int board[ROW + 2 ][COL + 2 ] = { 0 }; char show[ROW + 2 ][COL + 2 ] = { 0 }; for (int i = 0 ;i < ROW + 2 ;i++) { for (int j = 0 ;j < COL + 2 ;j++) { show[i][j] = '*' ; } } int num = MINES; while (num--) { Place_landmines(board); } for (int i = 1 ;i <= ROW;i++) { for (int j = 1 ;j <= COL;j++) { printf ("%d " , board[i][j]); } printf ("\n" ); } print_show(show); clear_mines(board, show); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #define _CRT_SECURE_NO_WARNINGS 1 #include "func.h" int main () { int input = 0 ; do { menu(); printf ("选择游戏还是退出:> " ); scanf ("%d" , &input); switch (input) { case 1 : system("cls" ); game(); break ; case 0 : printf ("退出游戏!\n" ); exit (0 ); default : printf ("输入错误,请重新输入\n" ); } } while (input); return 0 ; }