贪吃蛇项目
核心算法:循环数组,发牌算法,二维坐标一维化
编译环境:TC 2.0
准备工作:学习gotoxy()函数,了解bioskey()函数使用,知道bioskey(1)与bioskey(0)的区别,了解键盘扫描码,并且知道如何使用。
核心工作:1.了解循环数组的下标循环规律
2.理解发牌算法的核心代码
3.掌握如何对二维坐标进行一维化的处理,以及二者之间的转换
那么,首先我们先来了解一下gotoxy()这个函数:
gotoxy (int x, int y)是 Borland C 扩充函数库 conio.h 中声明的一个函数,功能是将光标移动到指定位置。 在当代的 Visual C++ 或 GCC 中可以自定义这个函数。 在上世纪80-90年代流行的集成开发环境 Turbo C 或 Borland C 中的扩充函数库 conio.h 提供了 gotoxy 函数,用于屏幕输出,功能是将 光标 移动到屏幕指定位置。 在屏幕的左上角被定义为光标的坐标原点 (0, 0),横向为 X 轴,纵向为 Y 轴。
因为我们是Turbo C的环境,所以在使用时应该写上#include <conio.h>这个头文件。
接下来我们再来看bioskey()这个函数:
函数原型:int bioskey (int cmd)
说明:bioskey()的函数原型在bios.h中
bioskey()完成直接键盘操作,cmd的值决定执行什么操作。
cmd = 0:
当cmd是0,bioskey()返回下一个在键盘键入的值(它将等待到按下一个键)。它返回一个16位的二进制数,包括两个不同的值。当按下一个普通键时,它的低8位数存放该字符的ASCII码,高8位存放该键的扫描码;对于特殊键(如方向键、F1~F12等等),低8位为0,高8位字节存放该键的扫描码。
cmd = 1:
当cmd是1,bioskey()查询是否按下一个键,若按下一个键则返回非零值,否则返回0。
重要的一点是bioskey()函数检测后该键的键值被留在键盘缓冲区中,需要的话可以将它从键盘缓冲区中取出。
做完准备工作后,我们开始进行第一个核心算法—发牌算法
例如:
int arr[10] = {1,5,9,3,7,2,8,4,0,6};
从这10个数中挑选出六个完全随机且绝对不重复的数。
n个元素,随机生成0到n-1的下标,将被选出的元素调整(交换)的末尾,使得未挑选元素的下标,在0到n-2之间,下一轮随机生成生成0到n-2的下标,如此往复。
代码示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap(int *p, int *q);
void swap(int *p, int *q) {
int temp;
temp = *p;
*p = *q;
*q = temp;
}
int main() {
int arr[10] = {3,8,1,2,0,9,6,5,7,4};
int i;
int index;
int n = 10;
srand((unsigned) time(NULL));
for(i = 0; i < 6; i++) {
index = rand()%n;
printf("%d\t",arr[index]);
swap(&arr[index],&arr[n--]);
}
}
接下来的核心算法就是循环数组,目的是实现蛇的移动,使用数组而不使用链表的原因是因为没有必要,不划算,数组的操作相较于链表更加简单也更加方便。
而循环数组相较于普通数组,在蛇进行移动时更加方便,时间复杂度也会降低。
如何使得下标循环起来呢?这里有一个公式:
headIndex(蛇头坐标) = (index + 数组的长度 + 1)%数组的长度
tailIndex(蛇尾坐标) = (index + 数组的长度 - 蛇的长度 + 1)%数组的长度
移动蛇
使用循环数组来存储蛇身体每个点的行,列坐标
初始显示一个蛇头,慢慢增多,直到等于设定的蛇的长度
蛇移动的过程:
1.if(当前长度 < 蛇本身长度) {
当前长度++;
} else {
消尾;
}
2.改颈:在原来蛇头的地方画上蛇的身体
3.画头
二维坐标一维化:
i,j
1,1 1,2 1,3 1,4 2*4的二维数组 4:COL_COUNT
0 1 2 3
2,1 2,2 2,3 2,4
4 5 6 7
index(下标) = (i-1) *COL_COUNT+(j-1)
i = t / COL_COUNT + 1
j = t % COL_COUNT + 1
部分源码如下:
#include <stdio.h>
#include <bios.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#include "keyValue.h"
#include "snakeValue.h"
const int delta[][2] = {
{0, -1},
{0, 1},
{-1, 0},
{1, 0},
};
void keyOperate(ARG *arg);
boolean moveSnake(ARG *arg, SIT *sit, int *map);
void printHead(ARG *arg);
void produceFood(ARG *arg, SIT *sit, int *map);
void swap(int *p, int *q);
void printMap(int *map);
void printMap(int *map) {
int i;
int x;
int y;
int j;
for(i = 0; i < 2000; i++) {
x = i % COL_COUNT + 1;
y = i / COL_COUNT + 1;
if((x == 26 || x == 55) && ((y >= 4 && y <= 8)||(y >= 18 && y <=22))) {
map[i] = 4;
for (j = 0; j < 6; j++) {
gotoxy(x,y);
printf("%c",254);
}
}
if((y == 8 || y == 18) && ((x >= 6 && x <= 26) || (x >= 55 && x <= 74))) {
map[i] = 4;
for(j = 0 ; j < 20; j++) {
gotoxy(x,y);
printf("%c",254);
}
}
if(map[i] == 3) {
gotoxy(x,y);
printf("%c",254);
}
}
}
void swap(int *p, int *q) {
int temp;
temp = *p;
*p = *q;
*q = temp;
}
void produceFood(ARG *arg, SIT *sit, int *map) {
int foodMap[2000] = {0};
int i;
int x;
int y;
int index = 0;
int q;
srand((unsigned) time(NULL));
for (i = 0, q = 0; i < 2000; i++) {
if (map[i] == 0) {
foodMap[q] = i;
q++;
}
}
q++;
for (i = 0; i < 10; i++) {
index = rand()%q;
map[foodMap[index]] = 2;
x = foodMap[index] % COL_COUNT + 1;
y = foodMap[index] / COL_COUNT + 1;
gotoxy(x,y);
printf("%c",157);
swap(&foodMap[index],&foodMap[--q]);
}
}
void printHead(ARG *arg) {
if (arg->direct == LEFT ) {
printf("<");
}
if (arg->direct == RIGHT ) {
printf(">");
}
if (arg->direct == UP ) {
printf("^");
}
if (arg->direct == DOWN ) {
printf("v");
}
}
boolean moveSnake(ARG *arg,SIT *sit,int *map) {
int tailIndex;
int x;
int y;
int index;
tailIndex = (arg->headIndex + MAXLEN - arg->length + 1) % MAXLEN;
if(arg->curLength < arg->length) {
arg->curLength++;
} else {
gotoxy(sit[tailIndex].row,sit[tailIndex].col);
printf(" ");
index = (sit[tailIndex].row - 1) * COL_COUNT + (sit[tailIndex].col - 1);
map[index] = 0;
}
index = (sit[arg->headIndex].col - 1) * COL_COUNT + (sit[arg->headIndex].row - 1);
gotoxy(sit[arg->headIndex].row,sit[arg->headIndex].col);
printf("%c",233);
map[index] = 5;
x = sit[arg->headIndex].row;
y = sit[arg->headIndex].col;
arg->headIndex = (arg->headIndex + MAXLEN + 1) % MAXLEN;
sit[arg->headIndex].row = x + delta[arg->direct][0];
sit[arg->headIndex].col = y + delta[arg->direct][1];
index = (sit[arg->headIndex].col - 1) * COL_COUNT + (sit[arg->headIndex].row - 1);
if(map[index] == 2) {
arg->eatCount++;
arg->length++;
}
if(map[index] == 3 || map[index] == 4 || map[index] == 5) {
return FALSE;
}
map[index] = 1;
gotoxy(sit[arg->headIndex].row,sit[arg->headIndex].col);
printHead(arg);
return TRUE;
}
void keyOperate(ARG *arg) {
if (arg->key == KEY_UP) {
arg->direct = UP;
} else if (arg->key == KEY_DOWN) {
arg->direct = DOWN;
} else if (arg->key == KEY_LEFT) {
arg->direct = LEFT;
} else if (arg->key == KEY_RIGHT) {
arg->direct = RIGHT;
} else if (arg->key == KEY_ESC) {
arg->finished = TRUE;
} else if (arg->key == KEY_ADD) {
if(arg->delayTime > 1000) {
arg->judgeSpeed = -1000;
}
}else if (arg->key == KEY_SUB) {
if(arg->delayTime < 15000) {
arg->judgeSpeed = 1000;
}
} else if(arg->key == KEY_SPACE) {
arg->gameOut = !arg->gameOut;
}
}
需要源码的可以在下面留言,如果觉得代码还有什么可以改进的,也可以在下面进行交流。