数字迷宫
第一部分 案例描述
案例目的
本案例为实现动态的刷新Dos界面,使用用户控制头像“消灭”窗口中出现的数字(无固定顺序)的游戏,来使学员加深对一维数组、二维数组、循环语句、选择程序设计以及相关系统函数的使用。
案例难度
★★★★
案例覆盖技能点
a) 选择程序设计
b) 循环程序设计
c) 用户、屏幕窗口的输入输出
d) 相关系统函数
e) 一维、二维数组
推荐案例完成时间
4天
适用课程和对象
C语言案例(T阶段)
第二部分需求和开发环境
使用技术和开发环境
Microsoft Visual C++ 6.0
案例需求
本案例要求制作一个《数字迷宫》的游戏,该游戏的玩法描述为:
1、 系统主要地图为固定模式
2、 地图内部包含墙体、走廊、阿拉伯数字(1~7)、玩家头像(1个)四种不同内容
3、 用户通过上、下、左、右按键来控制玩家头像在地图范围内的走动
4、 在玩家走动过程中,碰撞墙壁时,该步的走动无效,玩家头像原地不变
5、 玩家允许在设计走廊内部进行走动
6、 玩家头像遇到阿拉布数字时,数字消失,并且对玩家走动无影响
7、 玩家头像遭遇所有数字之后(地图上无阿拉伯数字),该局游戏结束,并自动开始下一局游戏
8、 在某一局游戏中,游戏走廊、墙体与其他游戏相同,但数字位置会随机产生
9、 阿拉伯数字产生在走廊内而非墙体上
10、 在玩家游戏过程中按下Esc键,游戏无条件退出。
11、 在玩家未使用Esc键时,程序正常运行
数字迷宫工作原理
1. 本程序分为初始——玩家运行——重启一局——结束四个阶段
a) 初始化阶段
i. 程序当中存在一18*24大小的固定地图数组
ii. 该数组以0/-1分别标识程序地图当中的“墙体”以及“走廊”
iii. 通过随机函数在走廊中产生1~7阿拉伯数字,并且将该系列数字写入二维数组的相应位置当中,对-1(走廊)进行覆盖
iv. 产生玩家位置:数组的(1,1)处
v. 使用循环语句遍历打印出数组元素,元素包括
1. 墙体(0):■
2. 走廊(-1): 空格*2
3. 数字(1~7):数字本身+空格*1
4. 玩家头像:\1 即:J+空格*1
b) 玩家运行阶段
i. 玩家使用上下左右键进行头像控制
ii. 与墙体碰撞时,走动无效,原地不动(通过玩家头像位置标示与数组内部数据是否为墙体(0)来判断)
iii. 为一般走廊时,玩家原头像位置清空为双空格(通过玩家头像位置标示与数组内部数据是否为走廊(-1)来判断),玩家当前位置输出玩家头像,并更新玩家头像位置全局变量。
iv. 为数字时(通过玩家头像位置标示与数组内部数据是否为数字(>0)来判断),该数字消失,玩家原位置头像消失,新位置出现玩家头像,并将数组内消失数字位置置为走廊(-1), 并更新玩家头像位置全局变量。
v. 每走动一次系统遍历数组元素,判断数字(>0)多少,当数字存在数量>0时,该局继续,=0时,进入重启一局步骤。
c) 重启一局
i. 重复初始化阶段(注意要移动头像到(1,1)位置)
d) 结束程序
i. 用户点击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,用于用户走动时,消除之前位置处头像。 |
/*
**作者:张迪
**版本:V1.3.1
**日期:2016.7.11
**功能:数字迷宫
** 实现鼠标选择选项,ESC退出系统、通过随机函数产生随机数等
*/
#include <stdio.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#include <conio.h>
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 ii=1,p,q;//ii随机数,p行q列
int ss,ff=1,cc=1;
char ch;
int f;
void HideCursor()
{
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void Set();
void help();
void input()
{
HWND hwnd=FindWindow("ConsoleWindowClass",NULL);/* 控制台窗口句柄 */
POINT pos;
while(1)
{
GetCursorPos(&pos);
ScreenToClient(hwnd, &pos);
int Y=pos.y;
int X=pos.x;
//printf("%6ld",GetAsyncKeyState (VK_LBUTTON));
if (GetAsyncKeyState (VK_LBUTTON)) /* 鼠标左键单击 */
{
Sleep(100);
if(Y>=95&&Y<=111&&X>=272&&X<=303)//开始
{ss=1;break;}
if(Y>=127&&Y<=143&&X>=272&&X<=303)//帮助
{help();break;}
if(Y>=159&&Y<=175&&X>=272&&X<=303)//设置
{Set();break;}
if(Y>=191&&Y<=207&&X>=272&&X<=303)//退出
{ss=0;break;}
Sleep(100);
}
}
}
void SetNum()//程序初始化时,用于使用随机函数在数组“走廊”位置生成1~7的阿拉伯数字
{
int i,j;
for(; ii<=7;)
{
i=rand()%17;
j=rand()%24;
if((code[i][j]==-1)&&(i!=1)&&(j!=1))
code[i][j]=ii++;
else SetNum();
}
}
void gotoxy(int x,int y) //移动坐标
{
COORD coord;
coord.X=x;
coord.Y=y;
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );
}
void banquan()
{
gotoxy(20,19);
printf("侵权必究,最终解释权归迪哥所有!!");
}
int Key(char ch)//获取方向
{
if (ch == -32)
{
ch = getch();
if (ch == 72) return 0;//printf("上\n");
if (ch == 80) return 1;//printf("下\n");
if (ch == 75) return 2;//printf("左\n");
if (ch == 77) return 3;//printf("右\n");
}
return -1;
}
void SetCode(int num)//该函数通过传入的num值来判断并输出为:■,空格*2,或者数字本身
{
if(num==0) printf("■");
else if(num==-1)
printf(" ");
else if(num>=1&&num<=7) printf("%d ",num);
}
void Begin()//初始化主体函数,设置玩家头像初始位置,调用SetNum函数
{
SetNum();
int i,j;
for(i=0; i<17; i++)
{
gotoxy(12,i);
for(j=0; j<24; j++)
SetCode(code[i][j]);
// printf("\n");
}
gotoxy(14, 1);
printf("%c ",1);
gotoxy(5, 3);
printf("*数*");
gotoxy(5, 6);
printf("*字*");
gotoxy(5, 11);
printf("*谜*");
gotoxy(5, 14);
printf("*宫*");
gotoxy(25, 18);
printf("按ESC键可退出游戏!");
}
int CheckLeftNum()//该函数判断数组内剩余的数字(>0)数量,返回该数量
{
int f=0;
for(int i=0; i<17; i++)
for(int j=0; j<24; j++)
if(code[i][j]>0)
f++;
return f;
}
void Switch(int f)
{
switch (f)
{
case 0:
q>0&&((code[q-1][p]==-1)||(code[q-1][p]>=1&&code[q-1][p]<=7))?q--:q;
if(cc&&code[q][p]>=1&&code[q][p]<=7) puts("\n\a");code[q][p]=-1;
break;//上
case 1:
q<16&&((code[q+1][p]==-1)||(code[q+1][p]>=1&&code[q+1][p]<=7))?q++:q;
if(cc&&code[q][p]>=1&&code[q][p]<=7) puts("\n\a");code[q][p]=-1;
break;//下
case 2:
p>0&&((code[q][p-1]==-1)||(code[q][p-1]>=1&&code[q][p-1]<=7))?p--:p;
if(cc&&code[q][p]>=1&&code[q][p]<=7) puts("\n\a");code[q][p]=-1;
break;//左
case 3:
p<23&&((code[q][p+1]==-1)||(code[q][p+1]>=1&&code[q][p+1]<=7))?p++:p;
if(cc&&code[q][p]>=1&&code[q][p]<=7) puts("\n\a");code[q][p]=-1;
break;//右
}
}
void help();
void show();
void Set()
{
int i;
system("cls");
for(i=0; i<24; i++)
{
Sleep(4);
gotoxy(12+i*2,0);
printf("■");
}
for(i=1; i<16; i++)
{
Sleep(4);
gotoxy(58,i);
printf("■");
}
for(i=23; i>0; i--)
{
Sleep(4);
gotoxy(i*2+12,16);
printf("■");
}
for(i=16; i>0; i--)
{
Sleep(4);
gotoxy(12,i);
printf("■");
}
gotoxy(30,3);
printf("游 戏 设 置:");
gotoxy(30,6);
printf("扣0关闭声音");
gotoxy(26,8);
printf(" 扣任意键开启声音");/*
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hOut,
FOREGROUND_BLUE |
FOREGROUND_INTENSITY|
BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE |
BACKGROUND_INTENSITY);
gotoxy(34,11);
printf("# #");
SetConsoleTextAttribute(hOut,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY);*/
gotoxy(35,11);
cc=getch()-48;
if(cc==-21)
{
ss=0;
}
else
{
ss=1;
gotoxy(28,14);
system("pause");
}
}
void show()
{
int i;
system("cls");
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hOut,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY);
gotoxy(27,9);puts("游戏即将开始: %");
for(i=0; i<=100; i++)
{
gotoxy(40,9);
Sleep(20);
printf("%d",i);
// SetConsoleTextAttribute(hOut,
// BACKGROUND_RED |
// BACKGROUND_GREEN |
// BACKGROUND_BLUE |
// BACKGROUND_INTENSITY);
}
system("cls");
for(i=0; i<24; i++)
{
Sleep(8);
gotoxy(12+i*2,0);
printf("■");
}
for(i=1; i<16; i++)
{
Sleep(8);
gotoxy(58,i);
printf("■");
}
for(i=23; i>0; i--)
{
Sleep(8);
gotoxy(i*2+12,16);
printf("■");
}
for(i=16; i>0; i--)
{
Sleep(8);
gotoxy(12,i);
printf("■");
}
SetConsoleTextAttribute(hOut,
FOREGROUND_RED |
FOREGROUND_INTENSITY|
BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE |
BACKGROUND_INTENSITY);
gotoxy(23,3);
printf("\t数 \t字 \t迷 \t宫 ");
gotoxy(34,6);
printf("开始");
gotoxy(34,8);
printf("帮助");
gotoxy(34,10);
printf("设置");
gotoxy(34,12);
printf("退出");
SetConsoleTextAttribute(hOut,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY);
banquan();
input();
// ss = getch()-48;
// while(ss = getch())
// {
// if(ss==0)
// continue;
// else if(ss==27)
// {
// ss=0;
// break;
// }
// else if(ss==50)
// {
// ss=2;
// help();
// break;
// }
// else if(ss==49)
// {
// ss=1;
// break;
// }
// else if(ss==51)
// {
// Set();
// break;
// }
// }
}
void help()
{
int i;
system("cls");
for(i=0; i<24; i++)
{
Sleep(4);
gotoxy(12+i*2,0);
printf("■");
}
for(i=1; i<16; i++)
{
Sleep(4);
gotoxy(58,i);
printf("■");
}
for(i=23; i>0; i--)
{
Sleep(4);
gotoxy(i*2+12,16);
printf("■");
}
for(i=16; i>0; i--)
{
Sleep(4);
gotoxy(12,i);
printf("■");
}
gotoxy(15,3);
printf("游 戏 说 明:");
gotoxy(15,5);
printf("1. 通过上下左右键控制头像走动");
gotoxy(15,7);
printf("2. 将地图中七个数字吃光");
gotoxy(15,9);
printf("3. 按esc可退出游戏");
gotoxy(15,11);
printf("4. 感谢您的使用,迪哥真心为您提供优质的游戏");
gotoxy(15,13);
printf("按任意键开始游戏,退出游戏请扣ESC:");
gotoxy(40,15);
printf("designed by dige!");
ss = getch()-48;
if(ss!=-21) ss=1;
}
int main()//程序接口函数,负责程序整体运行
{
system("mode con cols=70 lines=23");
HideCursor();//隐藏光标
show();
while(ss==1)
{
p = 1, q = 1;//定义用户初始位置在(1,1)
srand((unsigned)time(NULL));//使用 time函数来获得系统时间,使用系统时间来做种子
Begin();//打印地图
while (ch = getch())//接收方向键输入方向
{
if(27==ch)//判断用户是否按下esc键
{
ff=0;//若是程序将结束循环
break;
}
gotoxy(2*p+12, q);
printf(" ");//覆盖掉上一步的笑脸轨迹
f = Key(ch);//转译方向
Switch(f);
gotoxy(2*p+12, q);//更新用户坐标
printf("%c ", 1);//输出用户位置
if(CheckLeftNum()==0)//判断数组内剩余的数字(>0)数量,数量为零的话结束循环
{
gotoxy(20,19);
printf("你真是太棒啦!");
system("pause");//按任意键继续
system("cls");
break;
}
}
if(ff==0)
{
// gotoxy(10,19);
break;
}
ii=1;
show();
}
gotoxy(23,20);//控制输出结束语句的位置
return 0;
}
//EXIT
//puts("\n\a");