有趣的笔试题——贪吃蛇游戏(确定不进来看看?)

原题

有趣的笔试题——贪吃蛇游戏(确定不进来看看?)_第1张图片

贪吃蛇游戏是一款耳熟能详的小游戏,通过上下左右控制蛇的方向,寻找吃的果子,每吃一口果子,蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,吃完所有果子,就能过关,然后继续玩下一关。(30分)

该游戏的核心是通过链表中的节点位置(假设节点中的x,y来表示节点所在的位置信息)和节点个数来描述蛇的长度和身体位置信息,移动方向即控制链表节点的位置信息。假设节点之间采用双向链表的形式进行连接。

int SnakeMove(Food_S *pFood, SLIST_S *pHeadSnake, SLIST_S *pTailSnake);
函数说明:
参数pFood:作为入参表示蛇下一个移动的位置,当成员IsHaveFood为FLASE时表示仅仅只是移动位置,当IsHaveFood为TRUE时,表示吃到了果子;
参数pHeadSnake、pTailSnake:分别表示贪吃蛇的头尾节点,即是入参也是出参;
返回值:表示贪吃蛇移动函数的结果是成功还是失败,0表示成功, -1表示失败;

typedef struct SLIST{
int x;
int y;
struct SLIST *prev;
struct SLIST *next;
}SLIST_S;
typedef struct Food{
int x;
int y;
bool IsHaveFood;
}Food_S;

根据上述描述:

(1) 请简要回答在不考虑吃到果子的前提下,贪吃蛇每上下左右移动一格,设计时如何对链表操作能达到高效的移动?(5分)

(2) 请实现贪吃蛇移动的函数,考虑移动时分别当吃到果子和没有吃的果子的场景,同时还要判断在移动一步之后是否会造成碰到蛇自己本身(不考虑碰壁),即当蛇的头部碰到蛇身体任何部分即表示失败。(25分)

第一题:

在不考虑吃到果子的前提下,贪吃蛇每上下左右移动一格时,可以按照以下步骤对链表进行高效的移动:

  1. 创建一个新的节点newHead,作为新的头节点,保存蛇头要移动到的位置信息。
  2. 根据当前的移动方向,更新newHead节点的x和y坐标,即计算蛇头移动后的位置。
  3. 将newHead节点的next指针指向原来的头节点,即将newHead插入到链表的头部。
  4. 将原来的头节点的prev指针指向newHead,完成链表的连接。
  5. 更新*pHeadSnake指针,使其指向newHead节点,即更新头节点的位置。
  6. 移除原来的尾节点,即将原来的尾节点从链表中删除。
  7. 更新*pTailSnake指针,使其指向新的尾节点,即更新尾节点的位置。

通过这种方式,每次移动只需要进行几个指针的重新连接和坐标的更新,而不需要对整个链表进行遍历,从而实现高效的移动操作。

第二题:

#include 

typedef struct SLIST {
    int x;
    int y;
    struct SLIST* prev;
    struct SLIST* next;
} SLIST_S;

typedef struct Food {
    int x;
    int y;
    bool IsHaveFood;
} Food_S;

int SnakeMove(Food_S* pFood, SLIST_S** pHeadSnake, SLIST_S** pTailSnake) {
    if (*pHeadSnake == NULL || *pTailSnake == NULL) {
        return -1; // 头节点或尾节点为空,移动失败
    }

    // 创建新的头节点
    SLIST_S* newHead = (SLIST_S*)malloc(sizeof(SLIST_S));
    if (newHead == NULL) {
        return -1; // 内存分配失败,移动失败
    }

    // 更新newHead节点的位置信息
    newHead->x = (*pHeadSnake)->x;
    newHead->y = (*pHeadSnake)->y;
    newHead->prev = NULL;
    newHead->next = *pHeadSnake;

    // 根据移动方向更新newHead节点的位置信息
    switch (direction) {
        case UP:
            newHead->y--;
            break;
        case DOWN:
            newHead->y++;
            break;
        case LEFT:
            newHead->x--;
            break;
        case RIGHT:
            newHead->x++;
            break;
    }

    // 判断是否吃到了果子
    if (pFood->IsHaveFood && pFood->x == newHead->x && pFood->y == newHead->y) {
        // 吃到了果子,不需要移除尾节点,更新pFood的IsHaveFood为FALSE
        pFood->IsHaveFood = false;
    } else {
        // 没有吃到果子,移除尾节点
        SLIST_S* oldTail = *pTailSnake;
        *pTailSnake = (*pTailSnake)->prev;
        (*pTailSnake)->next = NULL;
        free(oldTail);
    }

    // 检查是否碰到蛇自身
    SLIST_S* current = newHead->next;
    while (current != NULL) {
        if (current->x == newHead->x && current->y == newHead->y) {
            free(newHead);
            return -1; // 碰到蛇自身,移动失败
        }
        current = current->next;
    }

    // 更新*pHeadSnake指针和前一个节点的指针
    (*pHeadSnake)->prev = newHead;
    *pHeadSnake = newHead;

    return 0; // 移动成功
}

有趣的笔试题——贪吃蛇游戏(确定不进来看看?)_第2张图片

你可能感兴趣的:(笔记,游戏,链表,数据结构)