chg: dev: outsource the Grid generation and interactions to the backend #4
This commit is contained in:
@@ -33,6 +33,10 @@ use RuntimeException;
|
||||
*/
|
||||
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,
|
||||
@@ -42,54 +46,61 @@ class RpcManager implements RpcManagerInterface
|
||||
public function getConnectInformation($params): string
|
||||
{
|
||||
$gameAssoc = is_array($params) ? $params[0] : $params;
|
||||
$grid = $this->getGrid($gameAssoc);
|
||||
$users = null !== $grid ? $this->getUsers($gameAssoc) : null;
|
||||
|
||||
$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([
|
||||
'grid' => $grid,
|
||||
'users' => $users,
|
||||
], JSON_THROW_ON_ERROR, 512));
|
||||
'users' => $users,
|
||||
'revealedCells' => $revealedCells,
|
||||
], JSON_THROW_ON_ERROR));
|
||||
} catch (JsonException $e) {
|
||||
throw new RuntimeException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function saveGrid($data): bool
|
||||
public function saveGrid(string $gameAssoc): bool
|
||||
{
|
||||
$existingGame = $this->entityManager
|
||||
->getRepository(PlayedGame::class)
|
||||
->findOneByGameAssoc($data[1]);
|
||||
->findOneByGameAssoc($gameAssoc);
|
||||
|
||||
if (null !== $existingGame) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$grid2d = $this->generateGrid();
|
||||
$playedGame = new PlayedGame();
|
||||
$grid = new Grid();
|
||||
try {
|
||||
$rows = json_decode(base64_decode($data[0]), true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new RuntimeException($e->getMessage());
|
||||
}
|
||||
$grid = new Grid();
|
||||
|
||||
try {
|
||||
foreach ($rows as $row) {
|
||||
foreach ($grid2d as $row) {
|
||||
$gridRow = new GridRow();
|
||||
|
||||
$gridRow->setGridCol($row);
|
||||
|
||||
/** Save Row */
|
||||
$gridRow->setGrid($grid);
|
||||
$this->entityManager->persist($gridRow);
|
||||
}
|
||||
|
||||
/** Save Grid */
|
||||
$grid->setPlayedGame($playedGame);
|
||||
$this->entityManager->persist($grid);
|
||||
|
||||
/** Save PlayedGame */
|
||||
$playedGame->setGameAssoc($data[1]);
|
||||
$playedGame->setGameAssoc($gameAssoc);
|
||||
$playedGame->setGrid($grid);
|
||||
$playedGame->setCreated(new DateTime());
|
||||
$playedGame->setUpdated(new DateTime());
|
||||
@@ -104,77 +115,75 @@ class RpcManager implements RpcManagerInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* It gets the current Grid by PlayedGame/gameAssoc
|
||||
*
|
||||
* @param $gameAssoc
|
||||
*
|
||||
* @return array
|
||||
* Generate a random 16×16 grid with 51 mines and adjacent-mine numbers.
|
||||
*/
|
||||
private function getGrid($gameAssoc): ?array
|
||||
private function generateGrid(): array
|
||||
{
|
||||
$gridCols = 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'),
|
||||
);
|
||||
|
||||
try {
|
||||
$this->entityManager->clear();
|
||||
|
||||
/** @var PlayedGame $playedGame */
|
||||
$playedGame = $this->entityManager
|
||||
->getRepository(PlayedGame::class)
|
||||
->findOneByGameAssoc($gameAssoc);
|
||||
|
||||
if (null === $playedGame) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null === $rows = $playedGame->getGrid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rows = $rows->getGridRow();
|
||||
|
||||
/** @var GridRow $row */
|
||||
foreach ($rows as $row) {
|
||||
$gridCols[] = $row->getGridCol();
|
||||
}
|
||||
|
||||
return $gridCols;
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
// Fisher-Yates shuffle
|
||||
for ($i = count($set) - 1; $i > 0; $i--) {
|
||||
$j = random_int(0, $i);
|
||||
[$set[$i], $set[$j]] = [$set[$j], $set[$i]];
|
||||
}
|
||||
|
||||
return null;
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Users by PlayedGame
|
||||
*
|
||||
* @param $gameAssoc
|
||||
*
|
||||
* @return array
|
||||
* Collect all cells revealed so far, enriched with the player colour from each Step.
|
||||
*/
|
||||
private function getUsers($gameAssoc): array
|
||||
private function aggregateRevealedCells(PlayedGame $playedGame): array
|
||||
{
|
||||
return $this->getUserCollection(
|
||||
$this->entityManager
|
||||
->getRepository(PlayedGame::class)
|
||||
->findOneByGameAssoc($gameAssoc)
|
||||
);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user collection from PlayedGame entity
|
||||
*
|
||||
* @param PlayedGame $playedGame
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getUserCollection(PlayedGame $playedGame): array
|
||||
{
|
||||
return [
|
||||
'red' => null !== $playedGame->getRed() ? $playedGame->getRed()->getUsername() : '',
|
||||
'blue' => null !== $playedGame->getBlue() ? $playedGame->getBlue()->getUsername() : '',
|
||||
'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() : '',
|
||||
'blueAnon' => null !== $playedGame->getBlueAnon()? $playedGame->getBlueAnon()->getUserName(): '',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user