Skip to content

Commit

Permalink
✅ Make CI pass
Browse files Browse the repository at this point in the history
  • Loading branch information
matyo91 committed Oct 5, 2024
1 parent ca52108 commit 7d31f86
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 64 deletions.
22 changes: 15 additions & 7 deletions src/Job/WaveFunctionCollapse/CollapseJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,41 @@
namespace App\Job\WaveFunctionCollapse;

use App\Model\WaveFunctionCollapse\Cell;
use Exception;
use App\Model\WaveFunctionCollapse\Tile;
use Flow\JobInterface;

use function count;
use function in_array;

/**
* @implements JobInterface<mixed, mixed>
*/
class CollapseJob implements JobInterface
{
public function __construct(
/** @var Tile[] */
public array $tiles,
public int $width,
public int $height,
)
{}
) {}

public function __invoke($grid): mixed
{
// Pick cell with least entropy
$gridNoOptions = array_filter($grid, fn(Cell $a) => empty($a->getOptions()));
$gridCopy = array_filter($grid, fn(Cell $a) => !$a->isCollapsed());
$gridNoOptions = array_filter($grid, static fn (Cell $a) => empty($a->getOptions()));
$gridCopy = array_filter($grid, static fn (Cell $a) => !$a->isCollapsed());
if (!empty($gridNoOptions) || empty($gridCopy)) {
return null;
}

usort($gridCopy, fn($a, $b) => count($a->getOptions()) - count($b->getOptions()));
usort($gridCopy, static fn ($a, $b) => count($a->getOptions()) - count($b->getOptions()));

$len = count($gridCopy[0]->getOptions());
$stopIndex = 0;
for ($i = 1; $i < count($gridCopy); $i++) {
if (count($gridCopy[$i]->getOptions()) > $len) {
$stopIndex = $i;

break;
}
}
Expand Down Expand Up @@ -110,11 +114,15 @@ public function __invoke($grid): mixed
return $nextGrid;
}

/**
* @param array<int> $arr The array of options to check and potentially modify
* @param array<int> $valid The array of valid options to compare against
*/
private function checkValid(array &$arr, array $valid): void
{
for ($i = count($arr) - 1; $i >= 0; $i--) {
$element = $arr[$i];
if (!in_array($element, $valid)) {
if (!in_array($element, $valid, true)) {
array_splice($arr, $i, 1);
}
}
Expand Down
18 changes: 17 additions & 1 deletion src/Model/WaveFunctionCollapse/Cell.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Model\WaveFunctionCollapse;

use function is_array;

class Cell
{
public bool $collapsed = false;
/**
* @var array<int>
*/
public array $options;

public function __construct($value)
/**
* @param array<int>|int $value
*/
public function __construct(array|int $value)
{
if (is_array($value)) {
$this->options = $value;
Expand All @@ -26,11 +36,17 @@ public function setCollapsed(bool $collapsed): void
$this->collapsed = $collapsed;
}

/**
* @return array<int>
*/
public function getOptions(): array
{
return $this->options;
}

/**
* @param array<int> $options
*/
public function setOptions(array $options): void
{
$this->options = $options;
Expand Down
56 changes: 31 additions & 25 deletions src/Model/WaveFunctionCollapse/Tile.php
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
<?php

declare(strict_types=1);

namespace App\Model\WaveFunctionCollapse;

use function count;

class Tile
{
public $index;
public $edges;
public $up = [];
public $right = [];
public $down = [];
public $left = [];
public $direction = 0;
public function __construct(
public int $index,
/** @var array<string> */
public array $edges,
public int $direction = 0,
/** @var array<int> */
public array $up = [],
/** @var array<int> */
public array $right = [],
/** @var array<int> */
public array $down = [],
/** @var array<int> */
public array $left = []
) {}

public function __construct($index, $edges, $direction = 0, $up = [], $right = [], $down = [], $left = [])
{
$this->index = $index;
$this->edges = $edges;
$this->direction = $direction;
$this->up = $up;
$this->right = $right;
$this->down = $down;
$this->left = $left;
}

public function analyze($tiles)
/**
* @param Tile[] $tiles
*/
public function analyze(array $tiles): void
{
foreach ($tiles as $i => $tile) {
// Tile can't match itself
if ($tile->index == $this->index) continue;
if ($tile->index === $this->index) {
continue;
}

// UP
if ($this->compareEdge($tile->edges[2], $this->edges[0])) {
Expand All @@ -48,23 +53,24 @@ public function analyze($tiles)
}
}

public function rotate($direction)
public function rotate(int $direction): self
{
$newEdges = [];
$len = count($this->edges);
for ($i = 0; $i < $len; $i++) {
$newEdges[$i] = $this->edges[($i - $direction + $len) % $len];
}
return new Tile($this->index, $newEdges, $direction);

return new self($this->index, $newEdges, $direction);
}

private function reverseString($s)
private function reverseString(string $s): string
{
return strrev($s);
}

private function compareEdge($a, $b)
private function compareEdge(string $a, string $b): bool
{
return $a == $this->reverseString($b);
return $a === $this->reverseString($b);
}
}
94 changes: 63 additions & 31 deletions src/Twig/Components/WaveFunctionCollapse/Board.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
<?php

declare(strict_types=1);

namespace App\Twig\Components\WaveFunctionCollapse;

use App\Enum\WaveFunctionCollapse\DataSetEnum;
use App\Job\WaveFunctionCollapse\CollapseJob;
use App\Model\WaveFunctionCollapse\Cell;
use App\Model\WaveFunctionCollapse\Tile;
use Flow\Driver\FiberDriver;
use Flow\Flow\Flow;
use Flow\Ip;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;

use function count;

#[AsLiveComponent]
final class Board
{
Expand All @@ -23,11 +25,13 @@ final class Board
#[LiveProp(writable: true, onUpdated: 'reset')]
public DataSetEnum $dataSet = DataSetEnum::CIRCUIT_CODING_TRAIN;

/** @var array<Tile> */
#[LiveProp(hydrateWith: 'hydrateTiles', dehydrateWith: 'dehydrateTiles', writable: true)]
public array $tiles = [];
/** @var array<Cell> */
#[LiveProp(hydrateWith: 'hydrateGrid', dehydrateWith: 'dehydrateGrid', writable: true)]
public array $grid = [];

#[LiveProp]
public int $width = 0;
#[LiveProp]
Expand All @@ -44,7 +48,7 @@ public function mount(int $width, int $height): void
$this->reset();
}

public function reset()
public function reset(): void
{
$this->loadDataset();

Expand All @@ -69,15 +73,17 @@ public function reset()
}

#[LiveAction]
public function collapse() {
public function collapse(): void
{
$flow = Flow::do(function () {
yield new CollapseJob($this->tiles, $this->width, $this->height);
yield function($nextGrid) {
if($nextGrid === null) {
yield function ($nextGrid) {
if ($nextGrid === null) {
$this->startOver();
} else {
$this->grid = $nextGrid;
}

return $this->grid;
};
});
Expand All @@ -92,27 +98,14 @@ public function togglePool(): void
$this->pool = !$this->pool;
}

private function removeDuplicatedTiles(array $tiles): array
{
$uniqueTilesMap = [];
foreach ($tiles as $tile) {
$key = implode(',', $tile->edges); // ex: "ABB,BCB,BBA,AAA"
$uniqueTilesMap[$key] = $tile;
}
return array_values($uniqueTilesMap);
}

private function startOver(): void
/**
* @param array<Tile> $tiles
*
* @return array<mixed>
*/
public function dehydrateTiles(array $tiles): array
{
// Create cell for each spot on the grid
for ($i = 0; $i < $this->width * $this->height; $i++) {
$this->grid[$i] = new Cell(count($this->tiles));
}
}

public function dehydrateTiles(array $tiles)
{
return array_map(function (Tile $tile) {
return array_map(static function (Tile $tile) {
return [
'index' => $tile->index,
'edges' => $tile->edges,
Expand All @@ -125,41 +118,81 @@ public function dehydrateTiles(array $tiles)
}, $tiles);
}

/**
* @param array<mixed> $data
*
* @return array<Tile>
*/
public function hydrateTiles($data): array
{
return array_map(function ($tileData) {
return array_map(static function ($tileData) {
return new Tile(
$tileData['index'],
$tileData['edges'],
$tileData['direction'],
$tileData['up'],
$tileData['right'],
$tileData['down'],
$tileData['left']
$tileData['left']
);
}, $data);
}

/**
* @param array<Cell> $grid
*
* @return array<mixed>
*/
public function dehydrateGrid(array $grid): array
{
return array_map(function (Cell $cell) {
return array_map(static function (Cell $cell) {
return [
'options' => $cell->options,
'collapsed' => $cell->collapsed,
];
}, $grid);
}

/**
* @param array<mixed> $data
*
* @return array<Cell>
*/
public function hydrateGrid(array $data): array
{
return array_map(function ($cellData) {
$cell = new Cell(count($this->tiles));
$cell->options = $cellData['options'];
$cell->collapsed = $cellData['collapsed'];

return $cell;
}, $data);
}

/**
* @param array<Tile> $tiles
*
* @return array<Tile>
*/
private function removeDuplicatedTiles(array $tiles): array
{
$uniqueTilesMap = [];
foreach ($tiles as $tile) {
$key = implode(',', $tile->edges); // ex: "ABB,BCB,BBA,AAA"
$uniqueTilesMap[$key] = $tile;
}

return array_values($uniqueTilesMap);
}

private function startOver(): void
{
// Create cell for each spot on the grid
for ($i = 0; $i < $this->width * $this->height; $i++) {
$this->grid[$i] = new Cell(count($this->tiles));
}
}

private function loadDataset(): void
{
$this->tiles = match ($this->dataSet) {
Expand Down Expand Up @@ -311,7 +344,6 @@ private function loadDataset(): void
new Tile(68, ['TTO', 'OOO', 'TTO', 'TTT']),
new Tile(69, ['OTT', 'TTT', 'OTT', 'OOO']),
],
default => throw new \InvalidArgumentException('Invalid dataset'),
};
}
}

0 comments on commit 7d31f86

Please sign in to comment.