说明:
在贪吃蛇智能版(中级)的基础之上,增加了判断小食物是否安全的方法,并且增加了在寻找食物路径失败和寻找尾巴失败之后,会进行一小段的随机溜达,直到重新找到路径为止,当然这段溜达会有一定风险,这个在后面会想办法改进,再改进的版本希望能更上一层楼,姑且叫做专家版吧。
参考代码:
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
{
pa