Anmelden
DE
games/open-lemmings / tests / WorldTest.php · commit 04e2e2a
<?phpnamespace Tests;use App\Sim\Autoplay;use App\Sim\LevelBuilder;use App\Sim\Levels;use App\Sim\Lumi;use App\Sim\Terrain;use App\Sim\World;use PHPUnit\Framework\TestCase;/** The rules, without a window: a flat world, one Lumikin, one skill at a time. */final class WorldTest extends TestCase{    private function flat(int $width = 300): World    {        $t = new Terrain($width, 200);        $t->fillRect(0, 150, $width, 50, Terrain::EARTH);        $w = new World($t);        $w->total = 1;        $w->need = 1;        $w->ticksLeft = 100000;        $w->hatch = [40, 140];        $w->exit = [9999, 150];        foreach (World::SKILLS as $s) {            $w->skills[$s] = 5;        }        return $w;    }    private function steps(World $w, int $ticks): Lumi    {        for ($i = 0; $i < $ticks; $i++) {            $w->step();        }        return $w->lumis[0];    }    public function testALumikinComesOutAndWalksToTheRight(): void    {        $w = $this->flat();        $l = $this->steps($w, 100);        self::assertSame(Lumi::WALK, $l->state);        self::assertGreaterThan(60, $l->x);        self::assertSame(150, $l->y);    }    public function testItTurnsAroundAtAWall(): void    {        $w = $this->flat();        $w->terrain->fillRect(100, 100, 10, 50, Terrain::EARTH);        $l = $this->steps($w, 160);        self::assertSame(-1, $l->dir);        self::assertLessThan(100, $l->x);    }    public function testADiggerGoesStraightDown(): void    {        $w = $this->flat();        $l = $this->steps($w, 60);        self::assertTrue($w->assign($l, 'dig'));        $x = $l->x;        $this->steps($w, 60);        self::assertSame($x, $l->x);        self::assertGreaterThan(165, $l->y);        self::assertFalse($w->terrain->solid($x, 152));        self::assertSame(4, $w->skills['dig']);    }    public function testABasherOpensATunnelThroughAWall(): void    {        $w = $this->flat();        $w->terrain->fillRect(100, 100, 30, 50, Terrain::EARTH);        $l = $this->steps($w, 98);        self::assertTrue($w->assign($l, 'bash'));        $this->steps($w, 200);        self::assertGreaterThan(135, $l->x);        self::assertFalse($w->terrain->solid(115, 145));        self::assertTrue($w->terrain->solid(115, 120));    }    public function testSteelStopsABasher(): void    {        $w = $this->flat();        $w->terrain->fillRect(100, 100, 30, 50, Terrain::STEEL);        $l = $this->steps($w, 98);        $w->assign($l, 'bash');        $this->steps($w, 60);        self::assertTrue($w->terrain->solid(115, 145));        self::assertLessThan(100, $l->x);    }    public function testABuilderLaysAStairOfTwelveBricks(): void    {        $w = $this->flat();        $l = $this->steps($w, 60);        $w->assign($l, 'bridge');        $x = $l->x;        $this->steps($w, 9 * 12 + 2);        self::assertSame(World::MAX_BRICKS, $l->bricks);        self::assertSame(150 - 12, $l->y);        self::assertSame($x + 24, $l->x);        self::assertSame(Terrain::BRICK, $w->terrain->at($x + 10, 150 - 5));    }    public function testABlockerTurnsTheOthersAround(): void    {        $w = $this->flat();        $w->total = 2;        $w->rate = 99;        $this->steps($w, 70);        self::assertCount(2, $w->lumis);        self::assertTrue($w->assign($w->lumis[0], 'stop'));        $this->steps($w, 20);        self::assertSame(-1, $w->lumis[1]->dir);        self::assertLessThan($w->lumis[0]->x, $w->lumis[1]->x);    }    public function testALongFallIsDeadlyUnlessItGlides(): void    {        foreach ([false, true] as $glider) {            $w = $this->flat();            $w->hatch = [40, 20];            $l = $this->steps($w, 42);            if ($glider) {                $w->assign($l, 'glide');            }            $this->steps($w, 200);            self::assertSame($glider, $l->alive);        }    }    public function testAClimberGoesOverAWall(): void    {        $w = $this->flat();        $w->terrain->fillRect(100, 110, 10, 40, Terrain::EARTH);        $l = $this->steps($w, 60);        $w->assign($l, 'climb');        $this->steps($w, 200);        self::assertGreaterThan(110, $l->x);        self::assertTrue($l->alive);    }    public function testAFirecrackerBurstsAfterThreeSecondsAndDigsAHole(): void    {        $w = $this->flat();        $l = $this->steps($w, 60);        $w->assign($l, 'boom');        $this->steps($w, World::FUSE_TICKS - 2);        self::assertTrue($l->alive);        $this->steps($w, 4);        self::assertFalse($l->alive);        self::assertSame(1, $w->lost);        self::assertFalse($w->terrain->solid($l->x, 152));    }    public function testReachingTheExitSavesIt(): void    {        $w = $this->flat();        $w->exit = [120, 150];        $this->steps($w, 160);        self::assertSame(1, $w->saved);        self::assertTrue($w->isOver());        self::assertTrue($w->isWon());    }    public function testEveryLevelCanBeWonByItsSolution(): void    {        foreach (Levels::all() as $i => $def) {            $w = LevelBuilder::build($def);            $auto = new Autoplay($w, $def['solution']);            while (!$w->isOver()) {                $w->step();                $auto->step();                $w->events = [];            }            self::assertTrue($w->isWon(), 'level ' . ($i + 1) . " ({$def['name']}): saved {$w->saved}, needs {$w->need}");        }    }}