数字迷宫
第一部分 案例描述
案例目的
本案例为实现动态的刷新Dos界面,使用用户控制头像“消灭”窗口中出现的数字(无固定顺序)的游戏,来使学员加深对一维数组、二维数组、循环语句、选择程序设计以及相关系统函数的使用。
案例难度
★★★★
案例覆盖技能点
- 选择程序设计
- 循环程序设计
- 用户、屏幕窗口的输入输出
- 相关系统函数
- 一维、二维数组
推荐案例完成时间
4天
适用课程和对象
C语言案例(T阶段)
第二部分 需求和开发环境
使用技术和开发环境
Microsoft Visual C++ 6.0
案例需求
本案例要求制作一个《数字迷宫》的游戏,该游戏的玩法描述为:
- 系统主要地图为固定模式
- 地图内部包含墙体、走廊、阿拉伯数字(1~7)、玩家头像(1个)四种不同内容
- 用户通过上、下、左、右按键来控制玩家头像在地图范围内的走动
- 在玩家走动过程中,碰撞墙壁时,该步的走动无效,玩家头像原地不变
- 玩家允许在设计走廊内部进行走动
- 玩家头像遇到阿拉布数字时,数字消失,并且对玩家走动无影响
- 玩家头像遭遇所有数字之后(地图上无阿拉伯数字),该局游戏结束,并自动开始下一局游戏
- 在某一局游戏中,游戏走廊、墙体与其他游戏相同,但数字位置会随机产生
- 阿拉伯数字产生在走廊内而非墙体上
- 在玩家游戏过程中按下Esc键,游戏无条件退出。
- 在玩家未使用Esc键时,程序正常运行
数字迷宫工作原理
- 本程序分为初始——玩家运行——重启一局——结束四个阶段
- 初始化阶段
- 程序当中存在一18*24大小的固定地图数组
- 该数组以0/-1分别标识程序地图当中的“墙体”以及“走廊”
- 通过随机函数在走廊中产生1~7阿拉伯数字,并且将该系列数字写入二维数组的相应位置当中,对-1(走廊)进行覆盖
- 产生玩家位置:数组的(1,1)处
- 使用循环语句遍历打印出数组元素,元素包括
- 墙体(0):■
- 走廊(-1): 空格*2
- 数字(1~7):数字本身+空格*1
- 玩家头像:\1 即:J+空格*1
- 玩家运行阶段
- 玩家使用上下左右键进行头像控制
- 与墙体碰撞时,走动无效,原地不动(通过玩家头像位置标示与数组内部数据是否为墙体(0)来判断)
- 为一般走廊时,玩家原头像位置清空为双空格(通过玩家头像位置标示与数组内部数据是否为走廊(-1)来判断),玩家当前位置输出玩家头像,并更新玩家头像位置全局变量。
- 为数字时(通过玩家头像位置标示与数组内部数据是否为数字(>0)来判断),该数字消失,玩家原位置头像消失,新位置出现玩家头像,并将数组内消失数字位置置为走廊(-1), 并更新玩家头像位置全局变量。
- 每走动一次系统遍历数组元素,判断数字(>0)多少,当数字存在数量>0时,该局继续,=0时,进入重启一局步骤。
- 重启一局
- 重复初始化阶段(注意要移动头像到(1,1)位置)
- 结束程序
- 用户点击Esc或强行关闭应用程序时,程序无条件退出。
第三部分功能点介绍
头文件引用列表
头文件名
功能简述
#include <stdio.h>
使用一般输入输出函数
#include <conio.h>
使用getch函数达到输入数据不敲回车进行下步计算功能
#include <time.h>
使用time(int)函数
#include "windows.h"
使用光标移动函数对光标进行编码定位
系统函数使用列表
函数名称
功能简述
getch();
printf
srand();
设置系统rand函数随机引资
time(NULL);
以时间作为随机因子产生不重复的随机数,提高程序效率
rand()
得到随机数
GetStdHandle
得到该程序HANDLE的函数
GetLastError();
得到系统最近错误编号函数
SetConsoleCursorPosition(Handle, {x,y});
代码设置系统光标位置函数
公共变量列表
变量名称
初始值
功能简述
int code[17][24]
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,-1,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,
0,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,-1,-1,-1,0,0,
0,-1,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0,0,
0,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,0,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,
0,-1,0,0,-1,0,-1,0,0,0,0,-1,0,-1,-1,-1,0,0,0,0,0,0,0,0,
0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,0,0,0,0,0,0,0,0,
0,-1,0,0,0,0,0,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,0,
0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,0,0,-1,0,0,0,0,
0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,-1,0,0,-1,0,0,0,0,
0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,-1,-1,-1,-1,0,-1,-1,0,
0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,
0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,
0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,
0,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,
0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
地图数组,0表示墙体,-1表示走廊
int postionX, postionY
postionX=1; postionY=1;
玩家的初始位置
函数功能列表
函数名称
功能简述
void main()
程序接口函数,负责程序整体运行
void SetCode(int num);
该函数通过传入的num值来判断并输出为:■,空格*2,或者数字本身
void SetWindow();
生成地图主体函数:遍历公共数组,在位置部位(1,1)时,调用SetCode函数,并在(1,1)位置输出玩家头像
void SetNum();
程序初始化时,用于使用随机函数在数组“走廊”位置生成1~7的阿拉伯数字
void Begin();
初始化主体函数,设置玩家头像初始位置,调用SetNum函数
void LeftKey();
void UpKey();
void DownKey()
void RightKey();
玩家按下,上下左右按键时,分别调用的函数,该函数可判断玩家是否为被墙体阻挡、正常行走、“吃”掉数字三种状态,并改变玩家头像的位置。
int CheckLeftNum();
该函数判断数组内剩余的数字(>0)数量,返回该数量
void GoToXY(int x, int y);
该函数用于在x,y位置输出用户头像
void GoToXYSpace(int x, int y);
该函数用于在x,y处输出空格*2,用于用户走动时,消除之前位置处头像。
第四部分 考核评价点(系统验收标准)
序号
功能列表
功能描述
分数
说明
难度
1
正确创建系统原始地图
30
必做
★★
2
正确完成用户移动监测
50
必做
★★★★
3
正确完成数字剩余检测
10
必做
★★
4
正确完成系统重新开始
10
必做
★
7
系统退出
必做
代码如下:
#include<stdio.h>//使用输入输出函数
#include<stdlib.h> //动态分配函数
#include<string.h>
#include<time.h>//使用time(int)函数
#include<conio.h>//使用getch函数达到输入数据不敲进行下步计算功能
#include<Windows.h>//使用光标移动函数对光标进行编码定位
#define MAX_LINE 1024//定义文件所能存的最大长度的字符
void SetWindow(); //生成地图的主题函数,并在地图上打印笑脸
void SetCode(int num);//该函数通过传入的num值来判断并输出■,空格*2或者数字本身
void SetNum() ; //程序初始化时,用于使用随机函数在数组走廊位置生成1-7的阿拉伯数字
/**玩家按上下左右按键时,分别调用的函数,该函数可以判断玩家是否被墙体所
阻挡、正常行走、吃掉数字三种状态,并改变玩家的头像的位置**/
void LeftKey(int x, int y ) ; //左
void UpKey(int x, int y ) ; //上
void DownKey(int x, int y ) ; //下
void RightKey(int x, int y ) ; //右
void CheckLeftNum(int x, int y) ; //该函数用于判断剩余数字(>0)数量,返回该数量
void GoToXY(int x, int y ) ; //该函数用于在x,y位置输出用户头像
void GoToXYSpace(int x, int y) ;//该函数用于在x,y处输出空格*2,用于用户走动时,消除之前位置的头像
void Hidden() ; //隐藏光标
void Choose() ; //选择界面
void BeginGame() ; //游戏开始函数
void Wait() ; //等待界面
void Help() ; //游洗帮助函数
void Close() ; //关闭窗口程序
void RecodeTime(int x, int y) ; //游戏记时程序
void Main() ; //初始界面的选择程序
void Gaming() ; //游戏进入界面
void Setting() ; //游戏设置界面
void Color() ; //用于游戏界面选择颜色
//用来记录初始位置
int code[17][24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,-1,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,
0,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,-1,-1,-1,0,0,
0,-1,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0,0,
0,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,0,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,
0,-1,0,0,-1,0,-1,0,0,0,0,-1,0,-1,-1,-1,0,0,0,0,0,0,0,0,
0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,0,0,0,0,0,0,0,0,
0,-1,0,0,0,0,0,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,0,
0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,0,0,-1,0,0,0,0,
0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,-1,0,0,-1,0,0,0,0,
0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,-1,-1,-1,-1,0,-1,-1,0,
0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,
0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,0,0,
0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,
0,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,
0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
int start , end ; //记录开始的时间和结束的时间
int main()
{
Hidden() ;
Gaming() ;
Choose() ;
Main() ;
return 0 ;
}
void SetCode(int num )
{
if(num == -1)
printf(" ") ;
else if(num==0) printf("■");
}
void SetWindow()
{
int i , j ;
for(i = 0 ; i < 17 ; i++)
{
for(j = 0 ; j < 24 ; j++)
if(code[i][j] == 9)
printf("* ") ;
else
SetCode(code[i][j]) ; //创建一个有墙的实体的地图。
printf("\n") ;
}
SetNum() ;
}
void SetNum()
{
int num =1 ;
srand((unsigned)time(NULL)) ;//利用系统时钟,产生不同的随机种子。
while(num<=7)
{
/***********************
获取指定范围的随机数
int :
[0,x):rand()%x ;
[0,x]:rand()%(x+1) ;
[a,b):rand()%(b-a)+a ;
(a,b]:rand()%(b-a)+a+1 ;
[a,b]:rand()%(b-a+1)+a ;
float:
[0,1):rand()/double(RAND_MAX);
************************/
int i = rand()%17;
int j = rand()%24;
if(code[i][j]==-1&&(i!=1&&j!=1))
{
code[i][j] = num ;
num++ ;
GoToXY(2*j,i) ;
printf("%d ",code[i][j]) ;
}
}
}
void GoToXY(int x, int y )
{
COORD c= {x,y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
void RightKey(int x, int y)
{
int x1, y1 ;
x1 = x ;
y1 = y +1 ;
if(code[x1][y1]!=0)
{
code[x1][y1] = 9 ;
GoToXY(2*y1, x1) ;
printf("* ") ;
}
}
void LeftKey(int x, int y)
{
int x1, y1 ;
x1 = x ;
y1 = y -1 ;
if(code[x1][y1]!=0)
{
code[x1][y1] = 9 ;
GoToXY(2*y1, x1) ;
printf("* ") ;
}
}
void UpKey(int x, int y )
{
int x1, y1 ;
x1 = x -1 ;
y1 = y ;
if(code[x1][y1]!=0)
{
code[x1][y1] = 9 ;
GoToXY(2*y1, x1) ;
printf("* ") ;
}
}
void DownKey(int x, int y )
{
int x1, y1 ;
x1 = x +1 ;
y1 = y ;
if(code[x1][y1]!=0)
{
code[x1][y1] = 9 ;
GoToXY(2*y1, x1) ;
printf("* ") ;
}
}
void CheckLeftNum(int x , int y)
{
int i , j ;
int l = 0 ;
for(i =1 ; i < 16 ;i++)
{
for (j =1 ; j< 23 ;j++)
{
if(code[i][j]>0&&code[i][j]<8)
l++ ;
}
}
if(l == 0 ){
end = GetTickCount() ;
RecodeTime(start , end);
GoToXYSpace(x,y) ;
system("cls") ;
Choose() ;
Main() ;
}
}
void GoToXYSpace(int x, int y )
{
code[x][y] = -1 ;
GoToXY(2*y,x) ;
printf(" ") ;
}
void Hidden()
{
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(handle, &cursor);
}
void Choose()
{
printf("|||*******************************************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||**************①开始游戏*******************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||**************②游戏设置*******************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||**************③游戏帮助*******************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||**************④退出游戏*******************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||*******************************************|||\n") ;
}
void BeginGame()
{
code[1][1] = 9 ;
SetWindow() ;//构建窗口
Hidden() ; //隐藏光标
int i , j ;
int x, y ;
char key ;
while(1)
{
start = GetTickCount() ;
for( i = 0 ; i < 17 ; i++)
{
for( j = 0 ;j < 24 ; j++)
{
//找到笑脸的位置然后进行移动
if(code[i][j] == 9)
{
x = i ;
y = j ;
key = getch() ;//获取键盘信息
if(key == 27 )//按Esc键退出程序
{
GoToXY(0,24) ;
Close() ;
}
key = getch() ;//接受方向键
switch(key)
{
//上
case 'w':
case 'W':
case 72:
if(code[x-1][y]!=0)
{
UpKey(x,y) ;
GoToXYSpace(x,y) ;
CheckLeftNum(x-1,y) ;
}
break ;
case 75:
case 'a':
case 'A':
//左
if(code[x][y-1]!=0)
{
LeftKey(x, y) ;
GoToXYSpace(x,y) ;
CheckLeftNum(x,y-1) ;
}
break ;
case 77:
case 'd':
case 'D':
//右
if(code[x][y+1]!=0)
{
RightKey(x,y) ;
GoToXYSpace(x,y) ;
CheckLeftNum(x,y+1) ;
}
break ;
case 80:
case 's':
case 'S':
//下
if(code[x+1][y]!=0)
{
DownKey(x,y) ;
GoToXYSpace(x,y) ;
CheckLeftNum(x+1,y) ;
}
break ;
default :break;
}
}
}
}
}
}
void Wait()
{
int i ;
for( i = 0 ; i<=24 ; i++)
{
printf("■") ;
Sleep(50) ;
}
printf("\n 加载中...................\n") ;
Sleep(3000) ;
}
void Help()
{
char ch ;
printf("1.用户通过上、下、左、右(W、S、A、D)(w、s、a、d)按键来控制玩家头像在地图范围内的走动。\n") ;
printf("2.在玩家走动过程中,碰撞墙壁时,该步的走动无效,玩家头像原地不变。\n") ;
printf("3.玩家允许在设计走廊内部进行走动。\n") ;
printf("4.玩家头像遭遇所有数字之后(地图上无阿拉伯数字),该局游戏结束\n") ;
printf("\n\n") ;
printf("|||*******************|||\n") ;
printf("|||返回主界面,请按Esc|||\n") ;
printf("|||*******************|||\n") ;
ch = getch() ;
if(27 == ch){
Wait() ;
system("cls") ;
Choose() ;
Main() ;
}
}
void Close()
{
printf("|||*********************************************************|||\n") ;
printf("|||*****************退 出 中 请 等 待******************|||\n") ;
printf("|||*********************************************************|||\n") ;
Sleep(3000) ; //暂停3秒,然后在继续进行程序
system("cls") ;//刷新控制台界面
printf("||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n") ;
printf("||| |||\n") ;
printf("||| 按下Esc键,关闭窗口 |||\n") ;
printf("||| |||\n") ;
printf("||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n") ;
exit(0) ;
}
void RecodeTime(int x, int y )
{
GoToXY(0,17) ;
Sleep(1000) ;
Wait() ;
printf("Time = %d\n",y-x) ;
Sleep(3000) ;
}
void Main()
{
int a ; //一个选择按钮
printf("输入你要进行的操作:") ;
scanf("%d",&a) ;
switch(a){
case 1:
Wait() ;
system("cls") ;
BeginGame() ;
break ;
case 2:
Wait() ;
system("cls") ;
Setting() ;
Color() ;
break ;
case 3:
Wait() ;
system("cls") ;
Help() ;
break;
case 4:
Wait() ;
system("cls") ;
Close() ;
break ;
}
}
void Gaming()
{
printf("|||*******************************************|||\n") ;
printf("|||*******************************************|||\n") ;
printf("||| |||\n") ;
printf("||| |||\n") ;
printf("||| 数 字 迷 宫 |||\n") ;
printf("||| |||\n") ;
printf("||| 软 件 1801 李 长 昊 |||\n") ;
printf("||| |||\n") ;
printf("||| |||\n") ;
printf("|||*******************************************|||\n") ;
printf("|||*******************************************|||\n") ;
Sleep(3000) ;
system("cls") ;
}
void Setting()
{
printf(" 选 择 你 所 喜 欢 的 背 景 颜 色 和 字 体 颜 色\n") ;
printf(" 注:前面的颜色为背景颜色,后面的颜色为字体颜色 \n");
printf("|||***************************************************|||\n") ;
printf("|||***************************************************|||\n") ;
printf("||| 1 = 绿黑 8 = 红黑 |||\n") ;
printf("||| 2 = 黑白 9 = 淡红淡黄 |||\n");
printf("||| 3 = 绿黄 10 = 湖蓝白 |||\n");
printf("||| 4 = 紫黄 11 = 黄蓝 |||\n");
printf("||| 5 = 白黑 12 = 黑绿 |||\n");
printf("||| 6 = 紫灰 13 = 黑淡蓝 |||\n");
printf("||| 7 = 红白 14 = 红淡绿 |||\n");
printf("|||***************************************************|||\n") ;
printf("|||***************************************************|||\n") ;
}
void Color()
{
int a ;
printf("请输入选择颜色的编号:") ;
scanf("%d",&a) ;
switch(a)
{
//绿黑
case 1:
system("color 20") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//黑白
case 2:
system("color 07") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//绿黄
case 3:
system("color 26") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//紫黄
case 4:
system("color 56") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//白黑
case 5:
system("color 70") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//紫灰
case 6:
system("color 58") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//红白
case 7:
system("color 47") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//红黑
case 8:
system("color 40") ;
system("cls") ;
Choose() ;
Main() ;
break ;
//淡红淡黄
case 9 :
system("color CE") ;
system("cls") ;
Choose() ;
Main() ;
break;
//湖蓝白
case 10 :
system("color 37") ;
system("cls") ;
Choose() ;
Main() ;
break;
//黄蓝
case 11 :
system("color 61") ;
system("cls") ;
Choose() ;
Main() ;
break;
//黑绿
case 12 :
system("color 02") ;
system("cls") ;
Choose() ;
Main() ;
break;
//黑淡蓝
case 13 :
system("color 09") ;
system("cls") ;
Choose() ;
Main() ;
break;
//红淡绿
case 14 :
system("color 4A") ;
system("cls") ;
Choose() ;
Main() ;
break;
}
}