First git commit
This commit is contained in:
74
public_html/games/guess.php
Normal file
74
public_html/games/guess.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// Single player: guess the number 1-100, state persisted in sp_games.
|
||||
require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
$me = require_login();
|
||||
|
||||
function guess_load(int $uid): ?array {
|
||||
$s = db()->prepare("SELECT * FROM sp_games WHERE user_id=? AND game='guess'
|
||||
AND status='active' ORDER BY id DESC LIMIT 1");
|
||||
$s->execute([$uid]);
|
||||
return $s->fetch() ?: null;
|
||||
}
|
||||
function guess_new(int $uid): array {
|
||||
$st = json_encode(['n' => random_int(1, 100), 'tries' => 0, 'log' => []]);
|
||||
$now = time();
|
||||
db()->prepare("INSERT INTO sp_games (game,user_id,state,created_at,updated_at)
|
||||
VALUES ('guess',?,?,?,?)")->execute([$uid, $st, $now, $now]);
|
||||
return guess_load($uid);
|
||||
}
|
||||
|
||||
$msg = ''; $done = false;
|
||||
$g = guess_load((int)$me['id']);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_csrf();
|
||||
if (($_POST['act'] ?? '') === 'new') {
|
||||
if ($g) db()->prepare("UPDATE sp_games SET status='abandoned' WHERE id=?")->execute([$g['id']]);
|
||||
$g = guess_new((int)$me['id']);
|
||||
$msg = 'New game! Guess a number between 1 and 100.';
|
||||
} else {
|
||||
if (!$g) $g = guess_new((int)$me['id']);
|
||||
$st = json_decode($g['state'], true);
|
||||
$gv = (int)($_POST['guess'] ?? 0);
|
||||
if ($gv < 1 || $gv > 100) {
|
||||
$msg = 'Enter a number from 1 to 100.';
|
||||
} else {
|
||||
$st['tries']++;
|
||||
$st['log'][] = $gv;
|
||||
if ($gv === (int)$st['n']) {
|
||||
$score = max(1, 110 - 10 * (int)$st['tries']);
|
||||
db()->prepare("UPDATE sp_games SET status='won', state=?, updated_at=? WHERE id=?")
|
||||
->execute([json_encode($st), time(), $g['id']]);
|
||||
db()->prepare("INSERT INTO scores (game,user_id,score,detail,created_at)
|
||||
VALUES ('guess',?,?,?,?)")
|
||||
->execute([$me['id'], $score, $st['tries'] . ' tries', time()]);
|
||||
$msg = "Correct! $gv was the number, in {$st['tries']} tries. Score: $score";
|
||||
$done = true; $g = null;
|
||||
} else {
|
||||
$msg = $gv . ' is too ' . ($gv < (int)$st['n'] ? 'LOW' : 'HIGH')
|
||||
. '. Tries: ' . $st['tries'];
|
||||
db()->prepare("UPDATE sp_games SET state=?, updated_at=? WHERE id=?")
|
||||
->execute([json_encode($st), time(), $g['id']]);
|
||||
$g['state'] = json_encode($st);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page_start('Guess the Number', ['back' => '/games.php']);
|
||||
if ($msg) p_para($msg);
|
||||
if ($g) {
|
||||
$st = json_decode($g['state'], true);
|
||||
if ($st['log']) p_para('Previous: ' . implode(', ', array_slice($st['log'], -8)));
|
||||
p_form('/games/guess.php', [
|
||||
['name' => 'guess', 'label' => 'Your guess (1-100)', 'maxlength' => 3,
|
||||
'format' => '*N'],
|
||||
], 'Guess');
|
||||
} else {
|
||||
if (!$done) p_para('Guess the secret number between 1 and 100. Fewer tries = more points.');
|
||||
}
|
||||
p_form('/games/guess.php', [
|
||||
['name' => 'act', 'type' => 'hidden', 'value' => 'new'],
|
||||
], $g ? 'Restart' : 'New game');
|
||||
p_links([['/games/scores.php', 'High scores', ['g' => 'guess']], ['/games.php', 'Games']]);
|
||||
page_end();
|
||||
82
public_html/games/mplib.php
Normal file
82
public_html/games/mplib.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// Shared helpers for turn-based multiplayer games stored in `matches`.
|
||||
require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
|
||||
function mp_create(string $game, int $uid, string $state): int {
|
||||
$now = time();
|
||||
db()->prepare("INSERT INTO matches (game,p1,turn,state,status,created_at,updated_at)
|
||||
VALUES (?,?,1,?, 'open',?,?)")
|
||||
->execute([$game, $uid, $state, $now, $now]);
|
||||
return (int)db()->lastInsertId();
|
||||
}
|
||||
|
||||
function mp_join(string $game, int $mid, int $uid): bool {
|
||||
$s = db()->prepare("SELECT * FROM matches WHERE id=? AND game=?");
|
||||
$s->execute([$mid, $game]);
|
||||
$m = $s->fetch();
|
||||
if (!$m || $m['status'] !== 'open' || (int)$m['p1'] === $uid) return false;
|
||||
db()->prepare("UPDATE matches SET p2=?, status='playing', updated_at=? WHERE id=?")
|
||||
->execute([$uid, time(), $mid]);
|
||||
return true;
|
||||
}
|
||||
|
||||
function mp_get(string $game, int $mid): ?array {
|
||||
$s = db()->prepare("SELECT m.*, a.username AS n1, b.username AS n2
|
||||
FROM matches m
|
||||
LEFT JOIN users a ON a.id=m.p1
|
||||
LEFT JOIN users b ON b.id=m.p2
|
||||
WHERE m.id=? AND m.game=?");
|
||||
$s->execute([$mid, $game]);
|
||||
return $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
function mp_save(int $mid, string $state, int $turn, string $status = 'playing', ?int $winner = null): void {
|
||||
db()->prepare("UPDATE matches SET state=?, turn=?, status=?, winner=?, updated_at=? WHERE id=?")
|
||||
->execute([$state, $turn, $status, $winner, time(), $mid]);
|
||||
}
|
||||
|
||||
// Which seat is this user in? 1, 2, or 0 for spectator.
|
||||
function mp_seat(array $m, int $uid): int {
|
||||
if ((int)$m['p1'] === $uid) return 1;
|
||||
if ((int)$m['p2'] === $uid) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Render the lobby: open games to join, your active games, and a create button.
|
||||
function mp_lobby(string $game, string $self, int $uid, string $newState): void {
|
||||
$d = db();
|
||||
$s = $d->prepare("SELECT m.*, a.username AS n1 FROM matches m
|
||||
LEFT JOIN users a ON a.id=m.p1
|
||||
WHERE m.game=? AND m.status='open' AND m.p1<>?
|
||||
ORDER BY m.id DESC LIMIT 10");
|
||||
$s->execute([$game, $uid]);
|
||||
$open = $s->fetchAll();
|
||||
|
||||
$s = $d->prepare("SELECT m.*, a.username AS n1, b.username AS n2 FROM matches m
|
||||
LEFT JOIN users a ON a.id=m.p1
|
||||
LEFT JOIN users b ON b.id=m.p2
|
||||
WHERE m.game=? AND (m.p1=? OR m.p2=?) AND m.status IN ('open','playing')
|
||||
ORDER BY m.updated_at DESC LIMIT 10");
|
||||
$s->execute([$game, $uid, $uid]);
|
||||
$mine = $s->fetchAll();
|
||||
|
||||
if ($mine) {
|
||||
p_para('Your games:');
|
||||
foreach ($mine as $m) {
|
||||
$opp = ((int)$m['p1'] === $uid) ? ($m['n2'] ?? 'waiting...') : ($m['n1'] ?? '?');
|
||||
$yourTurn = ($m['status'] === 'playing' && mp_seat($m, $uid) === (int)$m['turn']);
|
||||
p_link($self, '#' . $m['id'] . ' vs ' . $opp . ($yourTurn ? ' - YOUR TURN' : ''),
|
||||
['g' => $m['id']]);
|
||||
}
|
||||
}
|
||||
if ($open) {
|
||||
p_para('Open games to join:');
|
||||
foreach ($open as $m) {
|
||||
p_link($self, 'Join #' . $m['id'] . ' by ' . ($m['n1'] ?? '?'), ['g' => $m['id'], 'join' => 1]);
|
||||
}
|
||||
}
|
||||
if (!$mine && !$open) p_para('No games yet - create one and wait for an opponent.');
|
||||
p_form($self, [
|
||||
['name' => 'act', 'type' => 'hidden', 'value' => 'create'],
|
||||
], 'Create new game');
|
||||
}
|
||||
95
public_html/games/nim.php
Normal file
95
public_html/games/nim.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
// Multiplayer Nim: 21 sticks, take 1-3, whoever takes the last stick loses.
|
||||
require_once __DIR__ . '/mplib.php';
|
||||
$me = require_login();
|
||||
$uid = (int)$me['id'];
|
||||
$SELF = '/games/nim.php';
|
||||
|
||||
$msg = '';
|
||||
$mid = (int)($_GET['g'] ?? 0);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_csrf();
|
||||
$act = $_POST['act'] ?? '';
|
||||
if ($act === 'create') {
|
||||
$mid = mp_create('nim', $uid, json_encode(['sticks' => 21]));
|
||||
redirect($SELF, ['g' => $mid]);
|
||||
}
|
||||
if ($act === 'take') {
|
||||
$mid = (int)($_POST['mid'] ?? 0);
|
||||
$m = mp_get('nim', $mid);
|
||||
$seat = $m ? mp_seat($m, $uid) : 0;
|
||||
if (!$m || $m['status'] !== 'playing') $msg = 'Game is not in play.';
|
||||
elseif ($seat === 0) $msg = 'You are not in this game.';
|
||||
elseif ($seat !== (int)$m['turn']) $msg = 'Not your turn.';
|
||||
else {
|
||||
$st = json_decode($m['state'], true);
|
||||
$n = (int)($_POST['n'] ?? 0);
|
||||
if ($n < 1 || $n > 3 || $n > (int)$st['sticks']) {
|
||||
$msg = 'Take 1 to 3 sticks (and no more than remain).';
|
||||
} else {
|
||||
$st['sticks'] -= $n;
|
||||
if ($st['sticks'] <= 0) {
|
||||
// taker of the last stick loses -> the other seat wins
|
||||
$winnerId = ($seat === 1) ? (int)$m['p2'] : (int)$m['p1'];
|
||||
mp_save($mid, json_encode($st), $seat, 'done', $winnerId);
|
||||
db()->prepare("INSERT INTO scores (game,user_id,score,detail,created_at)
|
||||
VALUES ('nim',?,?,?,?)")
|
||||
->execute([$winnerId, 40, 'win', time()]);
|
||||
$msg = 'You took the last stick - you lose!';
|
||||
} else {
|
||||
mp_save($mid, json_encode($st), $seat === 1 ? 2 : 1);
|
||||
$msg = 'You took ' . $n . '. ' . $st['sticks'] . ' left.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mid && !empty($_GET['join'])) {
|
||||
$msg = mp_join('nim', $mid, $uid) ? 'You joined the game.' : 'Could not join that game.';
|
||||
}
|
||||
|
||||
page_start('Nim - 21 sticks', ['back' => '/games.php']);
|
||||
if ($msg) p_para($msg);
|
||||
|
||||
if (!$mid) {
|
||||
p_para('21 sticks. Players alternate taking 1, 2 or 3. Take the LAST stick and you lose.');
|
||||
mp_lobby('nim', $SELF, $uid, json_encode(['sticks' => 21]));
|
||||
p_links([['/games.php', 'Games']]);
|
||||
page_end();
|
||||
exit;
|
||||
}
|
||||
|
||||
$m = mp_get('nim', $mid);
|
||||
if (!$m) bail('Game', 'No such game.', $SELF);
|
||||
$st = json_decode($m['state'], true);
|
||||
$seat = mp_seat($m, $uid);
|
||||
$left = (int)$st['sticks'];
|
||||
|
||||
p_para('#' . $m['id'] . ': ' . ($m['n1'] ?? '?') . ' vs ' . ($m['n2'] ?? 'waiting'));
|
||||
p_para('Sticks left: ' . $left);
|
||||
if ($left > 0) p_para(str_repeat('|', min($left, 21)));
|
||||
p_rule();
|
||||
|
||||
if ($m['status'] === 'open') {
|
||||
p_para('Waiting for an opponent to join.');
|
||||
} elseif ($m['status'] === 'done') {
|
||||
$wn = ((int)$m['winner'] === (int)$m['p1']) ? $m['n1'] : $m['n2'];
|
||||
p_para('Winner: ' . ($wn ?? '?'));
|
||||
} elseif ($seat === 0) {
|
||||
p_para('Spectating. Turn: player ' . $m['turn']);
|
||||
} elseif ($seat === (int)$m['turn']) {
|
||||
p_para('Your turn. Take how many?');
|
||||
p_form($SELF . '?g=' . $mid, [
|
||||
['name' => 'act', 'type' => 'hidden', 'value' => 'take'],
|
||||
['name' => 'mid', 'type' => 'hidden', 'value' => (string)$mid],
|
||||
['name' => 'n', 'label' => 'Take', 'type' => 'select',
|
||||
'options' => ['1' => '1 stick', '2' => '2 sticks', '3' => '3 sticks']],
|
||||
], 'Take');
|
||||
} else {
|
||||
p_para('Opponent to move.');
|
||||
}
|
||||
|
||||
p_links([[$SELF, 'Refresh', ['g' => $mid]], [$SELF, 'Lobby'], ['/games.php', 'Games']]);
|
||||
page_end();
|
||||
82
public_html/games/quiz.php
Normal file
82
public_html/games/quiz.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
// Single player: 5-question multiple choice quiz, one question per deck.
|
||||
require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
$me = require_login();
|
||||
|
||||
$QUESTIONS = [
|
||||
['What does WAP stand for?', ['Wireless Application Protocol','Web Access Point','Wide Area Paging','Wireless Audio Player'], 0],
|
||||
['WML is based on which language?', ['HTML','XML','SGML','JSON'], 1],
|
||||
['Which company made the Nokia 7110, the first big WAP phone?', ['Ericsson','Motorola','Nokia','Siemens'], 2],
|
||||
['A WML file is made up of one or more...', ['Pages','Cards','Frames','Slides'], 1],
|
||||
['What year was WAP 1.1 published?', ['1996','1999','2002','2005'], 1],
|
||||
['Default MIME type for WML is text/vnd.wap...?', ['wap','wml','xml','wsp'], 1],
|
||||
['GPRS stands for General Packet Radio...?', ['System','Service','Standard','Stream'], 1],
|
||||
];
|
||||
|
||||
function quiz_load(int $uid): ?array {
|
||||
$s = db()->prepare("SELECT * FROM sp_games WHERE user_id=? AND game='quiz'
|
||||
AND status='active' ORDER BY id DESC LIMIT 1");
|
||||
$s->execute([$uid]);
|
||||
return $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
$msg = '';
|
||||
$g = quiz_load((int)$me['id']);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_csrf();
|
||||
$act = $_POST['act'] ?? '';
|
||||
if ($act === 'new' || !$g) {
|
||||
if ($g) db()->prepare("UPDATE sp_games SET status='abandoned' WHERE id=?")->execute([$g['id']]);
|
||||
$keys = array_keys($QUESTIONS);
|
||||
shuffle($keys);
|
||||
$keys = array_slice($keys, 0, 5);
|
||||
$st = json_encode(['q' => $keys, 'i' => 0, 'right' => 0]);
|
||||
$now = time();
|
||||
db()->prepare("INSERT INTO sp_games (game,user_id,state,created_at,updated_at)
|
||||
VALUES ('quiz',?,?,?,?)")->execute([$me['id'], $st, $now, $now]);
|
||||
$g = quiz_load((int)$me['id']);
|
||||
$msg = 'New quiz: 5 questions.';
|
||||
} elseif ($act === 'ans') {
|
||||
$st = json_decode($g['state'], true);
|
||||
$qi = $QUESTIONS[$st['q'][$st['i']]];
|
||||
$pick = (int)($_POST['a'] ?? -1);
|
||||
if ($pick === (int)$qi[2]) { $st['right']++; $msg = 'Correct!'; }
|
||||
else $msg = 'Wrong - it was: ' . $qi[1][$qi[2]];
|
||||
$st['i']++;
|
||||
if ($st['i'] >= count($st['q'])) {
|
||||
$score = $st['right'] * 20;
|
||||
db()->prepare("UPDATE sp_games SET status='done', state=?, updated_at=? WHERE id=?")
|
||||
->execute([json_encode($st), time(), $g['id']]);
|
||||
db()->prepare("INSERT INTO scores (game,user_id,score,detail,created_at)
|
||||
VALUES ('quiz',?,?,?,?)")
|
||||
->execute([$me['id'], $score, $st['right'] . '/5', time()]);
|
||||
$msg .= ' Quiz over: ' . $st['right'] . '/5 correct, score ' . $score . '.';
|
||||
$g = null;
|
||||
} else {
|
||||
db()->prepare("UPDATE sp_games SET state=?, updated_at=? WHERE id=?")
|
||||
->execute([json_encode($st), time(), $g['id']]);
|
||||
$g['state'] = json_encode($st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page_start('Quick Quiz', ['back' => '/games.php']);
|
||||
if ($msg) p_para($msg);
|
||||
|
||||
if ($g) {
|
||||
$st = json_decode($g['state'], true);
|
||||
$qi = $QUESTIONS[$st['q'][$st['i']]];
|
||||
p_para('Q' . ($st['i'] + 1) . '/' . count($st['q']) . ': ' . $qi[0]);
|
||||
$opts = [];
|
||||
foreach ($qi[1] as $k => $lab) $opts[(string)$k] = $lab;
|
||||
p_form('/games/quiz.php', [
|
||||
['name' => 'act', 'type' => 'hidden', 'value' => 'ans'],
|
||||
['name' => 'a', 'label' => 'Answer', 'type' => 'select', 'options' => $opts],
|
||||
], 'Answer');
|
||||
} else {
|
||||
p_para('A short quiz about WAP and mobile history. 20 points per correct answer.');
|
||||
p_form('/games/quiz.php', [['name' => 'act', 'type' => 'hidden', 'value' => 'new']], 'Start quiz');
|
||||
}
|
||||
p_links([['/games/scores.php', 'High scores', ['g' => 'quiz']], ['/games.php', 'Games']]);
|
||||
page_end();
|
||||
30
public_html/games/scores.php
Normal file
30
public_html/games/scores.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
$games = ['guess' => 'Guess the Number', 'quiz' => 'Quick Quiz',
|
||||
'ttt' => 'Noughts & Crosses', 'nim' => 'Nim'];
|
||||
$g = (string)($_GET['g'] ?? '');
|
||||
|
||||
page_start('High scores', ['back' => '/games.php']);
|
||||
|
||||
if (!isset($games[$g])) {
|
||||
p_para('Pick a game:');
|
||||
$links = [];
|
||||
foreach ($games as $k => $n) $links[] = ['/games/scores.php', $n, ['g' => $k]];
|
||||
p_links($links);
|
||||
} else {
|
||||
p_para($games[$g] . ' - top 10:');
|
||||
$s = db()->prepare("SELECT u.username, MAX(s.score) sc, COUNT(*) n
|
||||
FROM scores s JOIN users u ON u.id=s.user_id
|
||||
WHERE s.game=? GROUP BY s.user_id
|
||||
ORDER BY sc DESC LIMIT 10");
|
||||
$s->execute([$g]);
|
||||
$rows = $s->fetchAll();
|
||||
if (!$rows) p_para('No scores yet.');
|
||||
$i = 1;
|
||||
foreach ($rows as $r) {
|
||||
p_para($i++ . '. ' . $r['username'] . ' - ' . $r['sc'] . ' (' . $r['n'] . ' plays)');
|
||||
}
|
||||
p_links([['/games/scores.php', 'Other games']]);
|
||||
}
|
||||
p_links([['/games.php', 'Games'], ['/index.php', 'Home']]);
|
||||
page_end();
|
||||
116
public_html/games/ttt.php
Normal file
116
public_html/games/ttt.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
// Multiplayer noughts & crosses.
|
||||
require_once __DIR__ . '/mplib.php';
|
||||
$me = require_login();
|
||||
$uid = (int)$me['id'];
|
||||
$SELF = '/games/ttt.php';
|
||||
|
||||
function ttt_win(array $b): ?string {
|
||||
$lines = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
|
||||
foreach ($lines as $l) {
|
||||
if ($b[$l[0]] !== '' && $b[$l[0]] === $b[$l[1]] && $b[$l[1]] === $b[$l[2]]) return $b[$l[0]];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$msg = '';
|
||||
$mid = (int)($_GET['g'] ?? 0);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_csrf();
|
||||
$act = $_POST['act'] ?? '';
|
||||
if ($act === 'create') {
|
||||
$mid = mp_create('ttt', $uid, json_encode(['b' => array_fill(0, 9, '')]));
|
||||
redirect($SELF, ['g' => $mid]);
|
||||
}
|
||||
if ($act === 'move') {
|
||||
$mid = (int)($_POST['mid'] ?? 0);
|
||||
$m = mp_get('ttt', $mid);
|
||||
$seat = $m ? mp_seat($m, $uid) : 0;
|
||||
if (!$m || $m['status'] !== 'playing') $msg = 'Game is not in play.';
|
||||
elseif ($seat === 0) $msg = 'You are not in this game.';
|
||||
elseif ($seat !== (int)$m['turn']) $msg = 'Not your turn.';
|
||||
else {
|
||||
$st = json_decode($m['state'], true);
|
||||
$cell = (int)($_POST['cell'] ?? 0) - 1; // players type 1-9
|
||||
if ($cell < 0 || $cell > 8 || $st['b'][$cell] !== '') {
|
||||
$msg = 'That square is not free (pick 1-9).';
|
||||
} else {
|
||||
$mark = $seat === 1 ? 'X' : 'O';
|
||||
$st['b'][$cell] = $mark;
|
||||
$w = ttt_win($st['b']);
|
||||
$full = !in_array('', $st['b'], true);
|
||||
if ($w !== null) {
|
||||
mp_save($mid, json_encode($st), $seat, 'done', $uid);
|
||||
db()->prepare("INSERT INTO scores (game,user_id,score,detail,created_at)
|
||||
VALUES ('ttt',?,?,?,?)")->execute([$uid, 50, 'win', time()]);
|
||||
$msg = 'You win!';
|
||||
} elseif ($full) {
|
||||
mp_save($mid, json_encode($st), $seat, 'done', null);
|
||||
$msg = 'Draw!';
|
||||
} else {
|
||||
mp_save($mid, json_encode($st), $seat === 1 ? 2 : 1);
|
||||
$msg = 'Move played. Waiting for your opponent.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mid && !empty($_GET['join'])) {
|
||||
if (mp_join('ttt', $mid, $uid)) $msg = 'You joined the game. Player 2 is O.';
|
||||
else $msg = 'Could not join that game.';
|
||||
}
|
||||
|
||||
page_start('Noughts & Crosses', ['back' => '/games.php']);
|
||||
if ($msg) p_para($msg);
|
||||
|
||||
if (!$mid) {
|
||||
mp_lobby('ttt', $SELF, $uid, json_encode(['b' => array_fill(0, 9, '')]));
|
||||
p_links([['/games.php', 'Games']]);
|
||||
page_end();
|
||||
exit;
|
||||
}
|
||||
|
||||
$m = mp_get('ttt', $mid);
|
||||
if (!$m) bail('Game', 'No such game.', $SELF);
|
||||
$st = json_decode($m['state'], true);
|
||||
$b = $st['b'];
|
||||
$seat = mp_seat($m, $uid);
|
||||
|
||||
p_para('#' . $m['id'] . ': X=' . ($m['n1'] ?? '?') . ' vs O=' . ($m['n2'] ?? 'waiting'));
|
||||
|
||||
// board: 3 rows, free cells show their number so WAP users know what to type
|
||||
for ($r = 0; $r < 3; $r++) {
|
||||
$cells = [];
|
||||
for ($c = 0; $c < 3; $c++) {
|
||||
$i = $r * 3 + $c;
|
||||
$cells[] = $b[$i] === '' ? (string)($i + 1) : $b[$i];
|
||||
}
|
||||
p_para(implode(' | ', $cells));
|
||||
}
|
||||
p_rule();
|
||||
|
||||
if ($m['status'] === 'open') {
|
||||
p_para('Waiting for an opponent to join. Tell a friend to open Games > Noughts & Crosses.');
|
||||
} elseif ($m['status'] === 'done') {
|
||||
if ($m['winner'] === null) p_para('Result: draw.');
|
||||
else {
|
||||
$wn = ((int)$m['winner'] === (int)$m['p1']) ? $m['n1'] : $m['n2'];
|
||||
p_para('Winner: ' . $wn);
|
||||
}
|
||||
} elseif ($seat === 0) {
|
||||
p_para('You are watching. Turn: player ' . $m['turn']);
|
||||
} elseif ($seat === (int)$m['turn']) {
|
||||
p_para('Your turn (' . ($seat === 1 ? 'X' : 'O') . '). Enter a free square number.');
|
||||
p_form($SELF . '?g=' . $mid, [
|
||||
['name' => 'act', 'type' => 'hidden', 'value' => 'move'],
|
||||
['name' => 'mid', 'type' => 'hidden', 'value' => (string)$mid],
|
||||
['name' => 'cell', 'label' => 'Square (1-9)', 'maxlength' => 1, 'format' => 'N'],
|
||||
], 'Play');
|
||||
} else {
|
||||
p_para('Opponent to move. Check back shortly.');
|
||||
}
|
||||
|
||||
p_links([[$SELF, 'Refresh', ['g' => $mid]], [$SELF, 'Lobby'], ['/games.php', 'Games']]);
|
||||
page_end();
|
||||
Reference in New Issue
Block a user