017 编写贪吃蛇

 

#include "stdafx.h"
#include <stdlib.h>
#include <windows.h>
#include <Winuser.h>
#include <assert.h>
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>

#define Blank    0    // 空白 -
#define Wall    1    // 墙体
#define Snake    2    //
#define Food    3    // 食物
#define Height    25    // 行数 - 高度
#define Wide    50    // 列数 - 宽度

int g_nMap[Height][Wide] = { Blank };


// 蛇 - 方向
enum EDirection
{
    Up = 0,
    Down,
    Left,
    Right
};

typedef struct SFood
{
    int x;
    int y;
}SFood, *pSFood;

typedef struct SSnake
{
    int x;    // 列数    nWide
    int y;    // 行数 nHeight
    SSnake *pPrev;
    SSnake *pNext;
}SSnake, *pSSnake;
pSSnake g_HeadSnake = NULL ;
pSSnake g_TailSnake = NULL ;
EDirection g_nDirection = Up;        // 初始化方向 - 蛇
SFood g_FoodCoordinate = { NULL };    // 初始化坐标 - 食物

// 设置窗口
void SetDos()
{
    HANDLE fd = GetStdHandle(STD_OUTPUT_HANDLE);

    // 设置窗口 : 宽高 - 大小
    system("mode con cols=51 lines=25");

    // 设置窗口 : 宽高 - 缓冲区
    COORD dwsize;
    dwsize.X = Height + 1;
    dwsize.Y = Wide + 1;
    SetConsoleScreenBufferSize(fd, dwsize);

    // 设置光标 - 消失    
    CONSOLE_CURSOR_INFO cinfo;
    cinfo.dwSize = 1;
    cinfo.bVisible = FALSE;    
    if (FALSE == SetConsoleCursorInfo(fd, &cinfo))
    {
        printf("执行失败\n");
    }
}

void AddSnake(EDirection Direction)
{
    pSSnake pSnake = (pSSnake)malloc(sizeof(SSnake));
    pSnake->y = g_HeadSnake->y;
    pSnake->x = g_HeadSnake->x;

    switch (Direction)
    {
        case Up:
        {
            pSnake->y = g_HeadSnake->y - 1;
            break;
        }
        case Down:
        {
            pSnake->y = g_HeadSnake->y + 1;
            break;
        }
        case Left:
        {
            pSnake->x = g_HeadSnake->x - 1;
            break;
        }
        case Right:
        {
            pSnake->x = g_HeadSnake->x + 1;
            break;
        }
    }
    g_nMap[pSnake->y][pSnake->x] = Snake;    // 绘画地图

    // 双向链表 - 连接
    pSnake->pPrev = NULL;            // 新节点首指针 - 为空
    pSnake->pNext = g_HeadSnake;    // 连接节点 : 新节点尾指针 - 指向原头部地址

    g_HeadSnake->pPrev = pSnake;    // 连接节点 : 原头部首指针 - 新节点地址
    g_HeadSnake = pSnake;            // 头部指针 : 指向 -新节点地址
}

void InitializeMap()
{
    // 循环地图
    int nHeight = 0;    // 行数 - 高度
    while (nHeight < Height)
    {
        int nWide = 0;    // 列数 - 宽度
        while (nWide < Wide)
        {
            // 初始化 - 墙
            if (0 == nHeight)    // 墙 : 坐标 - (0,x)
            {
                g_nMap[nHeight][nWide] = Wall;
            }
            if (0 == nWide)    // 墙 : 坐标 - (x,0)
            {
                g_nMap[nHeight][nWide] = Wall;
            }
            if (nWide == Wide - 1)    // 墙 : 坐标 - (x,Wide - 1)
            {
                g_nMap[nHeight][nWide] = Wall;
            }
            if (nHeight == Height - 1)    // 墙 : 坐标 - (x,Height - 1)
            {
                g_nMap[nHeight][nWide] = Wall;
            }

            // 初始化 - 蛇
            if (nHeight == Height / 2 && nWide == Wide / 2)
            {
                
                int nHeadSnakeY = nHeight;
                int nHeadSnakeX = nWide;
                // 绘画 - 蛇身
                g_nMap[nHeadSnakeY][nHeadSnakeX] = Snake;

                pSSnake pSnake = (pSSnake)malloc(sizeof(SSnake));
                pSnake->y = nHeadSnakeY;    // 行数 - 高度; y = nHeight
                pSnake->x = nHeadSnakeX;    // 列数 - 宽度; x - nWide
                pSnake->pPrev = NULL;
                pSnake->pNext = NULL;
                g_HeadSnake = pSnake;
                g_TailSnake = pSnake;

                AddSnake(Up);
                AddSnake(Up);
                AddSnake(Up);
            }

            // 初始化 - 食物

            ++nWide;
        }
        ++nHeight;
    }
}


void ShowMap()
{
    system("cls");

    // 初始化 - 墙
    int nHeight = 0;    // 行数 - 宽度
    while (nHeight < Height)
    {
        int nWide = 0;
        while (nWide < Wide)
        {
            if (Wall == g_nMap[nHeight][nWide])
            {
                printf("#");
            }
            else if (Snake == g_nMap[nHeight][nWide])
            {
                printf("*");
            }
            else if (Blank == g_nMap[nHeight][nWide])
            {
                printf(" ");
            }
            else if (Food == g_nMap[nHeight][nWide])
            {
                printf("@");
            }
            else
            {
                assert(FALSE);
                printf("%s\n%s\n%s\n%d\n", __DATE__, __FILE__, __func__, __LINE__);
            }
            ++nWide;    
        }


        // 设置目的 : 最后一行 - 不换行
        if (Height - 1 != nHeight && Wall != nWide)
        {
            printf("\n");
        }

        ++nHeight;
    }
}

BOOL StopOver()
{
    int nNextY = g_HeadSnake->y;
    int nNextX = g_HeadSnake->x;
    
    switch (g_nDirection)
    {
        case Up:
        {
            nNextY = g_HeadSnake->y - 1;
            break;
        }
        case Down:
        {
            nNextY = g_HeadSnake->y + 1;
            break;
        }
        case Left:
        {
            nNextX = g_HeadSnake->x - 1;
            break;
        }
        case Right:
        {
            nNextX = g_HeadSnake->x + 1;
            break;
        }
    }

    int nResult = g_nMap[nNextY][nNextX];
    if (nResult == Blank || nResult == Food)
    {
        return TRUE;
    }
    return FALSE;
}

void ChangeCurrentDirection(char cDirection)
{
    // 改变当前方向
    switch (cDirection)
    {
        case 'w':    // 向上移动
        {
            g_nDirection = Up;
            break;
        }
        case 's':    // 向下移动
        {
            g_nDirection = Down;
            break;
        }
        case 'a':    // 向左移动
        {
            g_nDirection = Left;
            break;

        }
        case 'd':    // 向右移动
        {
            g_nDirection = Right;
            break;
        }
    }
}

// 自动移动或者手动输入
void AutoMoveOrInputMove(char *pDirection)
{
    Sleep(400);
    fflush(stdin);
    if (!_kbhit())
    {
        switch (g_nDirection)
        {
            case Up:    // 向上移动
            {
                *pDirection = 'w';
                break;
            }
            case Down:    // 向下移动
            {
                *pDirection = 's';
                break;
            }
            case Left:    // 向左移动
            {
                *pDirection = 'a';
                break;

            }
            case Right:    // 向右移动
            {
                *pDirection = 'd';
                break;
            }
            default: return ;
            }
    }
    else
    {
        *pDirection = _getch();
    }
}


// 创建食物
void CreateFood()
{
    srand((unsigned)time(NULL));
    while (TRUE)
    {
        int nX = rand() % Wide - 1;
        int nY = rand() % Height - 1;
        if (Blank == g_nMap[nY][nX])
        {            
            g_nMap[nY][nX] = Food;
            g_FoodCoordinate.x = nX;
            g_FoodCoordinate.y = nY;
            return;
        }
    }
}


// 检查碰撞 - 蛇头和食物
void CrashDetection()
{
    if (g_HeadSnake->x == g_FoodCoordinate.x && g_HeadSnake->y == g_FoodCoordinate.y)
    {
        AddSnake(g_nDirection);
        CreateFood();
    }
}

// 移动蛇身
void MoveSnake(char cDirection)
{
    // 创建新节点 : 双向链表 - 头插法
    pSSnake pSnake = (pSSnake)malloc(sizeof(SSnake));
    pSSnake pTempHead = g_HeadSnake;

    pSnake->pPrev = NULL;
    pSnake->pNext = g_HeadSnake;
    g_HeadSnake->pPrev = pSnake;
    g_HeadSnake = pSnake;

    int nCoordinateY = pTempHead->y;
    int nCoordinateX = pTempHead->x;
    switch (cDirection)
    {
        case 'w':    // 向上移动
        {
            nCoordinateY = nCoordinateY - 1;                // 向上移动 : 纵坐标 - 递减            
            g_nDirection = Up;

            break;
        }
        case 's':    // 向下移动
        {
            nCoordinateY = nCoordinateY + 1;                // 向上移动 : 纵坐标 - 递减    
            break;
        }
        case 'a':    // 向左移动
        {
            nCoordinateX = nCoordinateX - 1;                // 向左移动 : 横坐标 - 递减
            break;

        }
        case 'd':    // 向右移动
        {
            nCoordinateX = nCoordinateX + 1;                // 向右移动 : 横坐标 - 递增            
            break;
        }
    }
    // 重绘蛇头
    g_nMap[nCoordinateY][nCoordinateX] = Snake;    // 重绘
    pSnake->y = nCoordinateY;
    pSnake->x = nCoordinateX;

    // 清空蛇尾
    g_nMap[g_TailSnake->y][g_TailSnake->x] = Blank;    // 清空    
    pSSnake pTempTail = g_TailSnake;
    g_TailSnake = g_TailSnake->pPrev;
    g_TailSnake->pNext = NULL;
    free(pTempTail);
}

int Run()
{
    while (TRUE)
    {
        char cDirection = NULL;
        // cDirection = _getch();
        AutoMoveOrInputMove(&cDirection);    // 检查输入

        // 相反方向
        if (g_nDirection == Down && cDirection == 'w' ||
            g_nDirection == Up && cDirection == 's' ||
            g_nDirection == Right && cDirection == 'a' ||
            g_nDirection == Left && cDirection == 'd')
        {
            return TRUE;
        }

        // 检查方向 - 当前位置
        ChangeCurrentDirection(cDirection);
        if (FALSE == StopOver())
        {
            return FALSE;
        }

        // 移动蛇身
        MoveSnake(cDirection);

        //  检查碰撞 - 蛇头和食物
        CrashDetection();

        return TRUE;
    }
}

int main(int argc, char *argv[], char **envp)
{
    SetDos();    
    InitializeMap();
    CreateFood();

    BOOL bContinue = TRUE;
    while (bContinue)
    {
        ShowMap();
        bContinue = Run();
    }

    return 0;
}

 

效果图

 

 

贪吃蛇 
    反思:
        1 没有概要设计,再详细编码。代码整体比较乱
        2 没有分层: 界面和逻辑。 逻辑(算法和操作)
        3 地图绘画做的不好,重复代码多。
        4 函数: 分类、太长、组合。
        5 全局变量用的太多
        6 垃圾代码太多

    总结
        1 函数中,检测条件放最前面
    

 

BUG:    
    1 写代码拖拖拉拉的,没有安装进度执行
    2 没学过设计模式,写代码前设计不好
    3 函数没有结对编程
    4 命名不规范
    5 注释不够

 

posted @ 2019-09-24 23:48  火焰马  阅读(200)  评论(0)    收藏  举报