로그인
KO
games/open-lemmings / src / Sim / Autoplay.php · commit 04e2e2a
<?phpnamespace App\Sim;/** Plays a level's 'solution' on its World: the title demo, the smoke test, the proof that a level can be won. */final class Autoplay{    private int $next = 0;    public function __construct(private World $world, private array $steps)    {    }    public function done(): bool    {        return $this->next >= count($this->steps);    }    /** Call once per tick, after World::step(). */    public function step(): void    {        if ($this->done()) {            return;        }        $s = $this->steps[$this->next];        [$skill, $who, $x, $dir] = $s;        $leader = null;        foreach ($this->world->lumis as $l) {            if ($l->alive && !$l->is(Lumi::STOP) && ($leader === null || $l->x > $leader->x)) {                $leader = $l;            }        }        if (isset($s[5])) {            $ref = $s[4] === -5 ? $leader : ($this->world->lumis[$s[4]] ?? null);            if ($this->world->saved === 0 && ($ref === null || ($ref->alive && $ref->x < $s[5]))) {                return;            }        }        foreach ($this->world->lumis as $l) {            if (!$l->alive) {                continue;            }            $match = match (true) {                $who >= 0 => $l->id === $who,                $who === -1 => $l !== $leader && $l->state === Lumi::WALK,                $who === -5 => $l === $leader,                $who === -2 => $l->state === Lumi::STOP,                default => $l->state === Lumi::WALK,            };            if (!$match || ($dir !== 0 && $l->dir !== $dir)) {                continue;            }            if ($x > 0 && ($l->dir > 0 ? $l->x < $x : $l->x > $x)) {                continue;            }            if ($x > 0 && $who < 0 && $who !== -5 && abs($l->x - $x) > 3) {                continue;            }            if ($this->world->assign($l, $skill)) {                $this->next++;                return;            }        }    }}