贪吃蛇智能版(高级)

本文在贪吃蛇智能版(中级)的基础上,介绍了如何判断小食物的安全性,并在寻路失败后让蛇进行随机移动,以重新找到路径。此策略存在风险,后续计划进一步优化,目标打造专家级版本。
摘要由CSDN通过智能技术生成

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

参考代码:
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
Snake-AI,这是一个用 C/C 语言编写的贪吃蛇游戏的人工智能。AI 的目的是让蛇尽可能的吃更多的食物,直到吃满整个地图。想参与这个项目,请查看todos。Demo使用方法编译与运行:$ make $ make run为了解详细使用方法, 请查看主函数main()算法介绍函数Snake.decideNext(): 计算蛇S1的下一个移动方向D计算从蛇S1的头部到达食物的最短路径P1。派一条与蛇S1完全一样的虚拟蛇S2沿路径P1吃掉食物。计算从蛇S2的头部到其尾部的最长路径P2。如果路径P2存在,将移动方向D设置为路径P1的第一个方向,否则进行步骤4。计算从蛇S1的头部到达其尾部的最长路径P3。如果P3存在,将移动方向D设置为路径P3的第一个方向,否则进行步骤5。将移动方向D设置为离食物最远的方向。函数Map.findMinPath(): 计算两个位置间的最短路径算法建立在BFS的基础上。为了使路径尽可能直,每次遍历邻接点时,在当前移动方向上的位置会被优先遍历。效果展示:(绿色区域为搜索算法扫描到的区域,红色区域为最后计算出的最短路径,每个位置上的数字表示了从起始位置开始到该位置的最短距离)函数Map.findMaxPath(): 计算两个位置间的最长路径算法建立在DFS与贪心算法的基础上。每次遍历邻接点时,离目标位置最远(使用曼哈顿距离估计)的位置将会被优先遍历到。另外,为了使路径尽可能直,如果两个位置到目标位置的距离相等,在当前移动方向上的位置将被优先遍历到。这个问题是一个NP完全问题,此算法得出的结果路径只是一个近似最长路径。效果展示:(绿色区域为搜索算法扫描到的区域,红色区域为最后计算出的最长路径,每个位置上的数字表示了从该位置开始到目标位置的估计距离) 标签:Snake
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值