in procgen/src/games/chaser.cpp [293:386]
void game_step() override {
BasicAbstractGame::game_step();
int num_orbs = 0;
int num_enemies = 0;
float default_enemy_speed = .5;
float vscale = can_eat_enemies() ? (default_enemy_speed * .5) : default_enemy_speed;
for (int j = (int)(entities.size()) - 1; j >= 0; j--) {
auto ent = entities[j];
if (ent->type == ORB) {
num_orbs++;
} else if (ent->type == ENEMY_EGG) {
num_enemies++;
ent->health -= 1;
if (ent->health == 0) {
ent->will_erase = true;
auto enemy = spawn_child(ent, ENEMY, .5);
enemy->smart_step = true;
}
} else if (ent->type == ENEMY) {
num_enemies++;
float x = ent->x - .5;
float y = ent->y - .5;
int dist_scale = can_eat_enemies() ? -1 : 1;
int enemy_idx = to_grid_idx(x, y);
int agent_idx = to_grid_idx(agent->x, agent->y);
bool is_at_junction = fabs(x - round(x)) + fabs(y - round(y)) < .01;
bool be_agressive = step_rand_int % 2 == 0;
if ((ent->vx == 0 && ent->vy == 0) || is_at_junction) {
std::vector<int> adj_elems;
std::vector<int> space_neighbors;
int prev_idx = to_grid_idx(x - sign(ent->vx), y - sign(ent->vy));
get_adjacent(enemy_idx, adj_elems);
int min_dist = 2 * main_width;
for (int adj : adj_elems) {
if (is_space_vec[adj] && adj != prev_idx) {
int md = manhattan_dist(adj, agent_idx) * dist_scale;
if (be_agressive) {
if (md < min_dist) {
min_dist = md;
space_neighbors.clear();
space_neighbors.push_back(adj);
} else if (md == min_dist) {
space_neighbors.push_back(adj);
}
} else {
space_neighbors.push_back(adj);
}
}
}
int neighbor_idx = step_rand_int % space_neighbors.size();
int neighbor = space_neighbors[neighbor_idx];
int nx = neighbor % main_width;
int ny = neighbor / main_width;
ent->vx = (nx - x) * vscale;
ent->vy = (ny - y) * vscale;
}
}
};
if (num_enemies < total_enemies) {
int selected_idx = step_rand_int % free_cells.size();
spawn_egg(free_cells[selected_idx]);
}
int agent_idx = get_agent_index();
if (get_obj(agent_idx) == ORB) {
set_obj(agent_idx, SPACE);
step_data.reward += ORB_REWARD;
orbs_collected += 1;
}
if (orbs_collected == total_orbs) {
step_data.reward += COMPLETION_BONUS;
step_data.level_complete = true;
step_data.done = true;
}
}