贪吃蛇的代码重构

前言

一开始写的时候并没有太把结构当一回事,所以第二次修改时,就重新整理了一下程序,不过不知道有没有把程序变得优美一点,如果没有,请原谅啦,下次再努力一点。


代码

先将代码贴出来,如下所示

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>

#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define SNAKE_FOOD '$'
#define WALL_CELL '*'

enum moveDirect {
    UP='W',DOWN='S',LEFT='A',RIGHT='D'
};

struct snakePoint {
    int x;
    int y;
    struct snakePoint* next;
};

void snakeMove(int x,int y);
void putMoney(void);
void output(void);
int gameover(void);
void updateMap(void);
void updateBody(int new_x,int new_y);
int checkEat(int x,int y);
char moveAI();
void swap(int *a,int *b);
int isLegal(char ch);
void insertToSnake();

char background[12][12]= {"************",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "************"
                         };

char map[12][12];

int snakeX[5]= {1,2,3,4,5};
int snakeY[5]= {1,1,1,1,1};
int snakeLength=5;

struct snakePoint* snake;
int moneyX;
int moneyY;
int hasNotEat=1;

int main(void) {

    snake=(struct snakePoint*)malloc(sizeof(struct snakePoint));
    snake->x=snakeX[4];
    snake->y=snakeY[4];
    snake->next=NULL;
    struct snakePoint* temp_next=snake;
    for(int i=3; i>=0; --i) {
        struct snakePoint* temp=malloc(sizeof(struct snakePoint));
        temp->x=snakeX[i];
        temp->y=snakeY[i];
        temp->next=NULL;
        temp_next->next=temp;
        temp_next=temp;
    }

    srand(time(NULL));

    putMoney();
    updateMap();
    output();
    int temp_x,next_x;
    int temp_y,next_y;
    char ch;

    while(!gameover()) {
        ch=getch();
        if(!isLegal(ch)) {
            continue;
        }
        int new_x=snake->x;
        int new_y=snake->y;
        switch(ch) {
            case UP:
                new_y=snake->y-1;
                break;
            case DOWN:
                new_y=snake->y+1;
                break;
            case LEFT:
                new_x=snake->x-1;
                break;
            case RIGHT:
                new_x=snake->x+1;
                break;
        }
        if(checkEat(new_x,new_y)) {
            insertToSnake();
            hasNotEat=0;
        } else {
            updateBody(new_x,new_y);
        }
        if(!hasNotEat) {
            putMoney();
        }
        updateMap();
        output();
    }

    return 0;
}

char moveAI_BFS() {

}

void insertToSnake() {
    struct snakePoint* temp=malloc(sizeof(struct snakePoint));
    temp->x=moneyX;
    temp->y=moneyY;
    temp->next=snake;
    snake=temp;
}

int isLegal(char ch) {
    if(ch=='W'&&snake->x==snake->next->x&&snake->y==snake->next->y+1) {
        return 0;
    } else if(ch=='S'&&snake->x==snake->next->x&&snake->y==snake->next->y-1) {
        return 0;
    } else if(ch=='A'&&snake->next->x+1==snake->x&&snake->next->y==snake->y) {
        return 0;
    } else if(ch=='D'&&snake->next->x-1==snake->x&&snake->next->y==snake->y) {
        return 0;
    } else if(ch!='W'&&ch!='S'&&ch!='A'&&ch!='D'){
        return 0;
    } 
    return 1;
}

void updateBody(int new_x,int new_y) {
    struct snakePoint* temp=snake;
    while(temp!=NULL) {
        swap(&new_x,&(temp->x));
        swap(&new_y,&(temp->y));
        temp=temp->next;
    }
}

int gameover(void) {
    if(snake->x==0||snake->x==11) {
        return 1;
    } else if(snake->y==0||snake->y==11) {
        return 1;
    }
    struct snakePoint* temp=snake->next;
    while(temp!=NULL) {
        if(snake->x==temp->x&&snake->y==temp->y) {
            return 1;
        }
        temp=temp->next;
    }
    return 0;
}

void updateMap(void) {
    for(int i=0; i<12; ++i) {
        for(int j=0; j<12; ++j) {
            map[i][j]=background[i][j];
        }
    }
    struct snakePoint* temp=snake;
    map[temp->y][temp->x]=SNAKE_HEAD;
    temp=temp->next;
    while(temp!=NULL) {
        map[temp->y][temp->x]=SNAKE_BODY;
        temp=temp->next;
    }
    map[moneyY][moneyX]=SNAKE_FOOD;
}

void output(void) {
    system("cls");
    for(int i=0; i<12; ++i) {
        for(int j=0; j<12; ++j) {
            printf("%c",map[i][j]);
        }
        printf("\n");
    }
}

void putMoney(void) {
    int legal=1;
    struct snakePoint* temp=snake;
    do {
        moneyX=1+rand()%10;
        moneyY=1+rand()%10;
        while(temp!=NULL) {
            if(moneyX==temp->x&&moneyY==temp->y) {
                legal=0;
                break;
            }
            temp=temp->next;
        }
    } while(!legal);
    hasNotEat=1;
}

int checkEat(int x,int y) {
    if(x==moneyX&&y==moneyY) {
        return 1;
    }
    return 0;
}

void swap(int *a,int *b) {
    int temp=*a;
    *a=*b;
    *b=temp;
}

解释

我首先觉得贪吃蛇应该作为链表的形式存储,每当移动一格,便将链表中元素的值往后移一个单位,比如原来头的坐标就赋给头后一位的元素,最后将新的坐标赋给头,当吃了食物以后,就插入一个新的元素(坐标为食物)进入链表中。


代码结构

首先先设置一个空白的地图(即背景),使用二维数组的形式存储

char background[12][12]= {"************",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "*          *",
                          "************"
                         };

接着再声明一个地图

char map[12][12];

我的想法是,每一次用户输入时都更新一次地图,先将地图设置为背景,接着将蛇添加进去,再将食物添加进去,所以我声明了两个函数:


void updateMap(void) {
    for(int i=0; i<12; ++i) {
        for(int j=0; j<12; ++j) {
            map[i][j]=background[i][j];
        }
    }
    struct snakePoint* temp=snake;
    map[temp->y][temp->x]=SNAKE_HEAD;
    temp=temp->next;
    while(temp!=NULL) {
        map[temp->y][temp->x]=SNAKE_BODY;
        temp=temp->next;
    }
    map[moneyY][moneyX]=SNAKE_FOOD;
}

void output(void) {
    system("cls");
    for(int i=0; i<12; ++i) {
        for(int j=0; j<12; ++j) {
            printf("%c",map[i][j]);
        }
        printf("\n");
    }
}

前者用于将更新后的蛇和食物添加进去,后者将地图打印出来

接着声明一个枚举类型,分别对应上下左右

enum moveDirect {
    UP='W',DOWN='S',LEFT='A',RIGHT='D'
};

每次输入后都检查输入是否正确,当蛇头转向蛇头后一格时判为非法,当输出除了WASD以外的字符也是非法的,要求重新输入

int isLegal(char ch) {
    if(ch=='W'&&snake->x==snake->next->x&&snake->y==snake->next->y+1) {
        return 0;
    } else if(ch=='S'&&snake->x==snake->next->x&&snake->y==snake->next->y-1) {
        return 0;
    } else if(ch=='A'&&snake->next->x+1==snake->x&&snake->next->y==snake->y) {
        return 0;
    } else if(ch=='D'&&snake->next->x-1==snake->x&&snake->next->y==snake->y) {
        return 0;
    } else if(ch!='W'&&ch!='S'&&ch!='A'&&ch!='D'){
        return 0;
    } 
    return 1;
}

接着在主程序之中将每次的输入都进行判断

ch=getch();
if(!isLegal(ch)) {
    continue;
}
int new_x=snake->x;
int new_y=snake->y;     
switch(ch) {
    case UP:
        new_y=snake->y-1;
        break;
    case DOWN:
        new_y=snake->y+1;
        break;
    case LEFT:
        new_x=snake->x-1;
        break;
    case RIGHT:
        new_x=snake->x+1;
        break;
}
if(checkEat(new_x,new_y)) {
    insertToSnake();
    hasNotEat=0;
} else {
    updateBody(new_x,new_y);
}
if(!hasNotEat) {
    putMoney();
}
updateMap();
output();

感想

感觉程序这样划分清晰明了很多了啦,不过不知道这样写好不好啦。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值