prepare("SELECT * FROM sp_games WHERE user_id=? AND game='mastermind' AND status='active' ORDER BY id DESC LIMIT 1"); $s->execute([$uid]); return $s->fetch() ?: null; } function mm_new(int $uid): array { $secret = []; foreach (range(0, 3)) $secret[] = MM_COLORS[array_rand(MM_COLORS)]; $st = json_encode(['secret' => $secret, 'tries' => 0, 'log' => []]); $now = time(); db()->prepare("INSERT INTO sp_games (game,user_id,state,created_at,updated_at) VALUES ('mastermind',?,?,?,?)")->execute([$uid, $st, $now, $now]); return mm_load($uid); } function mm_feedback(array $secret, array $guess): array { $black = 0; $sCounts = []; $gCounts = []; for ($i = 0; $i < 4; $i++) { if ($guess[$i] === $secret[$i]) $black++; $sCounts[$secret[$i]] = ($sCounts[$secret[$i]] ?? 0) + 1; $gCounts[$guess[$i]] = ($gCounts[$guess[$i]] ?? 0) + 1; } $white = 0; foreach ($sCounts as $c => $n) { $white += min($n, $gCounts[$c] ?? 0); } return [$black, $white - $black]; } $msg = ''; $done = false; $g = mm_load((int)$me['id']); if ($_SERVER['REQUEST_METHOD'] === 'POST') { require_csrf(); $act = $_POST['act'] ?? ''; if ($act === 'new') { if ($g) db()->prepare("UPDATE sp_games SET status='abandoned' WHERE id=?")->execute([$g['id']]); $g = mm_new((int)$me['id']); $msg = 'New game! I have chosen a sequence of 4 colors from 1-6.'; } else { if (!$g) $g = mm_new((int)$me['id']); $st = json_decode($g['state'], true); $raw = (string)($_POST['guess'] ?? ''); if (strlen($raw) !== 4 || !ctype_digit($raw) || !array_reduce(str_split($raw), function($carry, $c) { return $carry && in_array($c, MM_COLORS, true); }, true)) { $msg = 'Enter exactly 4 digits from 1-6 (e.g. 1234).'; } else { $guess = str_split($raw); $st['tries']++; $st['log'][] = $guess; list($black, $white) = mm_feedback($st['secret'], $guess); if ($black === 4) { $score = max(1, 100 - 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 ('mastermind',?,?,?,?)") ->execute([$me['id'], $score, $st['tries'] . ' tries', time()]); $msg = "Correct! " . implode('', $st['secret']) . " in {$st['tries']} tries. Score: $score"; $done = true; $g = null; } elseif ($st['tries'] >= MM_MAX_TRIES) { db()->prepare("UPDATE sp_games SET status='lost', state=?, updated_at=? WHERE id=?") ->execute([json_encode($st), time(), $g['id']]); $msg = "Out of tries. The code was " . implode('', $st['secret']) . '.'; $done = true; $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); $msg = "Feedback: $black Black, $white White. Tries: {$st['tries']}."; } } } } page_start('Mastermind', ['back' => '/games.php']); if ($msg) p_para($msg); if ($g) { $st = json_decode($g['state'], true); if ($st['log']) { $rows = []; foreach (array_slice($st['log'], -5) as $lg) { $rows[] = implode('', $lg); } p_para('Recent guesses: ' . implode(', ', $rows)); } p_para('Guess a 4-digit code (digits 1-6).'); p_form('/games/mastermind.php', [ ['name' => 'guess', 'label' => 'Your guess (e.g. 1234)', 'maxlength' => 4, 'format' => '*N'], ], 'Guess'); } else { if (!$done) p_para('Guess the secret 4-color sequence. Black = right color and position, White = right color only.'); } p_form('/games/mastermind.php', [ ['name' => 'act', 'type' => 'hidden', 'value' => 'new'], ], $g ? 'Restart' : 'New game'); p_links([['/games/scores.php', 'High scores', ['g' => 'mastermind']], ['/games.php', 'Games']]); page_end();