贪吃蛇向右移动(原理就是删一个头节点,添加一个新节点)
#include <curses.h>
#include <stdlib.h>
struct snake{
int hang;
int lie;
struct snake *next;
};
struct snake *head;
struct snake *tail;
void initNcurse()
{
initscr();
keypad(stdscr,1);
}
int hasSnakeNode(int i,int j)
{
struct snake *p;
p = head;
while(p != NULL){
if(p->hang==i && p->lie==j){
return 1;
}
p=p->next;
}
return 0;
}
void gamepic()
{
int hang;
int lie;
move(0,0);
for(hang=0;hang<20;hang++){
if(hang == 0){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
if(hang>=0 && hang<=19){
for(lie=0;lie<=20;lie++){
if(lie==0||lie==20){
printw("|");
}else if(hasSnakeNode(hang,lie)){
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(hang == 19){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
}
printw("by shijintao");
printw("\n");
}
void addNode()//程序每调用一次这个函数就会新搞个new,开辟一个新的内存给new
{
struct snake *new;
new =(struct snake *)malloc(sizeof(struct snake));
new->hang=tail->hang;
new->lie=tail->lie+1;
tail->next = new;
tail = new;
new->next = NULL;
}
void initSnake()
{
head = (struct snake *)malloc(sizeof(struct snake));
head->hang=2;
head->lie=2;
head->next=NULL;
tail = head;
addNode();
addNode();
}
void deleteNode()
{
struct snake *p;//这个p是为了释放旧节点,避免内存泄漏
p = head;
head = head->next;
free(p);
}
void moveSnake()
{
addNode();
deleteNode();
}
int main()
{
int con;
initNcurse();
initSnake();
gamepic(); //这边都还是初始化贪吃蛇,就是游戏刚进入有个默认的小蛇
while(1){
con = getch();
if(con == KEY_RIGHT){
moveSnake();
gamepic(); //这个是刷新地图的效果,就是重新捕获地图
}
}
getch();
endwin();
return 0;
}
知识点:
这个是ncurse的特性
- move(y, x) 用于将光标移动到屏幕上的指定坐标位置
- (0, 0):表示屏幕的左上角(第一行、第一列)。
这边有个move(0,0)函数添加到了gamepic函数中,是因为这个ncurse程序输出时候光标在最尾巴,所以我们按-->方向键的时候,内容随着光标位置显示地图,就像这样
如何解决?才能像我们需要的效果
那么ncurse里面有个函数叫做move可以改变光标的位置,我们肯定是想要得到一个图的,然后我们使用move函数相当于覆盖了之前的地图,达到了我们的效果
move函数要放在gamepic函数的循环遍历前面
我们实现蛇向右走的原理其实就是按-->的时候,把头节点删掉,然后尾巴后面增加新节点。然后利用ncurse的move函数将光标重置随后生成的图覆盖之前的图,就达到了看上去的按-->键往右移动的效果
这个就是按右方向键可以获得响应到相关代码:
调用这个moveSnake()函数后其实链表已经发生了变化,但是要重新扫描一下地图才会显示,所以有 gamepic();这个函数的再次调用
while(1){
con = getch();
if(con == KEY_RIGHT){
moveSnake();
gamepic();
}
}
贪吃蛇撞墙
人想的蛇头是我们链表的尾节点,这点要分清楚
如果尾节点的hang和lie与边界的行和列重合就表示撞墙了
撞墙就是判断链表尾节点的行和列是否等于地图边界的行和列的值,如果等于了,那么就释放内存,重新初始化成刚开始head还是NULL的时候
#include <curses.h>
#include <stdlib.h>
struct snake{
int hang;
int lie;
struct snake *next;
};
struct snake *head=NULL;
struct snake *tail=NULL;
void initNcurse()
{
initscr();
keypad(stdscr,1);
}
int hasSnakeNode(int i,int j)
{
struct snake *p;
p = head;
while(p != NULL){
if(p->hang==i && p->lie==j){
return 1;
}
p=p->next;
}
return 0;
}
void gamepic()
{
int hang;
int lie;
move(0,0);
for(hang=0;hang<20;hang++){
if(hang == 0){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
if(hang>=0 && hang<=19){
for(lie=0;lie<=20;lie++){
if(lie==0||lie==20){
printw("|");
}else if(hasSnakeNode(hang,lie)){
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(hang == 19){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
}
printw("by shijintao");
printw("\n");
}
void addNode()
{
struct snake *new;
new =(struct snake *)malloc(sizeof(struct snake));
new->hang=tail->hang;
new->lie=tail->lie+1;
tail->next = new;
tail = new;
new->next = NULL;
}
void initSnake()
{
struct snake *p;
while(head != NULL){//如果这个游戏第一次运行,head是空的,不会运行这个代码
p=head;
head=head->next;
free(p);
}
head = (struct snake *)malloc(sizeof(struct snake));
head->hang=2;
head->lie=2;
head->next=NULL;
tail = head;
addNode();
addNode();
}
void deleteNode()
{
struct snake *p;
p = head;
head = head->next;
free(p);
}
void moveSnake()
{
addNode();
deleteNode();
if(tail->hang==0||tail->hang==20||tail->lie==20||tail->lie==0){
initSnake();
}
}
int main()
{
int con;
initNcurse();
initSnake();
gamepic();
while(1){
con = getch();
if(con == KEY_RIGHT){
moveSnake();
gamepic();
}
}
getch();
endwin();
return 0;
}
代码优化点:
initSnake()这段函数添加了while()这段代码,作用是用于释放链表内存的,因为游戏死亡后,贪吃蛇会重新回到初始位置上,那么我们要将旧的链表的每一项节点拿去释放掉,避免内存泄漏,当然第一次玩的时候head是空的,不会运行while这段代码,只有死后head才会不为NULL,才会运行。
void initSnake()
{
struct snake *p;
while(head != NULL){//如果这个游戏第一次运行,head是空的,不会运行这个代码
p=head;
head=head->next;
free(p);
}
head = (struct snake *)malloc(sizeof(struct snake));
head->hang=2;
head->lie=2;
head->next=NULL;
tail = head;
addNode();
addNode();
}
主要的算法在这:用于判断是否到边界
void moveSnake()
{
addNode();
deleteNode();
if(tail->hang==0||tail->hang==20||tail->lie==20||tail->lie==0){
initSnake();//如果值相等了,说明蛇撞墙死了,然后蛇复活,调用这个函数就是从新开 始,让蛇的坐标回到初始位置
}
}