SlidingCratesPuzzle::possibleMoves()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\PuzzleSolver\Puzzle\SlidingCrates;
4
5
use Stratadox\PuzzleSolver\Move;
6
use Stratadox\PuzzleSolver\Puzzle;
7
use Stratadox\PuzzleSolver\Moves;
8
use function count;
9
use function preg_split;
10
use function str_replace;
11
use function str_split;
12
use function usort;
13
14
final class SlidingCratesPuzzle implements Puzzle
15
{
16
    private const NO_CRATE = '.';
17
18
    /** @var Room */
19
    private $room;
20
    /** @var string */
21
    private $target;
22
    /** @var Moves */
23
    private $moves;
24
25
    private function __construct(Room $room, string $target, Moves $moves)
26
    {
27
        $this->room = $room;
28
        $this->target = $target;
29
        $this->moves = $moves;
30
    }
31
32
    public static function with(Room $room, string $target): Puzzle
33
    {
34
        return new self($room, $target, Moves::none());
35
    }
36
37
    public static function fromString(string $crates, string $target): Puzzle
38
    {
39
        $rows = [];
40
        foreach (preg_split("/(\n)|(\r)/", str_replace(' ', '', $crates)) as $line) {
41
            $row = [];
42
            if (empty($line)) {
43
                continue;
44
            }
45
            foreach (str_split($line) as $char) {
46
                $row[] = $char;
47
            }
48
            $rows[] = $row;
49
        }
50
        return self::fromArray($rows, $target);
51
    }
52
53
    public static function fromArray(array $room, string $target): Puzzle
54
    {
55
        /** @var array[][] $crateCoordinates */
56
        $crateCoordinates = [];
57
        foreach ($room as $y => $row) {
58
            foreach ($row as $x => $column) {
59
                if ($column === self::NO_CRATE) {
60
                    continue;
61
                }
62
                $crateCoordinates[$column][] = [$x, $y];
63
            }
64
        }
65
        /** @var Crate[] $crates */
66
        $crates = [];
67
        foreach ($crateCoordinates as $id => $coordinates) {
68
            $crates[] = Crate::fromCoordinates($id, ...$coordinates);
69
        }
70
        usort($crates, static function (Crate $crate1, Crate $crate2): int {
71
            return $crate1->id() <=> $crate2->id();
72
        });
73
74
        return self::with(Room::withCrates(
75
            new Crates(...$crates),
76
            count($room[0]),
77
            count($room),
78
            Push::right($target)
79
        ), $target);
80
    }
81
82
    public function representation(): string
83
    {
84
        return (string) $this->room;
85
    }
86
87
    public function afterMaking(Move ...$moves): Puzzle
88
    {
89
        return new self(
90
            $this->room->afterPushing(...$moves),
91
            $this->target,
92
            $this->moves->add(...$moves)
93
        );
94
    }
95
96
    public function isSolved(): bool
97
    {
98
        return $this->room->isSolvedFor($this->target);
99
    }
100
101
    public function movesSoFar(): Moves
102
    {
103
        return $this->moves;
104
    }
105
106
    public function possibleMoves(): Moves
107
    {
108
        return new Moves(...$this->room->possiblePushes());
109
    }
110
111
    public function minimumDistanceToGoal(): int
112
    {
113
        return $this->room->minimumDistanceToGoalFor($this->target);
114
    }
115
}
116