void game_step()

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;
        }
    }