Private
Public Access
1
0
Files
MineSeeker/src/Util/RpcManager.php

190 lines
5.7 KiB
PHP
Raw Normal View History

<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2019 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Util;
use App\Entity\Grid;
use App\Entity\GridRow;
use App\Entity\PlayedGame;
use App\Interfaces\RpcManagerInterface;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use JsonException;
use Psr\Log\LoggerInterface;
use RuntimeException;
/**
* Class RpcManager
*
* @package App\Util
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 09.
*/
class RpcManager implements RpcManagerInterface
{
private const ROWS = 16;
private const COLS = 16;
private const MINES = 51;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
public function getConnectInformation($params): string
{
$gameAssoc = is_array($params) ? $params[0] : $params;
$playedGame = $this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc);
if (null === $playedGame) {
try {
return base64_encode(json_encode([
'users' => null,
'revealedCells' => null,
], JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
throw new RuntimeException($e->getMessage());
}
}
$users = $this->getUserCollection($playedGame);
$revealedCells = $this->aggregateRevealedCells($playedGame);
try {
return base64_encode(json_encode([
'users' => $users,
'revealedCells' => $revealedCells,
], JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
throw new RuntimeException($e->getMessage());
}
}
public function saveGrid(string $gameAssoc): bool
{
$existingGame = $this->entityManager
->getRepository(PlayedGame::class)
->findOneByGameAssoc($gameAssoc);
if (null !== $existingGame) {
return true;
}
$grid2d = $this->generateGrid();
$playedGame = new PlayedGame();
$grid = new Grid();
try {
foreach ($grid2d as $row) {
$gridRow = new GridRow();
$gridRow->setGridCol($row);
$gridRow->setGrid($grid);
$this->entityManager->persist($gridRow);
}
$grid->setPlayedGame($playedGame);
$this->entityManager->persist($grid);
$playedGame->setGameAssoc($gameAssoc);
$playedGame->setGrid($grid);
$playedGame->setCreated(new DateTime());
$playedGame->setUpdated(new DateTime());
$this->entityManager->persist($playedGame);
$this->entityManager->flush();
} catch (Exception $e) {
$this->logger->error($e->getMessage());
}
return true;
}
/**
* Generate a random 16×16 grid with 51 mines and adjacent-mine numbers.
*/
private function generateGrid(): array
{
// Build flat set: 51 mines ('m') + remaining water ('w')
$set = array_merge(
array_fill(0, self::MINES, 'm'),
array_fill(0, self::ROWS * self::COLS - self::MINES, 'w'),
);
// Fisher-Yates shuffle
for ($i = count($set) - 1; $i > 0; $i--) {
$j = random_int(0, $i);
[$set[$i], $set[$j]] = [$set[$j], $set[$i]];
}
// Reshape to 2-D
$grid = [];
for ($r = 0; $r < self::ROWS; $r++) {
$grid[$r] = array_slice($set, $r * self::COLS, self::COLS);
}
// Replace 'w' with adjacent-mine count
$dirs = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]];
for ($r = 0; $r < self::ROWS; $r++) {
for ($c = 0; $c < self::COLS; $c++) {
if ('w' !== $grid[$r][$c]) {
continue;
}
$count = 0;
foreach ($dirs as [$dr, $dc]) {
if (isset($grid[$r + $dr][$c + $dc]) && 'm' === $grid[$r + $dr][$c + $dc]) {
$count++;
}
}
$grid[$r][$c] = $count;
}
}
return $grid;
}
/**
* Collect all cells revealed so far, enriched with the player colour from each Step.
*/
private function aggregateRevealedCells(PlayedGame $playedGame): array
{
$all = [];
foreach ($playedGame->getSteps() as $step) {
if (null === $step->getRevealedCells()) {
continue;
}
$player = $step->getPlayer();
foreach ($step->getRevealedCells() as $cell) {
$all[] = array_merge($cell, ['player' => $player]);
}
}
return $all;
}
private function getUserCollection(PlayedGame $playedGame): array
{
return [
'red' => null !== $playedGame->getRed() ? $playedGame->getRed()->getUsername() : '',
'blue' => null !== $playedGame->getBlue() ? $playedGame->getBlue()->getUsername() : '',
'redAnon' => null !== $playedGame->getRedAnon() ? $playedGame->getRedAnon()->getUserName() : '',
'blueAnon' => null !== $playedGame->getBlueAnon() ? $playedGame->getBlueAnon()->getUserName() : '',
];
}
}