96 lines
3.5 KiB
PHP
96 lines
3.5 KiB
PHP
<?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();
|