게시판인베이더 게임으로 배우는 휴리스틱과 AI 브리지예제 소스

예제 소스

인베이더 게임으로 배우는 휴리스틱과 AI 브리지 · 파일 17개

aiplayer.cpp

#include "aiplayer.h"

#include <QPoint>
#include <QtGlobal>
#include <limits>

namespace AiPlayer {

using namespace Invader;

namespace {

bool bulletThreatNearX(const GameEngine &g, int px)
{
    const QRect pr = g.playerRect();
    for (const Bullet &b : g.bullets()) {
        if (b.fromPlayer)
            continue;
        if (b.rect.bottom() < pr.top() - 90)
            continue;
        if (qAbs(b.rect.center().x() - px) <= 14)
            return true;
    }
    return false;
}

int bestAlienX(const GameEngine &g)
{
    const QRect pr = g.playerRect();
    const int px = pr.center().x();
    int bestX = px;
    int bestScore = std::numeric_limits<int>::min();
    for (const QRect &a : g.alienRects()) {
        // 아래쪽/가까운 x 가 우선 (맞추기 쉬움)
        const int dy = a.y();
        const int dx = qAbs(a.center().x() - px);
        const int score = dy * 3 - dx;
        if (score > bestScore) {
            bestScore = score;
            bestX = a.center().x();
        }
    }
    return bestX;
}

bool alienAboveX(const GameEngine &g, int px)
{
    const QRect pr = g.playerRect();
    for (const QRect &a : g.alienRects()) {
        if (qAbs(a.center().x() - px) <= 14 && a.bottom() < pr.top())
            return true;
    }
    return false;
}

int countPlayerBullets(const GameEngine &g)
{
    int n = 0;
    for (const Bullet &b : g.bullets()) {
        if (b.fromPlayer)
            ++n;
    }
    return n;
}

} // namespace

PlayerAction suggestAction(const GameEngine &game)
{
    const QRect pr = game.playerRect();
    const int px = pr.center().x();

    if (game.status() == GameStatus::Intermission) {
        const int targetX = bestAlienX(game);
        if (targetX < px - 6)
            return PlayerAction::Left;
        if (targetX > px + 6)
            return PlayerAction::Right;
        return PlayerAction::None;
    }

    if (bulletThreatNearX(game, px)) {
        if (px > 40 && !bulletThreatNearX(game, px - 28))
            return PlayerAction::Left;
        if (px < kWorldW - 40 && !bulletThreatNearX(game, px + 28))
            return PlayerAction::Right;
        if (px > kWorldW / 2)
            return PlayerAction::Left;
        return PlayerAction::Right;
    }

    const int targetX = bestAlienX(game);
    if (targetX < px - 6)
        return PlayerAction::Left;
    if (targetX > px + 6)
        return PlayerAction::Right;

    if (countPlayerBullets(game) < game.maxPlayerBullets() && alienAboveX(game, px))
        return PlayerAction::Fire;

    return PlayerAction::None;
}

} // namespace AiPlayer