Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

brendt/majo.stitcher.io

47 stars
3 code files
View brendt/majo.stitcher.io on GitHub

composer.json

Open in GitHub
{
// ...
"require": {
"php": "^8.1",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.0",
"laravel/sanctum": "^3.2",
"laravel/tinker": "^2.8",
"livewire/livewire": "^2.12"
},
// ...
}

app/Http/Livewire/Game.php

Open in GitHub
use App\Game\Board;
use Livewire\Component;
 
class Game extends Component
{
public function mount(): void
{
$board = Board::resolve();
 
if ($board === null) {
$board = Board::init();
}
 
$board->persist();
}
 
public function render()
{
$board = Board::resolve();
 
return view('livewire.game', [
'board' => $board,
]);
}
 
public function showHint(): void
{
$board = Board::resolve();
 
if (! $board) {
return;
}
 
$board->showHint()->persist();
}
 
public function resetBoard(): void
{
$board = Board::resolve();
 
if (! $board) {
return;
}
 
$board->destroy();
 
Board::init()->persist();
}
 
public function shuffleBoard(): void
{
$board = Board::resolve();
 
if (! $board) {
return;
}
 
$board->shuffle()->persist();
}
 
public function handleClick($x, $y): void
{
$board = Board::resolve();
 
$tileToSelect = $board->get($x, $y);
 
if (! $tileToSelect) {
return;
}
 
if (! $board->canSelect($tileToSelect)) {
return;
}
 
$highlightedTiles = $board->findHighlightedTiles();
 
if ($highlightedTiles) {
[$a, $b] = $highlightedTiles;
 
if ($a->isSame($tileToSelect) || $b->isSame($tileToSelect)) {
$board->remove($a);
$board->remove($b);
 
return;
}
}
 
$currentlySelectedTile = $board->getCurrentlySelectedTile();
 
if ($currentlySelectedTile?->matches($tileToSelect)) {
$board->remove($currentlySelectedTile);
$board->remove($tileToSelect);
} elseif ($currentlySelectedTile?->isSame($tileToSelect)) {
$tileToSelect->toggleSelected();
} else {
$board->clearSelectedTiles();
$tileToSelect->toggleSelected();
}
}
}

resources/views/livewire/game.blade.php

Open in GitHub
<div>
<style>
:root {
--tile-size: 60px;
--tile-gap: 15px;
}
 
.board {
display: grid;
grid-template-columns: repeat({{ $board->getXCount() }}, var(--tile-size));
grid-auto-rows: var(--tile-size);
grid-gap: var(--tile-gap);
margin: var(--tile-gap);
}
 
.cell {
position: relative;
}
 
.tile {
width: var(--tile-size);
height: 100%;
grid-area: 1 / 1 / 1 / 1;
display: flex;
align-items: end;
justify-content: center;
border: 4px solid var(--tile-color);
color: var(--tile-color);
background-color: #fff;
font-weight: bold;
padding-bottom: 5px;
font-size: 1em;
position: absolute;
cursor: not-allowed;
}
 
.tile.unselectable {
filter: blur(1px) grayscale(.7);
}
 
.tile.selectable {
cursor: pointer;
}
 
.tile.selectable:hover {
box-shadow: 0 0 0 2px var(--tile-color);
}
 
.tile.highlighted {
box-shadow: 0 0 5px 5px gold;
}
 
.tile.selected {
background-color: var(--tile-color);
color: #fff;
}
</style>
 
<div class="flex justify-center items-center h-screen pb-16">
@if($board->isFinished())
<div>
FINISHED!
 
<button class="underline hover:no-underline" wire:click="resetBoard">New Game</button>
</div>
@elseif($board->isStuck())
<div>
stuck :(
 
<button class="underline hover:no-underline" wire:click="shuffleBoard">Shuffle</button>
 
<button class="underline hover:no-underline" wire:click="resetBoard">Reset</button>
</div>
@else
<div>
<div class="board">
@foreach($board->tiles as $x => $row)
@foreach($row as $y => $column)
<div
class="cell"
style="grid-area: {{ $y + 1 }} / {{ $x + 1 }} / {{ $y + 1 }} / {{ $x + 1 }}"
wire:click="handleClick({{ $x }}, {{ $y }})"
>
@foreach($column as $z => $tile)
<div
class="
tile
{{ $tile->state->value }}
{{ $board->canSelect($tile) ? 'selectable' : 'unselectable' }}
"
style="
bottom: {{ $z * 3 }}px;
left: {{ $z * -3 }}px;
z-index: {{ $z }};
--tile-color: {{ $tile->getColor() }};
"
>
{{ $tile->value }}
</div>
@endforeach
</div>
@endforeach
@endforeach
</div>
 
<div class="flex justify-between p-4">
<span>Available pairs: {{ $board->getAvailablePairs() }}</span>
<span>Tiles left: {{ $board->getTileCount() }}</span>
<button class="underline hover:no-underline" wire:click="showHint">Show Hint</button>
<button class="underline hover:no-underline" wire:click="resetBoard">Reset</button>
<button class="underline hover:no-underline" wire:click="shuffleBoard">Shuffle</button>
</div>
</div>
@endif
</div>
 
</div>

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.