void POCMAN::MoveGhostDefensive(POCMAN_STATE& pocstate, int g) const { if (Bernoulli(DefensiveSlip) && pocstate.GhostDir[g] >= 0) { pocstate.GhostDir[g] = -1; return; } int bestDist = 0; COORD bestPos = pocstate.GhostPos[g]; int bestDir = -1; for (int dir = 0; dir < 4; dir++) { int dist = COORD::DirectionalDistance( pocstate.PocmanPos, pocstate.GhostPos[g], dir); COORD newpos = NextPos(pocstate.GhostPos[g], dir); if (dist >= bestDist && newpos.Valid() && COORD::Opposite(dir) != pocstate.GhostDir[g]) { bestDist = dist; bestPos = newpos; } } pocstate.GhostPos[g] = bestPos; pocstate.GhostDir[g] = bestDir; }
void POCMAN::GeneratePreferred(const STATE& state, const HISTORY& history, vector<int>& actions, const STATUS& status) const { const POCMAN_STATE& pocstate = safe_cast<const POCMAN_STATE&>(state); if (history.Size()) { int action = history.Back().Action; int observation = history.Back().Observation; // If power pill and can see a ghost then chase it if (pocstate.PowerSteps > 0 && (observation & 15 != 0)) { for (int a = 0; a < 4; ++a) if (CheckFlag(observation, a)) actions.push_back(a); } // Otherwise avoid observed ghosts and avoid changing directions else { for (int a = 0; a < 4; ++a) { COORD newpos = NextPos(pocstate.PocmanPos, a); if (newpos.Valid() && !CheckFlag(observation, a) && COORD::Opposite(a) != action) actions.push_back(a); } } } }
void POCMAN::MoveGhostAggressive(POCMAN_STATE& pocstate, int g) const { if (!Bernoulli(ChaseProb)) { MoveGhostRandom(pocstate, g); return; } int bestDist = Maze.GetXSize() + Maze.GetYSize(); COORD bestPos = pocstate.GhostPos[g]; int bestDir = -1; for (int dir = 0; dir < 4; dir++) { int dist = COORD::DirectionalDistance( pocstate.PocmanPos, pocstate.GhostPos[g], dir); COORD newpos = NextPos(pocstate.GhostPos[g], dir); if (dist <= bestDist && newpos.Valid() && COORD::Opposite(dir) != pocstate.GhostDir[g]) { bestDist = dist; bestPos = newpos; } } pocstate.GhostPos[g] = bestPos; pocstate.GhostDir[g] = bestDir; }
void POCMAN::GenerateLegal(const STATE& state, const HISTORY& history, vector<int>& legal, const STATUS& status) const { const POCMAN_STATE& pocstate = safe_cast<const POCMAN_STATE&>(state); // Don't move into walls for (int a = 0; a < 4; ++a) { COORD newpos = NextPos(pocstate.PocmanPos, a); if (newpos.Valid()) legal.push_back(a); } }
void POCMAN::MoveGhostRandom(POCMAN_STATE& pocstate, int g) const { // Never switch to opposite direction // Currently assumes there are no dead-ends. COORD newpos; int dir; do { dir = Random(4); newpos = NextPos(pocstate.GhostPos[g], dir); } while (COORD::Opposite(dir) == pocstate.GhostDir[g] || !newpos.Valid()); pocstate.GhostPos[g] = newpos; pocstate.GhostDir[g] = dir; }
int POCMAN::MakeObservations(const POCMAN_STATE& pocstate) const { int observation = 0; for (int d = 0; d < 4; d++) { if (SeeGhost(pocstate, d) >= 0) SetFlag(observation, d); COORD wpos = NextPos(pocstate.PocmanPos, d); if (wpos.Valid() && Passable(wpos)) SetFlag(observation, d + 4); } if (SmellFood(pocstate)) SetFlag(observation, 8); if (HearGhost(pocstate)) SetFlag(observation, 9); return observation; }
bool POCMAN::Step(STATE& state, int action, int& observation, double& reward) const { POCMAN_STATE& pocstate = safe_cast<POCMAN_STATE&>(state); reward = RewardDefault; observation = 0; // cout << COORD::CompassChar[action]; COORD newpos = NextPos(pocstate.PocmanPos, action); if (newpos.Valid()) pocstate.PocmanPos = newpos; else reward += RewardHitWall; if (pocstate.PowerSteps > 0) pocstate.PowerSteps--; int hitGhost = -1; for (int g = 0; g < NumGhosts; g++) { if (pocstate.GhostPos[g] == pocstate.PocmanPos) hitGhost = g; MoveGhost(pocstate, g); if (pocstate.GhostPos[g] == pocstate.PocmanPos) hitGhost = g; } if (hitGhost >= 0) { if (pocstate.PowerSteps > 0) { reward += RewardEatGhost; pocstate.GhostPos[hitGhost] = GhostHome; pocstate.GhostDir[hitGhost] = -1; } else { reward += RewardDie; return true; } } observation = MakeObservations(pocstate); int pocIndex = Maze.Index(pocstate.PocmanPos); if (pocstate.Food[pocIndex]) { pocstate.Food[pocIndex] = false; pocstate.NumFood--; if (pocstate.NumFood == 0) { reward += RewardClearLevel; return true; } if (CheckFlag(Maze(pocstate.PocmanPos.X, pocstate.PocmanPos.Y), E_POWER)) pocstate.PowerSteps = PowerNumSteps; reward += RewardEatFood; } return false; }