说明:
在贪吃蛇智能版(中级)的基础之上,增加了判断小食物是否安全的方法,并且增加了在寻找食物路径失败和寻找尾巴失败之后,会进行一小段的随机溜达,直到重新找到路径为止,当然这段溜达会有一定风险,这个在后面会想办法改进,再改进的版本希望能更上一层楼,姑且叫做专家版吧。
参考代码:
easysnake.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 110
#define MINUS_SPEED 10#define TOTAL_TIME 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, 8, 16, 24, 32, 40, 48, 60, 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;//最大追尾长度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();
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;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"时间到", 0);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"游戏失败", 0);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"游戏失败", 0);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;
}void AIChangeDir()
{if (pattern != EmPattern::emIntelligencePattern)return;if (bUserInput)return;if (AISearchBigFood())return;if (AISearchSmallFood())return;if (nCurChaseTailTimes > snake.nCount){int nRand = rand() % 4;if (nRand == 0 && AISearchFourCorner(1, 1)){nRand -= 100;return;}if (nRand == 1 && AISearchFourCorner(1, REGION_HEIGHT / SNAKE_DRAW_SIZE - 2)){nRand -= 100;return;}if (nRand == 2 && AISearchFourCorner(REGION_WIDTH / SNAKE_DRAW_SIZE - 2, REGION_HEIGHT / SNAKE_DRAW_SIZE - 2)){nRand -= 100;return;}if (nRand == 3 && AISearchFourCorner(REGION_WIDTH / SNAKE_DRAW_SIZE - 2, 1)){nRand -= 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);//上->右elseDecideBodyDirection(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();elseDecideCornerDirection(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;ProduceBigFood();}if (IsEatBigFood()){nCurScore += BIG_FOOD_SCORE;snake.nCount++;bigFood.isEat = 1;}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;
}
运行结果: