字符游戏-智能蛇的学习

2023-11-12

目标:实现可以智能化移动,不撞墙,自由追寻果实的贪吃蛇程序(即拥有感知、决策、行动的能力)。
学习过程:根据index中sin曲线的绘制过程可知我们可以知道可以用while循环反复打印的方式达到刷屏的效果,这样,我们将贪吃蛇移动的每一步都单独打印出来即可得到其自由移动的效果,同时加入if语句(即限制效果,例如蛇头即将与边界重合时转向、蛇头与果实重合时贪吃蛇加长且果实随机出现在另一处)。
具体实施有

#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();

#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);//上->右
    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;
        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; }

实验结果:
这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字符游戏-智能蛇的学习 的相关文章

  • 【Python小游戏】当当当当 万众瞩目得《滑雪大冒险》来啦~(附源码)

    前文 大家好 我是梨子同学 希望大家多多支持我 哈哈 为了感谢每一个关注我的小可爱 每篇文章的项目源码都是无偿分享滴 见文末 很多csdn的功能还在研究中 还有小编的文笔不好勿怪 会慢慢进步跟大家一起学习的 小编也一直在学习编程 如果代码小
  • 超级等级福利礼包

    文章目录 一 介绍 二 设计等级礼包的目的 1 提升游戏玩家活跃度 2 提升游戏用户吸引力 3 提高游戏用户留存率 4 实现间接收入 5 持续营收 三 玩家心理总结 四 总结该模式的赢利点 五 该模式的应用场景举例 一 介绍 超级等级福利礼
  • 编码 & 8421BCD 码的故事

    计算机编码中 我们都是先了解了二进制 其中分有符号数 无符号数 然后会接触到BCD码 那么BCD码是怎么产生的 为什么又要用四位二进制来表示呢 8421BCD 码的故事 一 BCD码 1 由来 2 8421BCD码 3 修正 二 底层验证修
  • Python——报数出圈

    编写程序 模拟报数游戏 有n个人围成一圈 顺序编号 从第一个人开始从1到k 假设k 3 报数 报到k的人退出圈子 然后圈子缩小 从下一个人继续游戏 问最后留下的是原来的第几号 n int input 请输入总人数 n k int input
  • 【PDF】PDF无法注释的一种解决方案

    PDF无法注释 需要检查 1 权限问题 2 文档规范问题 PDF A 拓展阅读 浏览器打开PDF调整亮度和颜色的小技巧 处理pdf 文档的相关功能包总结 1 pdf文档不能注释 下载的一篇pdf文档在阅读时不能注释 高亮和打字机等选项都是灰
  • Java基础之随机生成数字和字母

    原文地址 http blog csdn net yaodong y article details 8115250 字母与数字的ASCII码 目 前计算机中用得最广泛的 字符集及其编码 是由美国国家标准局 ANSI 制定的ASCII码 Am
  • 俄罗斯方块游戏(C语言)

    简介 俄罗斯方块 Tetris 是一款经典的游戏 下面是用C语言实现俄罗斯方块的示例代码 code include
  • 基于java的俄罗斯方块游戏系统设计与实现

    基于java的俄罗斯方块游戏系统设计与实现 I 引言 A 研究背景和动机 基于Java的俄罗斯方块游戏系统设计与实现的研究背景和动机 俄罗斯方块是一种经典的益智游戏 游戏规则简单 但难度较大 需要玩家有良好的计算能力和手眼协调能力 近年来
  • 基于java的飞机大战游戏系统设计与实现

    基于java的飞机大战游戏系统设计与实现 I 引言 A 研究背景和动机 背景 随着现代游戏产业的不断发展 传统的飞行射击游戏已经无法满足玩家对新颖 刺激的需求 因此 设计一个基于Java的飞机大战游戏系统成为了游戏开发人员们的共同目标 动机
  • 运行游戏找不到x3daudio1_7.dll怎么解决?教你如何快速修复的教程

    在计算机使用过程中 我们经常会遇到一些错误提示 其中之一就是 x3daudio1 7 dll丢失 这个错误提示可能让我们感到困惑和烦恼 但是不用担心 本文将为您介绍x3daudio1 7 dll丢失的原因以及五种修复方法 帮助您解决这个问题
  • 揭开神秘面纱,探索犹格索托斯的庭院:一款令人陶醉的模拟经营+AVG游戏

    你是否曾梦想过踏入一个充满神秘与奇幻的世界 体验一番独特的冒险 现在 这个梦想将成为现实 我们荣幸地向你介绍一款全新的模拟经营 AVG游戏 犹格索托斯的庭院 犹格索托斯的庭院是一款极具创意的游戏 它将带你进入一个神秘而充满魅力的世界 在这里
  • 计算机提示vcruntime140.dll丢失的解决方法,多种修复教程分享

    vcruntime140 dll是一个非常重要的动态链接库文件 它包含了许多运行时的函数和类 然而 有时候我们可能会遇到vcruntime140 dll无法继续执行代码的问题 这会给我们带来很大的困扰 那么 这个问题是什么原因导致的呢 又应
  • 如何有效获取APP新增用户

    在提升APP用户获取效果方面 有几个关键策略可以考虑 市场定位与目标用户明确 在推广过程中 确保清晰地了解你的目标用户是谁 以便有针对性地开展推广活动 对用户的需求和偏好有深入了解 可以更好地制定吸引用户的策略 引人入胜的营销策略 设计有吸
  • 揭开神秘面纱,探索犹格索托斯的庭院:一款令人陶醉的模拟经营+AVG游戏

    你是否曾梦想过踏入一个充满神秘与奇幻的世界 体验一番独特的冒险 现在 这个梦想将成为现实 我们荣幸地向你介绍一款全新的模拟经营 AVG游戏 犹格索托斯的庭院 犹格索托斯的庭院是一款极具创意的游戏 它将带你进入一个神秘而充满魅力的世界 在这里
  • 游戏被攻击了要怎么办

    有客户反馈刚上线新款游戏 没两天就被攻击了 导致用户无法登录 来咨询到我们这边能不能帮他解决 今天就来分享下 怎么预防游戏攻击和已经被攻击的游戏服务器该怎么处理 服务器不管是个人还是企业 被攻击的都有 在所难免 特别是新上线时候要承受住外来
  • 基于java的扫雷游戏系统设计与实现

    基于java的扫雷游戏系统设计与实现 I 引言 A 研究背景和动机 扫雷游戏是一种经典的益智游戏 由于其简单易学 规则简单 玩法多样等特点 深受广大游戏爱好者的喜爱 但是 现有的扫雷游戏系统往往存在着游戏难度不均衡 游戏时间过长 游戏规则不
  • U3D游戏开发中摇杆的制作(UGUI版)

    在PC端模拟摇杆 实现玩家通过控制摇杆让玩家移动 以下是完整代码 using System Collections using System Collections Generic using UnityEngine using Unity
  • U3D游戏开发中摇杆的制作(NGUI版)

    在PC端模拟摇杆 实现控制摇杆让玩家或者物体移动 以下是完整代码 using System Collections using System Collections Generic using UnityEngine public clas
  • 游戏开发常见操作梳理之NPC药品商店系统(NGUI版)

    后续会出UGUI Json的版本 敬请期待 游戏开发中经常会出现药品商店 实际操作与武器商店类似 甚至根据实际情况可以简化设置 废话不多说 直接上代码 药品商店的源码 using System Collections using Syste
  • 游戏开发常见操作梳理之小地图的制作

    游戏中一般存在小地图系统 实际上就是设置一个新的摄像机放置在玩家的正上方 然后在小地图上显示新摄像机看见的东西就可以了 在小地图上一般存在放大地图和缩小地图的按钮可以方便放大和缩小地图 这些操作是如何实现的呢 接下来直接上核心代码 usin

随机推荐

  • vue高德地图的实现 根据经纬度回显地理位

    效果图 1 首先 下载vue amap 插件 2 在main js中引入 import VueAMap from vue amap Vue use VueAMap VueAMap initAMapApiLoader key 你自己的key
  • 深度探索c++对象模型之template中的名称决议方式

    我们应该能够区分以下两种意义 一个是c standard标准中的 scope of the template definition 模板定义域 另一个是c standard标准中的 scope of the template instant
  • SpringMvc

    简述 基于Java实现Mvc模型的轻量级web框架 配置案例过程 导入maven
  • 神经网络——非线性激活

    torch官网 torch nn PyTorch 1 11 0 documentation 非线性变换的主要目的就是给网中加入一些非线性特征 非线性越多才能训练出符合各种特征的模型 常见的非线性激活 ReLU 官网给出的例子 gt gt g
  • C语言求平均成绩小程序(以五个学科为例)

    include
  • 客户好评“收割机”,NPS高达0.7, 实在RPA6.8.0重磅升级解析

    近期 实在智能大模型新品 TARS RPA Agent 发布会召开 通过底层软件架构的全新优化和全面结合大语言模型实现 超进化 持续以AI技术为RPA行业提供领先的超自动化解决方案 同时在发布会上亮相的 还有备受关注的最新版RPA产品 实在
  • buuctf MD5

    打开是一串MD5密文 md5加密后是32位的字符 也有16位的 是去除32位的前后各八位所得 由字母和数字组成 字母要么全是大写要么全是小写 MD5加密是不可逆的加密 无法解密 但是可以爆破出来 给大家推荐一个可以爆破MD5加密的网站htt
  • 小码哥学习感想第一天

    开班须知 本小节知识点 了解 课堂纪律要求 了解 上课的时间和内容安排 了解 学习方法 了解 教学思想和目标 1 课堂纪律要求 手机静音 保持安静 很容易错过精彩 关键瞬间 低调听课 尊重他人 多点反馈 多点互动 积极思考 积极回答 大家一
  • pycharm内无法激活conda虚拟环境

    仅供参考 问题描述 在pycharm终端里conda activate xxx 没报错 但是并没有激活指定的xxx虚拟环境 解决方法 检查是否已将conda加入到系统环境变量内 查找了其他教程 说conda没有加入到环境变量内 但我的已经加
  • 签好软件定制开发合同,需要注意什么

    签订好一份责权分明 细节清晰的软件定制开发合同 对于任何软件定制开发合同的双方而言都是百利无害的 尤其对于软件开发软件定制开发合同这种非常容易引起争议的项目 签订合同的时候更是要慎之又慎 前期做好充足的准备 后期才能达到一个良好的效果 那么
  • Fastapi 学习笔记之请求多个参数

    1 混合使用 Path Query 和请求体参数 from fastapi import FastAPI Path from typing import Optional from pydantic import BaseModel app
  • 人工智能-目标识别:古典目标识别、R-CNN、SPP-NET、Fast-R-CNN、Faster-R-CNN、YOLO

    古典目标识别 第一部分 训练集构造 负样本 使用 select search ss 方法对区域进行融合 gt 计算每个候选区域域真实标记区域 GRadeonTruts GT 之间的重合 如果区域A与GT的重合度在20 50 之间 而且A与其
  • Android LCD(四):LCD驱动调试篇

    关键词 android LCD TFTSN75LVDS83B TTL LVDS LCD电压背光电压平台信息 内核 linux2 6 linux3 0系统 android android4 0 平台 samsung exynos 4210 e
  • Error:Execution failed for task ‘:app:mergeDebugResources‘. > Error: java.util.concurrent.ExecutionE

    我的解决办法是 点击Gradle Scripts下的build gradle Module app 添加如下两行 aaptOptions cruncherEnabled falseaaptOptions useNewCruncher fal
  • 计算机导论 复习 第一章 计算机学什么

    一 核心知识点 1 计算系统构成 硬件 系统软件 操作系统 应用程序 软件 2 算法的特征 算法的高级程序实现方法 3 程序设计语言 机器语言 汇编语言 高级语言 4 计算机发展简史 二 选择题 1 冯 诺伊曼体系结构是现代计算机基础 被人
  • 左程云 Java 笔记--前缀树 贪心算法

    文章目录 前缀树 贪心算法 例1 字典序排序 例3 哈夫曼编码 例四 堆的一个应用 N皇后 总结 前缀树 介绍前缀树 何为前缀树 如何生成前缀树 例子 一个字符串类型的数组arr1 另一个字符串类型的数组arr2 arr2中有哪些字符 是a
  • 【Java】使用Swing组件弹窗展示九十九乘法表

    目录 一 效果展示 二 完整代码 三 代码思路 一 效果展示 直接先上效果图 二 完整代码 import java awt import javax swing public class MultiplicationTable extend
  • 从零开始 React 服务器渲染

    一 前言 当我们选择使用 Node React 的技术栈开发 Web 时 React 提供了一种优雅的方式实现服务器渲染 使用 React 实现服务器渲染有以下好处 1 利于 SEO React 服务器渲染的方案使你的页面在一开始就有一个
  • 线段树的学习

    在力扣刷题中遇到一道 我的日程安排表 的题 经过求解和资料的参考利用线段树的方法解决 以下对线段树的知识进行一个简单的总结 线段树的定义 线段树是一种二叉搜索树 与区间树相似 它将一个区间划分成一些单元区间 每个单元区间对应线段树中的一个叶
  • 字符游戏-智能蛇的学习

    目标 实现可以智能化移动 不撞墙 自由追寻果实的贪吃蛇程序 即拥有感知 决策 行动的能力 学习过程 根据index中sin曲线的绘制过程可知我们可以知道可以用while循环反复打印的方式达到刷屏的效果 这样 我们将贪吃蛇移动的每一步都单独打