diff --git a/app/library/Controllers/IndexController.php b/app/library/Controllers/IndexController.php index 64cab40..7d685d5 100644 --- a/app/library/Controllers/IndexController.php +++ b/app/library/Controllers/IndexController.php @@ -3,6 +3,7 @@ namespace App\Controllers; use App\GameLogic; +use App\Models\PlayersTable; use App\Views\IndexView; use App\Views\AbstractView; use App\Views\JsonView; @@ -29,6 +30,21 @@ private function getGridSize(): int return $gridSize; } + private function getCurrentTimeString(): string + { + return date('Y-m-d h:i:s'); + } + + private function calculateElapsedTime($startTimeU): int + { + if (!is_numeric($startTimeU)) { + return 0; + } + + $now = (int) date('U'); + return ($now - (int) $startTimeU); + } + /** * It is used in Ajax requests. * @noinspection PhpUnused @@ -40,6 +56,9 @@ public function opponentsTurnAction(): AbstractView $request = json_decode($requestJson, true); $matrix = $request['matrix'] ?? []; + $playerName = $request['player_name'] ?? 'Unknown player'; + $gridSize = $request['grid_size'] ?? 3; + $startTime = $request['start_time'] ?? 0; $gameLogic = new GameLogic($matrix); @@ -49,12 +68,17 @@ public function opponentsTurnAction(): AbstractView $row = 0; $col = 0; if (!$isPlayerWin && $gameLogic->isFreeCellsLeft()) { - list($row, $col) = $gameLogic->findBestMove(); + list($row, $col) = $gameLogic->findAMove(); $gameLogic->setComputersMove($row, $col); $isGameOver = $gameLogic->isGameOver(); $isComputerWin = $gameLogic->doWeHaveWinner(); } + if ($isPlayerWin) { + $playersTable = new PlayersTable(); + $playersTable->addRow($playerName, $gridSize, $this->calculateElapsedTime($startTime), $this->getCurrentTimeString()); + } + $view = new JsonView(); $view->data = [ 'is_game_over' => $isGameOver, diff --git a/app/library/Controllers/LeaderboardController.php b/app/library/Controllers/LeaderboardController.php index 4b257c4..f9883d0 100644 --- a/app/library/Controllers/LeaderboardController.php +++ b/app/library/Controllers/LeaderboardController.php @@ -13,8 +13,10 @@ public function indexAction(): AbstractView $view = new LeaderboardView(); // Todo: redo this crap! - $players = (new PlayersTable())->getLeaders(10); + $players = (new PlayersTable())->getTotalLeaders(); + $playerCount = count((new PlayersTable())->getAllUniquePlayers()); $view->players = $players; + $view->playerCount = $playerCount; return $view; } diff --git a/app/library/GameLogic.php b/app/library/GameLogic.php index 0715dc3..2f84a27 100644 --- a/app/library/GameLogic.php +++ b/app/library/GameLogic.php @@ -45,6 +45,33 @@ public function findBestMove(): array return $this->findBestMove(); } + /** + * At least it doesn't recurse... + */ + public function findAMove(): array + { + $freeRows = $this->findPlayableRows(); + $freeRow = array_rand($freeRows); + $freeColumn = $freeRows[$freeRow][array_rand($freeRows[$freeRow])]; + + return [$freeRow, $freeColumn]; + } + + public function findPlayableRows(): array + { + $playableRows = []; + + foreach($this->matrix as $index => $row) { + $freeCells = array_keys($row, ''); + + if(count($freeCells)) { + $playableRows[$index] = $freeCells; + } + } + + return $playableRows; + } + public function setComputersMove(int $row, int $col): void { $this->matrix[$row][$col] = 'O'; diff --git a/app/library/Models/PlayersTable.php b/app/library/Models/PlayersTable.php index 8183613..0a4c204 100644 --- a/app/library/Models/PlayersTable.php +++ b/app/library/Models/PlayersTable.php @@ -20,6 +20,8 @@ public function getLeaders(int $gridSize): array FROM players WHERE grid_size = :grid_size + ORDER BY + play_time_seconds ASC ", [ ':grid_size' => $gridSize, @@ -27,6 +29,39 @@ public function getLeaders(int $gridSize): array ); } + public function getTotalLeaders(): array + { + return $this->executeSql( + " + SELECT + name, + play_time_seconds, + grid_size, + ctime + FROM players + ORDER BY + grid_size DESC, + play_time_seconds ASC + LIMIT 20 + ", + [] + ); + } + + public function getAllUniquePlayers(): array + { + return $this->executeSQL( + " + SELECT DISTINCT + name + FROM players + ORDER BY + name ASC + ", + [] + ); + } + public function addRow(string $name, int $gridSize, int $playTimeSeconds, string $date): void { $this->executeSql( diff --git a/app/library/Views/IndexView.php b/app/library/Views/IndexView.php index b22bc37..c50313d 100644 --- a/app/library/Views/IndexView.php +++ b/app/library/Views/IndexView.php @@ -4,11 +4,13 @@ class IndexView extends AbstractView { - public int $gridSize; + public int $gridSize; + public string $playerName; public function __construct() { - $this->setTitle("Hello player!"); + $this->playerName = ($_GET['player_name']) ?? "Player Name"; + $this->setTitle( "Hello " . $this->playerName . "!"); } public function render(): void diff --git a/app/library/Views/Layouts/app.phtml b/app/library/Views/Layouts/app.phtml index 29d86bd..3d50f28 100644 --- a/app/library/Views/Layouts/app.phtml +++ b/app/library/Views/Layouts/app.phtml @@ -17,7 +17,7 @@ use App\Views\Layouts\AppLayout; - + diff --git a/app/library/Views/LeaderboardView.php b/app/library/Views/LeaderboardView.php index 72e46d5..956df5e 100644 --- a/app/library/Views/LeaderboardView.php +++ b/app/library/Views/LeaderboardView.php @@ -7,6 +7,9 @@ class LeaderboardView extends AbstractView /** @var array[][] */ public array $players; + /** @var int */ + public int $playerCount; + public function __construct() { $this->setTitle("Leaderboard"); diff --git a/app/library/Views/index.phtml b/app/library/Views/index.phtml index 81feac5..a8fbc66 100644 --- a/app/library/Views/index.phtml +++ b/app/library/Views/index.phtml @@ -8,6 +8,8 @@ ?>
+ + +
@@ -31,7 +34,7 @@ $button_id = 'game_grid_' . $row . '_' . $col; ?> - + diff --git a/app/library/Views/leaderboard.phtml b/app/library/Views/leaderboard.phtml index c72299b..0e7704d 100644 --- a/app/library/Views/leaderboard.phtml +++ b/app/library/Views/leaderboard.phtml @@ -8,5 +8,26 @@ ?>
- players) ?> + + + + + + + + + players); $row++) { ?> + + + + + + + + +
NamePlay time (s)Grid sizeDate
players[$row]['name']) ?? '' ?>players[$row]['play_time_seconds']) ?? '' ?>players[$row]['grid_size']) ?? '' ?>players[$row]['ctime']) ?? '' ?>
+ + playerCount) : ?> + Total players: playerCount ?> +
diff --git a/app/www/script.js b/app/www/script.js index 1973a3a..69af126 100644 --- a/app/www/script.js +++ b/app/www/script.js @@ -9,6 +9,10 @@ function makeOpponentsTurn() { let row = 1; let col = 1; let rowTexts = []; + let playerName = document.getElementById('player_name').value ?? 'Player name'; + let startTime = document.getElementById('start_time').value ?? 0; + let gridSize = document.getElementById('grid_size').value ?? 3; + do { const buttonId = `game_grid_${row}_${col}`; @@ -38,7 +42,14 @@ function makeOpponentsTurn() { "Accept": "application/json", "Content-Type": "application/json", }, - body: JSON.stringify({ matrix: matrix }), + body: JSON.stringify( + { + matrix: matrix, + player_name: playerName, + start_time: startTime, + grid_size: gridSize + } + ), } ) .then((response) => { diff --git a/app/www/style.css b/app/www/style.css index 8713944..ee10661 100644 --- a/app/www/style.css +++ b/app/www/style.css @@ -16,11 +16,21 @@ body { width: 100px; } +#game_grid { + padding: 1px 0 0 1px; + border: 5px solid black; + background-color: black; +} + #game_grid button{ - width: 20px; - height: 20px; - padding: 2px; - margin: 0; + display: block; + width: 40px; + height: 40px; + padding: 0 2px 2px; + margin: 0 1px 1px 0; + background-color: white; + color: black; + font-size: 30px; text-align: center; line-height: 0; }