c语言作业1

阅读: 评论:0

c语言作业1

c语言作业1

扫雷代码分析

这段小程序中,我们首先要学会以下三个方面

1.颜色

小方块 ■ 是灰色的,方框 □ 是白色的,炸弹 ● 是黄色的
需要通过不同的颜色来表示炸弹、方框以及用户选定的区域
参考教材彩色版的C语言

说明:1.可以调用windows.h头文件下的setconsoletextattribute代码块函数来改变颜色与背景颜色
调用形式为SetConsoleTextAttribute( HANDLE hConsoleOutput, WORD wAttributes );
hConsoleOutput表示控制台缓冲区句柄,可以通过GetStdHandle(STD_OUTPUT_HANDLE)来获得;
wAttributes表示文字颜色和背景颜色

0~F分别代表的颜色
0 = 黑色 8 = 灰色 1 = 淡蓝 9 = 蓝色
2 = 淡绿 A = 绿色 3 = 湖蓝 B = 淡浅绿
C = 红色 4 = 淡红 5 = 紫色 D = 淡紫
6 = 黄色 E = 淡黄 7 = 白色 F = 亮白

#include <stdio.h>
#include <stdlib.h>
#include<windows.h>
int main()
{   HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hConsole,0x2c);printf("Hello world!n");return 0;
}

如果只希望字改变颜色不改变背景则:

  SetConsoleTextAttribute(hConsole,0xC);//将文字改为颜色为红色SetConsoleTextAttribute(hConsole,0xF);//将文字颜色改为白色

在扫雷小游戏中改变颜色的函数代码

void color(int m) {HANDLE consolehend;consolehend = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(consolehend, m);
}//m为要变的颜色

2. 键盘监听

通过用户输入Y/N来判断是否开始扫雷游戏,即通过键盘的输入不进行回车即可进行运行开始程序:
学习链接(C语言的非阻塞式键盘监听)
通过getchar(),getche(),getch()
以下代码利用了getchar()代码的使用:

#include <stdio.h>
#include <stdlib.h>
int main()
{  char ch;int i=0;//循环监听直到按下esc键后退出while(ch=getch()){if(ch==27)break;elseprintf("%dn",++i);}  return 0;
}

以上代码块每次都需要按下一键才能执行getch()之后的代码
也就是说 getch()之后的代码阻塞了
(为什么需要避免阻塞?因为不采取防止阻塞,那么很多游戏的用户需要不停地按下游戏键才可以继续游戏,所以游戏中需要采用阻塞式键盘监听:用户输入数据后可以执行下面的程序,不输入数据后也可以进行程序)
在window系统中,conio.h头文件中kbhit()也可以实现键盘监听

conio.h 是 Windows 下特有的头文件,所以 kbhit() 也只适用于 Windows,不适用于 Linux 和 Mac
OS。

用户每按下一个键,都会将对应的字符放到输入缓冲区中,kbhit() 函数会检测缓冲区中是否有数据,如果有的话就返回非 0 值,没有的话就返回 0 值。但是 kbhit() 不会读取数据,数据仍然留在缓冲区,所以一般情况下我们还要结合输入函数将缓冲区种的数据读出。请看下面的例子:

#include <stdio.h>
#include <windows.h>
#include <conio.h>
int main(){char ch;int i = 0;//循环监听,直到按Esc键退出while(1){if(kbhit()){  //检测缓冲区中是否有数据ch = getch();  //将缓冲区中的数据以字符的形式读出if(ch == 27){break;}}printf("Number: %dn", ++i);Sleep(1000);  //暂停1秒}return 0;
}

运行的结果就是要停留一秒仍然键盘没有指示也输出printf里面的内容
每次循环,kbhit() 会检测用户是否按下某个键(也就是检测缓冲区中是否有数据),没有的话继续执行后面的语句,有的话就通过 getch() 读取,并判断是否是 Esc,是的话就退出循环,否则继续循环。

3.获取随机数

由于雷区的炸弹是随机的,所以需要应用到这个算法。
学习资料(随机数选取)
常用的函数是rand() 函数
最简单的随机数代码:

#include <stdio.h>
#include <stdlib.h>
int main(){int a=rand();printf("%dn",a);return 0;
}

但是其实rand()函数输出的是“伪随机数”运行多次后输出的值几乎都发生重复,存在大概率数字(原因是这个函数通过一个公式进行运行,将输出的数叫做“种子”)所以我们需要一个播种函数:srand(),
另一方面,我们可以进行设定随机数范围:

int a=rand()%10;    //产生0~9的随机数,注意10会被整除
int a=rand()%51+13;    //产生13~63的随机数

优化程序后:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){int a;srand((unsigned)time(NULL));//是明确随机占用时间a=rand()%51+13;printf("%dn",a);return 0;

在扫雷代码中,我们用到的随机数部分
(mine数组是指扫雷区域)

void set_mine(int mine[ROW][COL])
{int x = 0;int y = 0;int count = DEFAULT;//用随机数想mine数组中设置数量为 count 的雷区,mine数组中,雷区用 -1 表示while (count){x = rand() % (ROW - 2) + 1;y = rand() % (COL - 2) + 1;if (mine[x][y] == 0){mine[x][y] = -1;count--;}}
}

一些小代码知识点

1.在主函数中,我们需要对屏幕进行清屏,所以会使用system(“cls”):用于清屏,但是需要一个函数头文件#include<stdlib.h>(拓展:system(“pause”);是暂停的意思 ,将程序暂停,直到用户按下下一个键,如果使用打开生成的exe文件,运行界面闪一下,用这个语句,就不会闪退了,类似于getchar();)

扫雷的具体程序实现

1.判断用户是否开始游戏。
2.判断用户输入的坐标是否有雷
3.如果是雷区那么将show数组里的“*”改为雷的“o”。
4.采用minedow数组中储存的数据一并更新到show数组中
5.将show数组呈现给用户、、。


```c
#include<stdio.h>
#include<time.h>
#include<windows.h>
#define ROW 11
#define COL 11
#define DEFAULT 10//设定雷区数量
//扫雷初始化,mine数组负责记录数据,show数组负责显示讲数据显示给用户
void init_board(int mine[ROW][COL], char show[ROW][COL]);
//显示扫雷结果,即将show数组中的数据显示给用户,显示过程中调用了windows API,对显示界面做了优化
void display_board(char show[ROW][COL]);
//设置雷区,没有雷的区域用数字 0 表示,有雷区域用数字 -1 表示
void set_mine(int mine[ROW][COL]);
//在扫雷游戏中,当用户点击的某个区域不是雷区时,游戏应将与此位置相邻的所有不是雷区的区域显示给用户,即实现“一点显示一片”的功能,
void mine_deal(int mine[ROW][COL], int mineDow[ROW][COL]);
//统计该位置周围雷的个数
int get_mine(int mine[ROW][COL], int x, int y);
//扫雷过程实现函数
void mine_sweep(int mine[ROW][COL], int mineDow[ROW][COL], char show[ROW][COL]);
//扫雷游戏开始入口函数
void game();
//采用递归思想,更新显示数组 show 中的数据
void show_deal(char show[ROW][COL], int mine[ROW][COL], int x, int y);
//调用windows API 给字符赋予不同颜色
void color(int m);
int main()
{srand((unsigned)time(NULL));//给随机数设置种子color(0xE);//给以下字符赋予淡黄色printf("是否开始游戏:(Y/N)n");while (1){char define;//根据用户输入的字符,设定游戏是否开始if ((define = getch()) == 'y' || (define = getch()) == 'Y') {system("cls");//清空命令行中显示的数据game();//游戏开始}else {break;}color(0xE);printf("是否重新开始游戏:(Y/N)n");}return 0;
}
void init_board(int mine[ROW][COL], char show[ROW][COL])
{int i;int j;//初始状态下,mine数组中全部设置为不是雷区for (i = 0; i < ROW - 1; i++){for (j = 0; j < COL - 1; j++){mine[i][j] = 0;}}//初始状态下,用户没有点击任何一个区域,所以,show数组中全部设为 * ,表示用户没有点击的区域for (i = 0; i < ROW - 1; i++){for (j = 0; j < COL - 1; j++){show[i][j] = '*';}}
}
void display_board(char show[ROW][COL])
{//在显示给用户时,为了方便用户游戏,扫雷区域外需增设一个坐标系int i, j;printf("  ");color(2);//横坐标系设为淡绿色for (i = 1; i < COL - 1; i++) {printf(" %d", i);//由于扫雷游戏,显示给用户所使用的所有字符都是特殊字符,每个特殊字符占用两个普通字符的位置}printf("n");for (i = 1; i < ROW - 1; i++){//每行的纵坐标系也设置为淡绿色color(2);printf("%d ", i);//根据 show 数组中存储的字符的不同,分别用不同的有意义的特殊字符代替for (j = 1; j < COL - 1; j++){if (show[i][j] == '*') {color(8);printf("■");}if (show[i][j] == '0') {color(7);printf("■");}if (show[i][j] == '1') {color(0xA);printf("1");}if (show[i][j] == '2') {color(1);printf("2");}if (show[i][j] == '3') {color(3);printf("3");}if (show[i][j] == '4') {color(3);printf("4");}if (show[i][j] == '5') {color(3);printf("5");}if (show[i][j] == '6') {color(3);printf("6");}if (show[i][j] == '7') {color(3);printf("7");}if (show[i][j] == '8') {color(3);printf("8");}if (show[i][j] == 'o') {color(6);printf("●");}}printf("n");}
}
int get_mine(int mine[ROW][COL], int x, int y)
{//计算横坐标为 x,纵坐标为 y的位置,周围的8个区域,雷的数量int count = 0;if (mine[x - 1][y - 1] == -1)count++;if (mine[x - 1][y] == -1)count++;if (mine[x - 1][y + 1] == -1)count++;if (mine[x][y - 1] == -1)count++;if (mine[x][y + 1] == -1)count++;if (mine[x + 1][y - 1] == -1)count++;if (mine[x + 1][y] == -1)count++;if (mine[x + 1][y + 1] == -1)count++;return count;
}
//初始化 mineDow数组,用于实现扫雷游戏中"点击一下出现一片安全区域"的功能。mineDow数组中存储的是各个位置周围雷区的个数
void mine_deal(int mine[ROW][COL], int mineDow[ROW][COL]) {int i;int j;for (i = 1; i<ROW - 1; i++) {for (j = 1; j<COL - 1; j++) {if (mine[i][j] != -1) {mineDow[i][j] = get_mine(mine, i, j);}else {mineDow[i][j] = -1;}}}}
void set_mine(int mine[ROW][COL])
{int x = 0;int y = 0;int count = DEFAULT;//用随机数想mine数组中设置数量为 count 的雷区,mine数组中,雷区用 -1 表示while (count){x = rand() % (ROW - 2) + 1;y = rand() % (COL - 2) + 1;if (mine[x][y] == 0){mine[x][y] = -1;count--;}}
}//根据mineDow数组中的数据,更新show数组。采用递归的方式,找出与(x,y)相邻的不是雷区的位置
void show_deal(char show[ROW][COL], int mine[ROW][COL], int x, int y) {//递归出口if (x == 0 || x == ROW - 1 || y == 0 || y == COL - 1) {return;}//如果show数组中的某个位置不是 *,说明该位置之前已经做过更新,无需再做一次。if (show[x][y] != '*') {return;}//更新show数组中的数据show[x][y] = mine[x][y] + '0';//扫雷游戏中,当遇到周围有雷区的位置时(位置上显示的为周围雷区的个数),即不再继续显示if (mine[x][y] != 0) {return;}show_deal(show, mine, x + 1, y);show_deal(show, mine, x - 1, y);show_deal(show, mine, x, y + 1);show_deal(show, mine, x, y - 1);
}
//判断用户是否完成游戏,采用时刻监控扫雷区域中 * 的个数,如果与设置的雷区数相等,证明用户扫雷成功
int countShow(char show[ROW][COL]) {int i, j,count=0;for (i = 1; i < ROW - 1; i++) {for (j = 1; j < COL - 1; j++) {if (show[i][j] == '*') {count++;}}}return count;
}
//实现扫雷的功能函数
void mine_sweep(int mine[ROW][COL],int mineDow[ROW][COL], char show[ROW][COL])
{int x = 0;int y = 0;int count = 0;//只要未知区域的个数比雷区的总数大,就继续while (countShow(show)> DEFAULT){printf("请输入坐标ROW(1-9)COL(1-9):");scanf("%d%d", &x, &y);//用户输入的x,y需在规定范围内,否则无效if (x >= 1 && x <= 9 && y >= 1 && y <= 9) {//输入的(x,y)每次都必须为位置区域。否则无效if (show[x][y] == '*') {//如果该位置为 -1,则是雷区,游戏结束if (mine[x][y] == -1){//雷区在show数组中用 o 表示show[x][y] = 'o';//通过重设光标所在位置进行刷新,可有效避免屏幕闪烁COORD pos = { 0, 0 };SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);display_board(show);printf("踩到雷了:");color(6);printf("●n");return;}else{//更新数组show中的数据,看是否有相邻且不是雷区的区域。若有,全部显示给用户show_deal(show, mineDow, x, y);COORD pos = { 0, 0 };SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);display_board(show);}}}}printf("扫雷成功n");
}
void game()
{int  mine[ROW][COL] = { 0 };char show[ROW][COL] = { 0 };int mineDow[ROW][COL] = { 0 };init_board(mine, show);display_board(show);set_mine(mine);//设置地雷mine_deal(mine, mineDow);mine_sweep(mine,mineDow, show);
}
void color(int m) {HANDLE consolehend;consolehend = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(consolehend, m);
}

(代码是从c语言中文网摘抄出来的,来自于[扫雷](.html))

本文发布于:2024-01-31 05:22:17,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170664974025860.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:作业   语言
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23