这个版本也是这个贪吃蛇系列的最后一个版本了(虽然蛇长度变得很长之后,食物在某些区域,蛇的行走路线还有优化的空间,但是近期应该不会再进行更新了),下面对之前所有的迭代版本做一个总结:
版本一、只有闯关模式和限时模式(主要时间花在贴那个蛇头,蛇转弯,蛇身和蛇尾上面,因为不同的方向状态是不一样的)(整整1天) 版本二、初级智能版,用了简单的BFS搜索,主要针对大食物和小食物(2个小时) 版本三、中级智能版,加入了启发式搜索和在食物搜索不到是跟着尾巴走的策略(3个小时) 版本四、高级智能版,因为跟着尾巴走有时会陷入死循环,加入了随机wander算法(3个小时) 版本五、专家智能版,根据蛇身的长度,策略有所调整,不再一味的跟着食物跑了,在吃到吃完之后,会判断一下自身是否已经调整完毕,如果调整好了再继续吃食物,否则继续调整(4个小时) 版本六、修复了专家智能版的几个小bug(半个小时)
一条贪吃蛇的自白: 1. 刚开始的时候,我完全不会思考,别人要我往哪里走我就往哪里走(这是原始版本,通过方向键来控制) 2. 后来我升到了1级,能够感知到食物的存在,大草莓更加诱人,但是没多久就消失了,并且不是每次都有的,所以只要大的草莓一出来,我马上就过去吃,生怕一下就没了,如果大的吃完了,我在回来吃小草莓。(这是初级智能版) 3. 接着我又升到了2级,因为我发现有的时候被自己的身体挡住了,暂时是吃不到任何草莓的,但是有不敢乱走,走不好就撞到自己的尾巴了,所以这里我会跟着自己的尾巴走,因为我知道跟着尾巴走肯定不会挂(这是中级智能版) 4. 然后我又升到了3级,这个时候我发现了一个问题,在食物被身体围住之后,由于不确定是否安全,我不自觉的一直跟着尾巴走,一圈又一圈,感觉没有尽头,突然有一天,发现这样下去不行,永远都吃不到草莓了,所以我觉得随机的往各个方向去溜达一下,然后再回来找自己的尾巴,这样经过若干次之后,我就吃到草莓了(这是高级智能版) 5. 然后我升到了4级,我的身体已经越来越长了,这个时候不能再一味的吃食物了,要随时调整自己的身体,不然自己的头部马上就撞到自己的身体了,所以我每吃到一个草莓,就会看看我的身体是否已经调整好了,如果调整好了,我再去吃草莓,否则先把身体调整好(这是高级智能版) 6. 现在我已经有了一些智能了,我又修复了内部的一点小缺陷,主要是针对S形寻路的方向问题的优化(这是最后的一般了)
下面给出最后一个版本的代码: snake.h
#pragma once #include <stdio.h> #include <graphics.h> #include <windows.h> #include <mmsystem.h> #include <time.h> #include <conio.h> #include <queue> #include "resource.h" #pragma comment(lib, "winmm.lib") #define SNAKE_DRAW_SIZE 15 #define WND_WIDTH 1000 #define WND_HEIGHT 600 #define REGION_WIDTH 600 #define REGION_HEIGHT 600 #define RIGHT_EDGE_WIDTH 10 #define HEADLINE_POSX 265 #define HEADLINE_POSY 120 #define TEXT_TIME_POSX 670 #define TEXT_TIME_POSY 100 #define TEXT_LEVEL_POSX 670 #define TEXT_LEVEL_POSY 100 #define TEXT_SCORE_POSX 670 #define TEXT_SCORE_POSY 200 #define TEXT_LEN_POSX 670 #define TEXT_LEN_POSY 300 #define TEXT_HIGHSCORE_POSX 670 #define TEXT_HIGHSCORE_POSY 400 #define TEXT_HIGHLEVEL_POSX 670 #define TEXT_HIGHLEVEL_POSY 500 #define SNAKE_INIT_PT_X (REGION_WIDTH / SNAKE_DRAW_SIZE / 5) #define SNAKE_INIT_PT_Y (REGION_HEIGHT / SNAKE_DRAW_SIZE / 2) #define FIRST_ITEM_POSX 375 #define FIRST_ITEM_POSY 250 #define FIRST_ITEM_WIDTH 220 #define FIRST_ITEM_HEIGHT 30 #define SECOND_ITEM_POSX 375 #define SECOND_ITEM_POSY 350 #define SECOND_ITEM_WIDTH 220 #define SECOND_ITEM_HEIGHT 30 #define THIRD_ITEM_POSX 375 #define THIRD_ITEM_POSY 450 #define THIRD_ITEM_WIDTH 220 #define THIRD_ITEM_HEIGHT 30 #define BIGFOOD_SHOWTIME 6000 #define BIGFOOD_STEPTIME 100 #define FOOD_SCORE 1 #define BIG_FOOD_SCORE 5 #define INIT_SPEED 60 #define MINUS_SPEED 15 #define TOTAL_TIME 100 #define MAX_YOUNG_LEN 100 #define SNAKE_MAX ((REGION_WIDTH / SNAKE_DRAW_SIZE) * (REGION_HEIGHT / SNAKE_DRAW_SIZE)) #define BREAKTHROUGHAPPNAME L"BreakThrough" #define BREAKTHROUGHSCORE L"HighScore" #define BREAKTHROUGHLEVEL L"HighLevel" #define TIMELIMITEDAPPNAME L"TimeLimited" #define TIMELIMITEDSCORE L"HighScore" #define AIAPPNAME L"Intelligence" #define AISCORE L"HighScore" #define AILEVEL L"HighLevel" int arrScore[] = { 0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 85, 95, 118, 130, 155, 170, 190, 210, 230, 250, 270, 300, 350, 400, 460, 500, 550, 600, 650, 700, 750, 810, 880, 950, 1000, 1100, 1250, 1400, 1600, 1850, 2100, 2400, 2700, 3000, 3400, 3800, 4200, 4600, 5000, 5500, 5900, 6300, 6800, 7500, 8000, 8500, 9000, 9500, 10000 }; enum EmPattern { emBreakThroughPattern = 1, emTimeLimitedPattern, emIntelligencePattern, }; enum EmStage { emChooseStage = 1, emPlayStage, }; enum EmDir { emDirUp = 72, emDirDown = 80, emDirLeft = 75, emDirRight = 77, }; struct Point { int x; int y; }; struct Snake { int nCount; Point pt[SNAKE_MAX]; EmDir dir; }; struct Food { Point fpt; char isEat; }; struct BigFood { Point fpt; char isEat; }; bool mp[REGION_WIDTH / SNAKE_DRAW_SIZE + 1][REGION_HEIGHT / SNAKE_DRAW_SIZE + 1];//存放地图标记 bool isVisit[REGION_WIDTH / SNAKE_DRAW_SIZE + 1][REGION_HEIGHT / SNAKE_DRAW_SIZE + 1];//存放访问标记 Point parent[REGION_WIDTH / SNAKE_DRAW_SIZE + 1][REGION_HEIGHT / SNAKE_DRAW_SIZE + 1];//存放父节点指向 std::queue<Point>tempQ;//存放搜索过程中的节点 std::queue<Point>pathQ;//存放路径节点 int search_dir[4][2] = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; EmStage stage = EmStage::emChooseStage; EmPattern pattern = EmPattern::emBreakThroughPattern; Snake snake; Food food; BigFood bigFood; bool bUserInput = false; int nBigFoodTimer = 0; int nCurLevel = 1; int nCurScore = 0; int nSnakeLen = 3; int nHighLevel = 0; int nHighScore = 0; int nCurSpeed = INIT_SPEED; int nRemainTime = TOTAL_TIME; int nTimePast = 0; int nCurChaseTailTimes = 0;//最大追尾长度 bool bIsAdjustOk;//蛇身是否调整好 void SetMouseNormal(); void SetMouseHand(); void SetLevelText(); void SetHoverStyle(); void SetNormalStyle(); void TackleMouseMove(int x, int y); void TackleLeftButtonDown(int x, int y); void TackleMouseAction(); void InitFirstScene(); void InitSecondBackGround(); void InitSecondScene(); bool SearchSnakePath(Point startPt, Point endPt); void InitMap(); void GameInit(); void PlayGame(); int IsFoodPosOk(int x, int y, Point endPt); void ProduceFood(); void DrawFood(); int ProduceBigFood(); void DrawBigFood(); int IsEatBigFood(); void EatFood(); void LevelUp(); void DrawSnake(); bool IsEatFoodSafe(); void AIChangeDir(); bool IsSnakeAdjustOk(); bool IsGoLeftBetter(); bool IsGoUpBetter(); bool IsLeftDeadWay(int x, int y); bool IsRightDeadWay(int x, int y); bool IsGoDownDeadWay(int x, int y); bool IsGoUpDeadWay(int x, int y); bool MustWinModeGoDown(); bool MustWinModeGoUp(); bool MustWinModeGoLeft(); bool MustWinModeGoRight(); bool StartMustWinStrategy(); void AIRealChangeDirection(); bool AISearchBigFood(); bool AISearchSmallFood(); bool AISearchNearTail(); bool AIWanderSearch1(bool isTryAgain = false); bool AIWanderSearch2(bool isTryAgain = false); bool AIWanderSearch3(bool isTryAgain = false); bool AIWanderSearch4(bool isTryAgain = false); bool AISearchFourCorner(int x, int y); void SnakeMove(); void ChangeDir(); void BreakSnake(); void WriteRecord(); void BigFoodDisappear(); void TimeEclipse(); void DecideHeadDirection(); void DrawSnakeHead(int nIndex); void DecideCornerDirection(int idx); void DrawCorner(int nIndex, int idx); void DecideBodyDirection(int idx); void DrawBody(int nIndex, int idx); void DecideTailDirection(int idx); void DrawTail(int nIndex, int idx); void BreakThroughPattern(); void TimeLimitedPattern();easysnake.cpp
#include "easysnake.h" BOOL KExpandEnvironmentString(IN LPCTSTR lpEnvironmentString, OUT LPTSTR lpExpandString, IN ULONG ulExpandStringLength) { BOOL bResult = FALSE; LPTSTR lpBuffer = NULL; ULONG ulRetLength = 0; if (!lpEnvironmentString || !lpExpandString || 1 > ulExpandStringLength) { goto _abort; } ulRetLength = ::ExpandEnvironmentStrings(lpEnvironmentString, NULL, 0); if (1 > ulRetLength || ulRetLength > ulExpandStringLength - 1) { goto _abort; } __try { lpBuffer = new TCHAR[ulRetLength]; if (!lpBuffer) { goto _abort; } ::RtlZeroMemory(lpBuffer, sizeof(TCHAR)* ulRetLength); ulRetLength = ::ExpandEnvironmentStrings(lpEnvironmentString, lpBuffer, ulRetLength); if (ulRetLength && ulRetLength <= ulExpandStringLength - 1) { _tcsncpy_s(lpExpandString, ulExpandStringLength - 1, lpBuffer, ulRetLength); bResult = TRUE; } } __except (EXCEPTION_EXECUTE_HANDLER) { bResult = FALSE; } _abort: if (lpBuffer) { delete[] lpBuffer; lpBuffer = NULL; } return bResult; } void SetMouseNormal() { HCURSOR hcur = LoadCursor(NULL, IDC_ARROW); HWND hwnd = GetHWnd(); SetClassLong(hwnd, GCL_HCURSOR, (long)hcur); } void SetMouseHand() { HCURSOR hcur = LoadCursor(NULL, MAKEINTRESOURCE(32649)); HWND hwnd = GetHWnd(); SetClassLong(hwnd, GCL_HCURSOR, (long)hcur); } void SetLevelText() { switch (pattern) { case EmPattern::emBreakThroughPattern: outtextxy(FIRST_ITEM_POSX, FIRST_ITEM_POSY, L"闯关模式"); break; case EmPattern::emTimeLimitedPattern: outtextxy(SECOND_ITEM_POSX, SECOND_ITEM_POSY, L"限时模式"); break; case EmPattern::emIntelligencePattern: outtextxy(THIRD_ITEM_POSX, THIRD_ITEM_POSY, L"智能模式"); break; default: break; } } void SetHoverStyle() { settextcolor(RGB(255, 0, 119)); SetLevelText(); SetMouseHand(); } void SetNormalStyle() { settextcolor(BROWN); SetLevelText(); SetMouseNormal(); } void TackleMouseMove(int x, int y) { if (stage == EmStage::emPlayStage) return; if (x > FIRST_ITEM_POSX && x < FIRST_ITEM_POSX + FIRST_ITEM_WIDTH && y >FIRST_ITEM_POSY && y < FIRST_ITEM_POSY + FIRST_ITEM_HEIGHT) { pattern = EmPattern::emBreakThroughPattern; SetHoverStyle(); return; } else { pattern = EmPattern::emBreakThroughPattern; SetNormalStyle(); } if (x > SECOND_ITEM_POSX && x < SECOND_ITEM_POSX + SECOND_ITEM_WIDTH && y > SECOND_ITEM_POSY && y < SECOND_ITEM_POSY + SECOND_ITEM_HEIGHT) { pattern = EmPattern::emTimeLimitedPattern; SetHoverStyle(); return; } else { pattern = EmPattern::emTimeLimitedPattern; SetNormalStyle(); } if (x > THIRD_ITEM_POSX && x < THIRD_ITEM_POSX + THIRD_ITEM_WIDTH && y > THIRD_ITEM_POSY && y < THIRD_ITEM_POSY + THIRD_ITEM_HEIGHT) { pattern = EmPattern::emIntelligencePattern; SetHoverStyle(); } else { pattern = EmPattern::emIntelligencePattern; SetNormalStyle(); } } void TimeLimitedPattern() { settextstyle(20, 20, L"楷体", 0, 0, 900, 0, 0, 0); setbkmode(TRANSPARENT); settextcolor(RGB(255, 0, 0)); WCHAR szCurRemainTime[32]; WCHAR szCurScore[32]; WCHAR szSnakeLen[32]; WCHAR szHighScore[32]; swprintf_s(szCurRemainTime, L"剩余时间: %d", nRemainTime); swprintf_s(szCurScore, L"当前得分: %d", nCurScore); swprintf_s(szSnakeLen, L"蛇身长度: %d", snake.nCount); swprintf_s(szHighScore, L"最高分数: %d", nHighScore); outtextxy(TEXT_TIME_POSX, TEXT_TIME_POSY, szCurRemainTime); outtextxy(TEXT_SCORE_POSX, TEXT_SCORE_POSY, szCurScore); outtextxy(TEXT_LEN_POSX, TEXT_LEN_POSY, szSnakeLen); outtextxy(TEXT_HIGHSCORE_POSX, TEXT_HIGHSCORE_POSY, szHighScore); } void BreakThroughPattern() { settextstyle(20, 20, L"楷体", 0, 0, 900, 0, 0, 0); setbkmode(TRANSPARENT); settextcolor(RGB(255, 0, 0)); WCHAR szCurLevel[32]; WCHAR szCurScore[32]; WCHAR szSnakeLen[32]; WCHAR szHighLevel[32]; WCHAR szHighScore[32]; swprintf_s(szCurLevel, L"当前级别: %d", nCurLevel); swprintf_s(szCurScore, L"当前得分: %d", nCurScore); swprintf_s(szSnakeLen, L"蛇身长度: %d", snake.nCount); swprintf_s(szHighLevel, L"最高级别: %d", nHighLevel); swprintf_s(szHighScore, L"最高分数: %d", nHighScore); outtextxy(TEXT_LEVEL_POSX, TEXT_LEVEL_POSY, szCurLevel); outtextxy(TEXT_SCORE_POSX, TEXT_SCORE_POSY, szCurScore); outtextxy(TEXT_LEN_POSX, TEXT_LEN_POSY, szSnakeLen); outtextxy(TEXT_HIGHSCORE_POSX, TEXT_HIGHSCORE_POSY, szHighLevel); outtextxy(TEXT_HIGHLEVEL_POSX, TEXT_HIGHLEVEL_POSY, szHighScore); } void TackleLeftButtonDown(int x, int y) { if (x > FIRST_ITEM_POSX && x < FIRST_ITEM_POSX + FIRST_ITEM_WIDTH && y >FIRST_ITEM_POSY && y < FIRST_ITEM_POSY + FIRST_ITEM_HEIGHT) { pattern = EmPattern::emBreakThroughPattern; InitSecondScene(); } if (x > SECOND_ITEM_POSX && x < SECOND_ITEM_POSX + SECOND_ITEM_WIDTH && y > SECOND_ITEM_POSY && y < SECOND_ITEM_POSY + SECOND_ITEM_HEIGHT) { pattern = EmPattern::emTimeLimitedPattern; InitSecondScene(); } if (x > THIRD_ITEM_POSX && x < THIRD_ITEM_POSX + THIRD_ITEM_WIDTH && y > THIRD_ITEM_POSY && y < THIRD_ITEM_POSY + THIRD_ITEM_HEIGHT) { pattern = EmPattern::emIntelligencePattern; InitSecondScene(); } } void TackleMouseAction() { MOUSEMSG msg; while (1) { msg = GetMouseMsg();//获取鼠标信息 switch (msg.uMsg) { case WM_LBUTTONDOWN://处理鼠标的左键点击消息 TackleLeftButtonDown(msg.x, msg.y); break; case WM_MOUSEMOVE://处理鼠标的左键点击消息 TackleMouseMove(msg.x, msg.y); break; default: break; } } } void InitFirstScene() { cleardevice(); stage = EmStage::emChooseStage; IMAGE img; for (int i = 0; i < 22; i++) { loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG1), SNAKE_DRAW_SIZE * 3, SNAKE_DRAW_SIZE * 3); putimage(4 + SNAKE_DRAW_SIZE * 3 * i, 0, &img); } settextstyle(38, 38, L"楷体", 0, 0, 1000, 0, 0, 0); setbkmode(TRANSPARENT); settextcolor(RGB(255, 0, 0)); outtextxy(HEADLINE_POSX, HEADLINE_POSY, L"贪吃蛇大作战"); settextstyle(28, 28, L"楷体", 0, 0, 1000, 0, 0, 0); setbkmode(TRANSPARENT); pattern = EmPattern::emBreakThroughPattern; SetNormalStyle(); pattern = EmPattern::emTimeLimitedPattern; SetNormalStyle(); pattern = EmPattern::emIntelligencePattern; SetNormalStyle(); pattern = EmPattern::emBreakThroughPattern; TackleMouseAction(); } void InitSecondBackGround() { setlinecolor(RED); setlinestyle(PS_SOLID, RIGHT_EDGE_WIDTH); line(REGION_WIDTH + 4, 0, REGION_WIDTH + 4, REGION_HEIGHT); if (EmPattern::emBreakThroughPattern == pattern) BreakThroughPattern(); else if (EmPattern::emTimeLimitedPattern == pattern) TimeLimitedPattern(); else if (EmPattern::emIntelligencePattern == pattern) BreakThroughPattern(); } void InitSecondScene() { cleardevice(); stage = EmStage::emPlayStage; GameInit(); InitSecondBackGround(); PlayGame(); } bool IsSearchPointOk(int x, int y, Point endPt) { if (x < 0 || x > REGION_WIDTH / SNAKE_DRAW_SIZE - 1 || y < 0 || y > REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) return false; if (isVisit[x][y]) return false; if (mp[x][y] && (x != endPt.x || y != endPt.y)) return false; return true; } void PushPath(Point startPt, Point endPt) { if (endPt.x != startPt.x || endPt.y != startPt.y) { PushPath(startPt, parent[endPt.x][endPt.y]); pathQ.push(endPt); } } bool SearchSnakePath(Point startPt, Point endPt) { while (!pathQ.empty()) pathQ.pop(); while (!tempQ.empty()) tempQ.pop(); tempQ.push(startPt); isVisit[startPt.x][startPt.y] = true; Point nextPoint; while (!tempQ.empty()) { Point firstPoint = tempQ.front(); tempQ.pop(); if (firstPoint.x == endPt.x && firstPoint.y == endPt.y) return true; for (int i = 0; i < 4; i++) { nextPoint.x = firstPoint.x + search_dir[i][0]; nextPoint.y = firstPoint.y + search_dir[i][1]; if (IsSearchPointOk(nextPoint.x, nextPoint.y, endPt)) { isVisit[nextPoint.x][nextPoint.y] = true; tempQ.push(nextPoint); parent[nextPoint.x][nextPoint.y].x = firstPoint.x; parent[nextPoint.x][nextPoint.y].y = firstPoint.y; } } } return false; } void InitMap() { memset(mp, false, sizeof(mp)); //把地图标记还原 memset(isVisit, false, sizeof(isVisit)); for (int i = 0; i < snake.nCount; i++) mp[snake.pt[i].x][snake.pt[i].y] = true; for (int i = 0; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) { for (int j = 0; j < REGION_HEIGHT / SNAKE_DRAW_SIZE; j++) { parent[i][j].x = -1; parent[i][j].y = -1; } } } void GameInit() { snake.dir = EmDir::emDirRight; snake.nCount = 3; for (int i = 0; i < snake.nCount; i++) { snake.pt[i].x = SNAKE_INIT_PT_X - i; snake.pt[i].y = SNAKE_INIT_PT_Y; } food.isEat = 1; bigFood.isEat = 1; nBigFoodTimer = 0; InitMap();//初始化地图标记 WCHAR szTempPath[MAX_PATH] = { 0 }; WCHAR szIniPath[MAX_PATH] = { 0 }; KExpandEnvironmentString(L"%TEMP%", szTempPath, MAX_PATH); swprintf_s(szIniPath, L"%s\\record.ini", szTempPath); nCurSpeed = INIT_SPEED; nCurLevel = 1; nCurScore = 0; nSnakeLen = 3; nRemainTime = TOTAL_TIME; nTimePast = 0; nCurChaseTailTimes = 0; bIsAdjustOk = false; if (pattern == EmPattern::emTimeLimitedPattern) nHighScore = ::GetPrivateProfileInt(TIMELIMITEDAPPNAME, TIMELIMITEDSCORE, 0, szIniPath); else if (pattern == EmPattern::emBreakThroughPattern) { nHighScore = ::GetPrivateProfileInt(BREAKTHROUGHAPPNAME, BREAKTHROUGHSCORE, 0, szIniPath); nHighLevel = ::GetPrivateProfileInt(BREAKTHROUGHAPPNAME, BREAKTHROUGHLEVEL, 1, szIniPath); } else if (pattern == EmPattern::emIntelligencePattern) { nHighScore = ::GetPrivateProfileInt(AIAPPNAME, AISCORE, 0, szIniPath); nHighLevel = ::GetPrivateProfileInt(AIAPPNAME, AILEVEL, 1, szIniPath); } } void PlayGame() { while (1) { while (!_kbhit()) { ProduceFood(); BigFoodDisappear(); TimeEclipse(); BeginBatchDraw(); cleardevice(); InitSecondBackGround(); DrawFood(); DrawBigFood(); EatFood(); ProduceFood(); SnakeMove(); DrawSnake(); Sleep(nCurSpeed); EndBatchDraw(); BreakSnake(); } ChangeDir(); } } void TimeEclipse() { if (pattern != EmPattern::emTimeLimitedPattern) return; nTimePast += nCurSpeed; nRemainTime = TOTAL_TIME - nTimePast / 1000; nCurSpeed = INIT_SPEED - nTimePast / 1000; if (nRemainTime < 0) { WCHAR szScore[32] = { 0 }; swprintf_s(szScore, L"你的得分是: %d", nCurScore); ::MessageBox(0, szScore, L"时间到", MB_SYSTEMMODAL); WriteRecord(); InitFirstScene(); } } void BigFoodDisappear() { if (1 == bigFood.isEat) return; nBigFoodTimer += BIGFOOD_STEPTIME;//大食物定时消失 if (nBigFoodTimer >= BIGFOOD_SHOWTIME) { bigFood.isEat = 1; nBigFoodTimer = 0; } } void WriteRecord() { WCHAR szTempPath[MAX_PATH] = { 0 }; WCHAR szIniPath[MAX_PATH] = { 0 }; WCHAR szHighScore[8] = { 0 }; WCHAR szHighLevel[8] = { 0 }; KExpandEnvironmentString(L"%TEMP%", szTempPath, MAX_PATH); swprintf_s(szIniPath, L"%s\\record.ini", szTempPath); if (pattern == EmPattern::emBreakThroughPattern) { nHighLevel = ::GetPrivateProfileInt(BREAKTHROUGHAPPNAME, BREAKTHROUGHLEVEL, 1, szIniPath); nHighScore = ::GetPrivateProfileInt(BREAKTHROUGHAPPNAME, BREAKTHROUGHSCORE, 0, szIniPath); if (nCurScore > nHighScore) { swprintf_s(szHighScore, L"%d", nCurScore); WritePrivateProfileString(BREAKTHROUGHAPPNAME, BREAKTHROUGHSCORE, szHighScore, szIniPath); } if (nCurLevel > nHighLevel) { swprintf_s(szHighLevel, L"%d", nCurLevel); WritePrivateProfileString(BREAKTHROUGHAPPNAME, BREAKTHROUGHLEVEL, szHighLevel, szIniPath); } } else if (pattern == EmPattern::emTimeLimitedPattern) { nHighScore = ::GetPrivateProfileInt(TIMELIMITEDAPPNAME, TIMELIMITEDSCORE, 0, szIniPath); if (nCurScore > nHighScore) { swprintf_s(szHighScore, L"%d", nCurScore); WritePrivateProfileString(TIMELIMITEDAPPNAME, TIMELIMITEDSCORE, szHighScore, szIniPath); } } else if (pattern == EmPattern::emIntelligencePattern) { nHighLevel = ::GetPrivateProfileInt(AIAPPNAME, AILEVEL, 1, szIniPath); nHighScore = ::GetPrivateProfileInt(AIAPPNAME, AISCORE, 0, szIniPath); if (nCurScore > nHighScore) { swprintf_s(szHighScore, L"%d", nCurScore); WritePrivateProfileString(AIAPPNAME, AISCORE, szHighScore, szIniPath); } if (nCurLevel > nHighLevel) { swprintf_s(szHighLevel, L"%d", nCurLevel); WritePrivateProfileString(AIAPPNAME, AILEVEL, szHighLevel, szIniPath); } } } void BreakSnake() { if (snake.pt[0].x < 0 || snake.pt[0].x > REGION_WIDTH / SNAKE_DRAW_SIZE - 1 || snake.pt[0].y < 0 || snake.pt[0].y > REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) { ::MessageBox(0, L"你撞墙了", L"游戏失败", MB_SYSTEMMODAL); WriteRecord(); InitFirstScene(); } for (int i = snake.nCount - 2; i > 0; i--) { if (snake.pt[i].x == snake.pt[0].x && snake.pt[i].y == snake.pt[0].y) { ::MessageBox(0, L"你咬到自己了", L"游戏失败", MB_SYSTEMMODAL); WriteRecord(); InitFirstScene(); } } } void ChangeDir() { int dir = _getch(); switch (dir) { case EmDir::emDirUp: bUserInput = true; if (snake.dir != EmDir::emDirDown) snake.dir = EmDir::emDirUp; break; case EmDir::emDirDown: bUserInput = true; if (snake.dir != EmDir::emDirUp) snake.dir = EmDir::emDirDown; break; case EmDir::emDirLeft: bUserInput = true; if (snake.dir != EmDir::emDirRight) snake.dir = EmDir::emDirLeft; break; case EmDir::emDirRight: bUserInput = true; if (snake.dir != EmDir::emDirLeft) snake.dir = EmDir::emDirRight; break; default: break; } } void AIRealChangeDirection() { Point pt = pathQ.front(); pathQ.pop(); if (pt.x == snake.pt[0].x) { if (pt.y - snake.pt[0].y == -1) snake.dir = EmDir::emDirUp; else if (pt.y - snake.pt[0].y == 1) snake.dir = EmDir::emDirDown; } else if (pt.y == snake.pt[0].y) { if (pt.x - snake.pt[0].x == -1) snake.dir = EmDir::emDirLeft; else if (pt.x - snake.pt[0].x == 1) snake.dir = EmDir::emDirRight; } } bool AISearchBigFood() { if (bigFood.isEat) return false; InitMap(); if (!SearchSnakePath(snake.pt[0], bigFood.fpt)) return false; PushPath(snake.pt[0], bigFood.fpt); AIRealChangeDirection(); return true; } bool AISearchSmallFood() { InitMap(); if (!IsEatFoodSafe()) return false; if (!SearchSnakePath(snake.pt[0], food.fpt)) return false; PushPath(snake.pt[0], food.fpt); AIRealChangeDirection(); return true; } bool AISearchNearTail() { InitMap(); if (!SearchSnakePath(snake.pt[0], snake.pt[snake.nCount - 1])) return false; PushPath(snake.pt[0], snake.pt[snake.nCount -1]); AIRealChangeDirection(); nCurChaseTailTimes++; return true; } bool AIWanderSearch1(bool isTryAgain) { InitMap(); if (snake.pt[0].x < 2) return false; if (mp[snake.pt[0].x - 1][snake.pt[0].y] ) return false; if (!isTryAgain && mp[snake.pt[0].x - 2][snake.pt[0].y])//第二次进来时可以靠着蛇身走 return false; Point tempPoint; tempPoint.x = snake.pt[0].x - 1; tempPoint.y = snake.pt[0].y; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool AIWanderSearch2(bool isTryAgain) { InitMap(); if (snake.pt[0].x + 1 > REGION_WIDTH / SNAKE_DRAW_SIZE - 2) return false; if (mp[snake.pt[0].x + 1][snake.pt[0].y]) return false; if (!isTryAgain && mp[snake.pt[0].x + 2][snake.pt[0].y]) return false; Point tempPoint; tempPoint.x = snake.pt[0].x + 1; tempPoint.y = snake.pt[0].y; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool AIWanderSearch3(bool isTryAgain) { InitMap(); if (snake.pt[0].y < 2) return false; if (mp[snake.pt[0].x][snake.pt[0].y - 1]) return false; if (!isTryAgain && mp[snake.pt[0].x][snake.pt[0].y - 2]) return false; Point tempPoint; tempPoint.x = snake.pt[0].x; tempPoint.y = snake.pt[0].y - 1; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool AIWanderSearch4(bool isTryAgain) { InitMap(); if (snake.pt[0].y + 1 > REGION_HEIGHT / SNAKE_DRAW_SIZE - 2) return false; if (mp[snake.pt[0].x][snake.pt[0].y + 1]) return false; if (!isTryAgain && mp[snake.pt[0].x][snake.pt[0].y + 2]) return false; Point tempPoint; tempPoint.x = snake.pt[0].x; tempPoint.y = snake.pt[0].y + 1; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool AISearchFourCorner(int x, int y) { InitMap(); Point tempPoint; tempPoint.x = x; tempPoint.y = y; if (tempPoint.x == snake.pt[0].x && tempPoint.y == snake.pt[0].y) nCurChaseTailTimes = 0; if (mp[tempPoint.x][tempPoint.x]) return false; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool IsEatFoodSafe() { if (food.fpt.y == 0 && mp[food.fpt.x][food.fpt.y + 1]) { for (int i = 0; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) if (mp[i][food.fpt.y]) return false; } if (food.fpt.y == REGION_HEIGHT / SNAKE_DRAW_SIZE - 1 && mp[food.fpt.x][REGION_HEIGHT / SNAKE_DRAW_SIZE - 2]) { for (int i = 0; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) if (mp[i][food.fpt.y]) return false; } if (food.fpt.x == 0 && mp[food.fpt.x + 1][food.fpt.y]) { for (int i = 0; i < REGION_HEIGHT / SNAKE_DRAW_SIZE; i++) if (mp[food.fpt.x][i]) return false; } if (food.fpt.x == REGION_WIDTH / SNAKE_DRAW_SIZE - 1 && mp[REGION_WIDTH / SNAKE_DRAW_SIZE - 2][food.fpt.y]) { for (int i = 0; i < REGION_HEIGHT / SNAKE_DRAW_SIZE; i++) if (mp[food.fpt.x][i]) return false; } if (mp[food.fpt.x - 1][food.fpt.y] && mp[food.fpt.x + 1][food.fpt.y]) { for (int i = 0; i < REGION_HEIGHT / SNAKE_DRAW_SIZE; i++) if (mp[food.fpt.x][i]) return false; } if (mp[food.fpt.x][food.fpt.y - 1] && mp[food.fpt.x][food.fpt.y + 1]) { for (int i = 0; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) if (mp[i][food.fpt.y]) return false; } return true; } bool IsGoLeftBetter() {//是否开启大方向往左的模式 InitMap(); if (snake.pt[0].x == 0) return false; if (snake.pt[0].x == REGION_WIDTH / SNAKE_DRAW_SIZE - 1) return true; int nBlockLeft = 0; for (int i = snake.pt[0].x - 1; i >= 0; i--) { if (mp[i][snake.pt[0].y]) { nBlockLeft = i; break; } } if (nBlockLeft > 0 && snake.pt[0].x - nBlockLeft < 4) return false; int nBlockRight = REGION_WIDTH / SNAKE_DRAW_SIZE - 1; for (int i = snake.pt[0].x + 1; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) { if (mp[i][snake.pt[0].y]) { nBlockRight = i; break; } } if (nBlockRight < REGION_WIDTH / SNAKE_DRAW_SIZE - 1 && nBlockRight - snake.pt[0].x < 4) return true; int nCntLeft = 0; int nCntRight = 0; for (int i = snake.pt[0].x; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++)//统计右边个数 { for (int j = 0; j < REGION_HEIGHT / SNAKE_DRAW_SIZE; j++) { if (mp[i][j]) nCntRight++; } } int nPerRightCell = (REGION_WIDTH / SNAKE_DRAW_SIZE) * (REGION_WIDTH / SNAKE_DRAW_SIZE - snake.pt[0].x) / nCntRight; for (int i = 0; i <= snake.pt[0].x; i++)//统计左边个数 { for (int j = 0; j < REGION_HEIGHT / SNAKE_DRAW_SIZE; j++) { if (mp[i][j]) nCntLeft++; } } int nPerLeftCell = (REGION_WIDTH / SNAKE_DRAW_SIZE) * (snake.pt[0].x + 1) / nCntLeft; return nPerLeftCell > nPerRightCell; } bool IsGoUpBetter() { if (snake.pt[0].y == 0) return false; if (snake.pt[0].y == REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) return true; int upPoint = 0; for (int i = snake.pt[0].y - 1; i >= 0; i--)//往上找能到达的点 { if (mp[snake.pt[0].x][i]) { upPoint = i; break; } } int downPoint = REGION_HEIGHT / SNAKE_DRAW_SIZE - 1; for (int i = snake.pt[0].y + 1; i < REGION_HEIGHT / SNAKE_DRAW_SIZE; i++) { if (mp[snake.pt[0].x][i]) { downPoint = i; break; } } if (snake.pt[0].y - upPoint > downPoint - snake.pt[0].y) return true; return false; } bool IsLeftDeadWay(int x, int y) { if (mp[x - 1][y] || (x >= 2 && mp[x - 2][y])) return true; return false; } bool IsRightDeadWay(int x, int y) { if (mp[x + 1][y] || (x <= REGION_WIDTH / SNAKE_DRAW_SIZE - 3 && mp[x + 2][y])) return true; return false; } bool IsGoDownDeadWay(int x, int y) { if (x < 1 || x > REGION_WIDTH / SNAKE_DRAW_SIZE - 2) return false; InitMap(); int nCnt = 0; bool IsOtherPointThisColumn = false; for (int i = y + 1; i < REGION_HEIGHT / SNAKE_DRAW_SIZE; i++) { if (IsLeftDeadWay(x, i) && IsRightDeadWay(x, i)) nCnt++; if (mp[x][i]) IsOtherPointThisColumn = true; } if (IsOtherPointThisColumn && nCnt > 1) return true; return false; } bool IsGoUpDeadWay(int x, int y) { if (x < 1 || x > REGION_WIDTH / SNAKE_DRAW_SIZE - 2) return false; InitMap(); int nCnt = 0; bool IsOtherPointThisColumn = false; for (int i = 0; i < y; i++) { if (IsLeftDeadWay(x, i) && IsRightDeadWay(x, i)) nCnt++; if (mp[x][i]) IsOtherPointThisColumn = true; } if (IsOtherPointThisColumn && nCnt > 1) return true; return false; } bool MustWinModeGoDown() { InitMap(); Point tempPoint; tempPoint.x = snake.pt[0].x; tempPoint.y = snake.pt[0].y + 1; if (mp[tempPoint.x][tempPoint.y]) return false; if (tempPoint.y > REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) return false; if (IsGoDownDeadWay(tempPoint.x, tempPoint.y)) return false; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool MustWinModeGoUp() { InitMap(); Point tempPoint; tempPoint.x = snake.pt[0].x; tempPoint.y = snake.pt[0].y - 1; if (mp[tempPoint.x][tempPoint.y]) return false; if (tempPoint.y < 0) return false; if (IsGoUpDeadWay(tempPoint.x, tempPoint.y)) return false; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool MustWinModeGoLeft() { InitMap(); Point tempPoint; tempPoint.x = snake.pt[0].x - 1; tempPoint.y = snake.pt[0].y; if (tempPoint.x < 0 || mp[tempPoint.x][tempPoint.y]) return false; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool MustWinModeGoRight() { InitMap(); Point tempPoint; tempPoint.x = snake.pt[0].x + 1; tempPoint.y = snake.pt[0].y; if (tempPoint.x > REGION_WIDTH / SNAKE_DRAW_SIZE - 1 || mp[tempPoint.x][tempPoint.y]) return false; if (!SearchSnakePath(snake.pt[0], tempPoint)) return false; PushPath(snake.pt[0], tempPoint); AIRealChangeDirection(); return true; } bool IsSnakeAdjustOk() { InitMap(); int nCnt[REGION_WIDTH / SNAKE_DRAW_SIZE + 1] = { 0 }; for (int i = 0; i < snake.nCount; i++) nCnt[snake.pt[i].x]++; int nonZeroCnt = 0; for (int i = 0; i < REGION_WIDTH / SNAKE_DRAW_SIZE; i++) { if (nCnt[i] > 0) nonZeroCnt++; } if (nonZeroCnt <= snake.nCount / (REGION_HEIGHT / SNAKE_DRAW_SIZE - 2) + 2) return true; int nEdgePoint = 0; for (int i = 0; i < snake.nCount; i++) { if (snake.pt[i].x == 0 || snake.pt[i].x == REGION_WIDTH / SNAKE_DRAW_SIZE - 1 || snake.pt[i].y == 0 || snake.pt[i].y == REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) nEdgePoint++; } if (nEdgePoint > snake.nCount * 3 / 4) return true; return false; } bool StartMustWinStrategy() { if (bIsAdjustOk) return false; bIsAdjustOk = IsSnakeAdjustOk(); if (snake.pt[0].y == 0 || snake.pt[0].y == REGION_HEIGHT / SNAKE_DRAW_SIZE - 1 || (snake.pt[0].y == 1 && mp[snake.pt[0].x][snake.pt[0].y + 1]) || (snake.pt[0].y == REGION_HEIGHT / SNAKE_DRAW_SIZE - 2 && mp[snake.pt[0].x][snake.pt[0].y - 1])) { if (IsGoLeftBetter()) { if (MustWinModeGoLeft() || MustWinModeGoRight()) return true; } else { if (MustWinModeGoRight() || MustWinModeGoLeft()) return true; } if (IsGoUpBetter()) { if (MustWinModeGoUp() || MustWinModeGoDown()) return true; } else { if (MustWinModeGoDown() || MustWinModeGoUp()) return true; } } else { if (IsGoUpBetter()) { if (MustWinModeGoUp() || MustWinModeGoDown()) return true; } else { if (MustWinModeGoDown() || MustWinModeGoUp()) return true; } if (IsGoLeftBetter()) { if (MustWinModeGoLeft() || MustWinModeGoRight()) return true; } else { if (MustWinModeGoRight() || MustWinModeGoLeft()) return true; } } return false; } void AIChangeDir() { if (pattern != EmPattern::emIntelligencePattern) return; if (bUserInput) return; if (snake.nCount > MAX_YOUNG_LEN) if (StartMustWinStrategy()) return; if (AISearchBigFood()) return; if (AISearchSmallFood()) return; if (nCurChaseTailTimes > snake.nCount) { int nRand = rand() % 4; if (nRand == 0 && AISearchFourCorner(1, 1)) { nCurChaseTailTimes -= 100; return; } if (nRand == 1 && AISearchFourCorner(1, REGION_HEIGHT / SNAKE_DRAW_SIZE - 2)) { nCurChaseTailTimes -= 100; return; } if (nRand == 2 && AISearchFourCorner(REGION_WIDTH / SNAKE_DRAW_SIZE - 2, REGION_HEIGHT / SNAKE_DRAW_SIZE - 2)) { nCurChaseTailTimes -= 100; return; } if (nRand == 3 && AISearchFourCorner(REGION_WIDTH / SNAKE_DRAW_SIZE - 2, 1)) { nCurChaseTailTimes -= 100; return; } } if (AISearchNearTail()) return; if (AIWanderSearch1()) return; if (AIWanderSearch2()) return; if (AIWanderSearch3()) return; if (AIWanderSearch4()) return; if (AIWanderSearch1(true)) return; if (AIWanderSearch2(true)) return; if (AIWanderSearch3(true)) return; if (AIWanderSearch4(true)) return; } void SnakeMove() { for (int i = snake.nCount; i > 0; i--) { snake.pt[i].x = snake.pt[i - 1].x; snake.pt[i].y = snake.pt[i - 1].y; } AIChangeDir(); switch (snake.dir) { case EmDir::emDirUp: snake.pt[0].y--; break; case EmDir::emDirDown: snake.pt[0].y++; break; case EmDir::emDirLeft: snake.pt[0].x--; break; case EmDir::emDirRight: snake.pt[0].x++; break; default: break; } bUserInput = false; } void DecideHeadDirection() { if (snake.pt[0].y == snake.pt[1].y && snake.pt[0].x > snake.pt[1].x)//头往右走 DrawSnakeHead(0); else if (snake.pt[0].y == snake.pt[1].y && snake.pt[0].x < snake.pt[1].x)//头往左走 DrawSnakeHead(1); else if (snake.pt[0].x == snake.pt[1].x && snake.pt[0].y < snake.pt[1].y)//头往上走 DrawSnakeHead(2); else if (snake.pt[0].x == snake.pt[1].x && snake.pt[0].y > snake.pt[1].y)//头往下走 DrawSnakeHead(3); } void DrawSnakeHead(int nIndex) { IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG2 + nIndex), SNAKE_DRAW_SIZE, SNAKE_DRAW_SIZE); putimage(snake.pt[0].x * SNAKE_DRAW_SIZE, snake.pt[0].y * SNAKE_DRAW_SIZE, &img); } void DecideCornerDirection(int idx) { if (snake.pt[idx].y > snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x && snake.pt[idx].y == snake.pt[idx + 1].y && snake.pt[idx].x > snake.pt[idx + 1].x) DrawCorner(0, idx);//右->上 else if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x > snake.pt[idx - 1].x && snake.pt[idx].y > snake.pt[idx + 1].y && snake.pt[idx].x == snake.pt[idx + 1].x) DrawCorner(0, idx);//下->左 else if (snake.pt[idx].y > snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x && snake.pt[idx].y == snake.pt[idx + 1].y && snake.pt[idx].x < snake.pt[idx + 1].x) DrawCorner(1, idx);//左->上 else if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x < snake.pt[idx - 1].x && snake.pt[idx].y > snake.pt[idx + 1].y && snake.pt[idx].x == snake.pt[idx + 1].x) DrawCorner(1, idx);//下->右 else if (snake.pt[idx].y < snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x && snake.pt[idx].y == snake.pt[idx + 1].y && snake.pt[idx].x > snake.pt[idx + 1].x) DrawCorner(2, idx);//右->下 else if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x > snake.pt[idx - 1].x && snake.pt[idx].y < snake.pt[idx + 1].y && snake.pt[idx].x == snake.pt[idx + 1].x) DrawCorner(2, idx);//上->左 else if (snake.pt[idx].y < snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x && snake.pt[idx].y == snake.pt[idx + 1].y && snake.pt[idx].x < snake.pt[idx + 1].x) DrawCorner(3, idx);//左->下 else if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x < snake.pt[idx - 1].x && snake.pt[idx].y < snake.pt[idx + 1].y && snake.pt[idx].x == snake.pt[idx + 1].x) DrawCorner(3, idx);//上->右 else DecideBodyDirection(idx);//不是corner的情况在考虑body } void DrawCorner(int nIndex, int idx) { IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG6 + nIndex), SNAKE_DRAW_SIZE, SNAKE_DRAW_SIZE); putimage(snake.pt[idx].x * SNAKE_DRAW_SIZE, snake.pt[idx].y * SNAKE_DRAW_SIZE, &img); } void DecideBodyDirection(int idx) { if (snake.pt[idx].x == snake.pt[idx - 1].x || snake.pt[idx].x == snake.pt[idx + 1].x)//上下 DrawBody(0, idx); else if (snake.pt[idx].y == snake.pt[idx - 1].y || snake.pt[idx].y == snake.pt[idx + 1].y)//左右 DrawBody(1, idx); } void DrawBody(int nIndex, int idx) { IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG10 + nIndex), SNAKE_DRAW_SIZE, SNAKE_DRAW_SIZE); putimage(snake.pt[idx].x * SNAKE_DRAW_SIZE, snake.pt[idx].y * SNAKE_DRAW_SIZE, &img); } void DecideTailDirection() { int idx = snake.nCount - 1; if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x < snake.pt[idx - 1].x)//往右 DrawTail(0, idx); else if (snake.pt[idx].y == snake.pt[idx - 1].y && snake.pt[idx].x > snake.pt[idx - 1].x)//往左 DrawTail(1, idx); else if (snake.pt[idx].y > snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x)//往上 DrawTail(2, idx); else if (snake.pt[idx].y < snake.pt[idx - 1].y && snake.pt[idx].x == snake.pt[idx - 1].x)//往下 DrawTail(3, idx); } void DrawTail(int nIndex, int idx) { IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG12 + nIndex), SNAKE_DRAW_SIZE, SNAKE_DRAW_SIZE); putimage(snake.pt[idx].x * SNAKE_DRAW_SIZE, snake.pt[idx].y * SNAKE_DRAW_SIZE, &img); } void DrawSnake() { for (int i = 0; i < snake.nCount; i++) { if (0 == i) DecideHeadDirection(); else if (i == snake.nCount - 1) DecideTailDirection(); else DecideCornerDirection(i); } } int IsEatBigFood() { if (1 == bigFood.isEat) return 0; for (int i = bigFood.fpt.x; i < bigFood.fpt.x + 3; i++) { for (int j = bigFood.fpt.y; j < bigFood.fpt.y + 3; j++) { if (snake.pt[0].x == i && snake.pt[0].y == j) return 1; } } return 0; } void LevelUp() { if (pattern == EmPattern::emTimeLimitedPattern) return; //WCHAR szLevelUp[32]; if (nCurScore > arrScore[nCurLevel]) { //swprintf_s(szLevelUp, L"恭喜你,升到第%d级", nCurLevel + 1); //::MessageBox(0, szLevelUp, L"升级啦", 0); nCurLevel++; if (nCurSpeed > 0) nCurSpeed -= MINUS_SPEED; } } void EatFood() { if (snake.pt[0].x == food.fpt.x && snake.pt[0].y == food.fpt.y) { nCurScore += FOOD_SCORE; snake.nCount++; food.isEat = 1; bIsAdjustOk = false; ProduceBigFood(); } if (IsEatBigFood()) { nCurScore += BIG_FOOD_SCORE; snake.nCount++; bigFood.isEat = 1; bIsAdjustOk = false; } LevelUp(); } int IsFoodPosOk(int x, int y) { for (int i = 0; i < snake.nCount; i++) { if (snake.pt[i].x == x && snake.pt[i].y == y) return 0; } if (0 == bigFood.isEat) { for (int i = bigFood.fpt.x; i < bigFood.fpt.x + 3; i++) { for (int j = bigFood.fpt.y; j < bigFood.fpt.y + 3; j++) { if (x == i && y == j) return 0; } } } return 1; } int IsBigFoodPosOk(int x, int y) { for (int i = x; i < x + 3; i++) { for (int j = y; j < y + 3; j++) { if (i < 0 || i > REGION_WIDTH / SNAKE_DRAW_SIZE - 1 || j < 0 || j > REGION_HEIGHT / SNAKE_DRAW_SIZE - 1) return 0; for (int k = 0; k < snake.nCount; k++) { if (snake.pt[k].x == i && snake.pt[k].y == j) return 0; } } } return 1; } void ProduceFood() { if (0 == food.isEat) return; while (1) { food.fpt.x = rand() % (REGION_WIDTH / SNAKE_DRAW_SIZE); food.fpt.y = rand() % (REGION_HEIGHT / SNAKE_DRAW_SIZE); if (IsFoodPosOk(food.fpt.x, food.fpt.y)) break; } food.isEat = 0; } void DrawFood() { IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG1), SNAKE_DRAW_SIZE, SNAKE_DRAW_SIZE); putimage(food.fpt.x * SNAKE_DRAW_SIZE, food.fpt.y * SNAKE_DRAW_SIZE, &img); } int ProduceBigFood() { if (0 == bigFood.isEat)//大食物没被吃掉,不产生 return 0; if (rand() % 2 == 0) { while (1) { bigFood.fpt.x = rand() % (REGION_WIDTH / SNAKE_DRAW_SIZE); bigFood.fpt.y = rand() % (REGION_HEIGHT / SNAKE_DRAW_SIZE); if (IsBigFoodPosOk(bigFood.fpt.x, bigFood.fpt.y)) break; } bigFood.isEat = 0; return 1; } return 0; } void DrawBigFood() { if (1 == bigFood.isEat) return; IMAGE img; loadimage(&img, L"jpg", MAKEINTRESOURCE(IDR_JPG1), SNAKE_DRAW_SIZE * 3, SNAKE_DRAW_SIZE * 3); putimage(bigFood.fpt.x * SNAKE_DRAW_SIZE, bigFood.fpt.y * SNAKE_DRAW_SIZE, &img); } int main() { HWND hWnd = GetConsoleWindow(); SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1))); initgraph(WND_WIDTH, WND_HEIGHT); srand((unsigned int)time(NULL)); InitFirstScene(); getchar(); closegraph(); return 0; }运行结果:
