예제 소스
인베이더 게임으로 배우는 휴리스틱과 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