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 注释不够
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号