{"project":{"id":"o7Gil9O","userId":"davidyarham@gmail.com","username":null,"userPicture":null,"name":"WOPR","thumbnail":"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","visible":true,"contributors":"","githubRepo":null,"forkedFrom":null,"tags":"","files":{"folder":"","files":[{"name":"index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Untitled</title>\n  <link rel=\"stylesheet\" href=\"style.css\">\n<!-- CRT Terminal -->\n</head>\n<body>\n<div class=\"crt-screen\">\n\t<div class=\"scanlines\"></div>\n\t<div class=\"crt-flicker\"></div>\n\t<div class=\"terminal\" id=\"terminal\">\n\t\t<div class=\"terminal__output\" id=\"output\"></div>\n\t\t<div class=\"terminal__input-line\" id=\"inputLine\" style=\"display:none;\">\n\t\t\t<span class=\"terminal__prompt\">&gt;&nbsp;</span>\n\t\t\t<input type=\"text\" class=\"terminal__input\" id=\"input\" autocomplete=\"off\" spellcheck=\"false\" autofocus />\n\t\t\t<span class=\"terminal__cursor\"></span>\n\t\t</div>\n\t</div>\n</div>\n<div class=\"war-overlay\" id=\"warOverlay\" style=\"display:none;\">\n\t<canvas id=\"warMap\" width=\"900\" height=\"500\"></canvas>\n\t<div class=\"war-overlay__status\" id=\"warStatus\"></div>\n</div>\n  <script type=\"module\" src=\"main.js\"></script>\n</body>\n</html>"},{"name":"main.js","content":"const output = document.getElementById('output');\nconst input = document.getElementById('input');\nconst inputLine = document.getElementById('inputLine');\nconst terminal = document.getElementById('terminal');\nconst activityLed = document.querySelector('.crt-led--activity'); // may be null in fullscreen mode\nconst warOverlay = document.getElementById('warOverlay');\nconst warMap = document.getElementById('warMap');\nconst warStatus = document.getElementById('warStatus');\nconst ctx = warMap.getContext('2d');\n\nlet state = 'BOOT';\nlet typing = false;\nlet voiceEnabled = true;\nlet tttBoard = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];\nlet tttPlayerMark = 'X';\nlet tttCpuMark = 'O';\nlet thermoWarSide = '';\nlet warAskedChess = false;\nlet defconLevel = 5;\nlet warTargets = [];\nlet gameListShown = false;\n\nconst synth = window.speechSynthesis;\n\nfunction speak(text) {\n\tif (!voiceEnabled || !synth) return;\n\tsynth.cancel();\n\tconst clean = text.replace(/[=\\-\\|+\\/\\\\_.#]/g, ' ').replace(/\\s+/g, ' ').trim();\n\tif (!clean) return;\n\tconst utter = new SpeechSynthesisUtterance(clean);\n\tutter.rate = 1.1;\n\tutter.pitch = 0.6;\n\tutter.volume = 0.8;\n\tconst voices = synth.getVoices();\n\tconst robotVoice = voices.find(v => v.name.includes('Google UK English Male')) ||\n\t\tvoices.find(v => v.name.includes('Daniel')) ||\n\t\tvoices.find(v => v.lang === 'en-US' && v.localService) ||\n\t\tvoices[0];\n\tif (robotVoice) utter.voice = robotVoice;\n\tsynth.speak(utter);\n}\n\nfunction scrollToBottom() {\n\tterminal.scrollTop = terminal.scrollHeight;\n}\n\nfunction addLine(text, cls = '') {\n\tconst span = document.createElement('span');\n\tspan.className = 'line' + (cls ? ' line--' + cls : '');\n\tspan.textContent = text;\n\toutput.appendChild(span);\n\tscrollToBottom();\n}\n\nfunction setActivity(on) {\n\tif (activityLed && on) activityLed.classList.add('active');\n\telse if (activityLed) activityLed.classList.remove('active');\n}\n\nfunction typeText(text, cls = '', speed = 30) {\n\treturn new Promise(resolve => {\n\t\ttyping = true;\n\t\tsetActivity(true);\n\t\tinputLine.style.display = 'none';\n\t\tconst span = document.createElement('span');\n\t\tspan.className = 'line' + (cls ? ' line--' + cls : '');\n\t\toutput.appendChild(span);\n\t\tlet i = 0;\n\t\tconst interval = setInterval(() => {\n\t\t\tif (i < text.length) {\n\t\t\t\tspan.textContent += text[i];\n\t\t\t\ti++;\n\t\t\t\tscrollToBottom();\n\t\t\t} else {\n\t\t\t\tclearInterval(interval);\n\t\t\t\ttyping = false;\n\t\t\t\tsetActivity(false);\n\t\t\t\tresolve();\n\t\t\t}\n\t\t}, speed);\n\t});\n}\n\nasync function typeLines(lines, cls = '', speed = 30) {\n\tfor (const line of lines) {\n\t\tawait typeText(line + '\\n', cls, speed);\n\t}\n}\n\nfunction showInput() {\n\tinputLine.style.display = 'flex';\n\tinput.value = '';\n\tinput.focus();\n\tscrollToBottom();\n}\n\nfunction waitForInput() {\n\treturn new Promise(resolve => {\n\t\tshowInput();\n\n\t\tfunction handler(e) {\n\t\t\tif (e.key === 'Enter') {\n\t\t\t\tconst val = input.value.trim().toUpperCase();\n\t\t\t\tinput.removeEventListener('keydown', handler);\n\t\t\t\tinputLine.style.display = 'none';\n\t\t\t\taddLine('> ' + val, 'user');\n\t\t\t\tresolve(val);\n\t\t\t}\n\t\t}\n\t\tinput.addEventListener('keydown', handler);\n\t});\n}\n\nfunction delay(ms) {\n\treturn new Promise(r => setTimeout(r, ms));\n}\n\n// GAME LIST from the movie\nconst GAMES_LIST = [\n\t'FALKEN\\'S MAZE',\n\t'BLACK JACK',\n\t'GIN RUMMY',\n\t'HEARTS',\n\t'BRIDGE',\n\t'CHECKERS',\n\t'CHESS',\n\t'POKER',\n\t'FIGHTER COMBAT',\n\t'GUERRILLA ENGAGEMENT',\n\t'DESERT WARFARE',\n\t'AIR-TO-GROUND ACTIONS',\n\t'THEATERWIDE TACTICAL WARFARE',\n\t'THEATERWIDE BIOTOXIC AND CHEMICAL WARFARE',\n\t'GLOBAL THERMONUCLEAR WAR',\n\t'TIC-TAC-TOE'\n];\n\nconst US_TARGETS = [\n\t'LAS VEGAS', 'SEATTLE', 'SAN FRANCISCO', 'LOS ANGELES',\n\t'NEW YORK CITY', 'WASHINGTON D.C.', 'CHICAGO', 'HOUSTON',\n\t'MIAMI', 'DENVER', 'DETROIT', 'BOSTON',\n\t'OMAHA', 'COLORADO SPRINGS', 'NORFOLK', 'SAN DIEGO'\n];\n\nconst USSR_TARGETS = [\n\t'MOSCOW', 'LENINGRAD', 'KIEV', 'MURMANSK',\n\t'VLADIVOSTOK', 'SVERDLOVSK', 'NOVOSIBIRSK', 'GORKY',\n\t'MINSK', 'RIGA', 'TBILISI', 'ODESSA',\n\t'STALINGRAD', 'SEVASTOPOL', 'ARKHANGELSK', 'KHABAROVSK'\n];\n\nfunction resolveGameByNumber(num) {\n\tif (num >= 1 && num <= GAMES_LIST.length) {\n\t\treturn GAMES_LIST[num - 1];\n\t}\n\treturn null;\n}\n\n// ============= BOOT SEQUENCE =============\nasync function boot() {\n\tawait typeText('LOGON: ', 'dim', 40);\n\tawait delay(800);\n\taddLine('');\n\tawait typeLines([\n\t\t'CONNECTING TO WOPR...',\n\t\t''\n\t], 'dim', 25);\n\tawait delay(600);\n\tawait typeLines([\n\t\t'    ██╗    ██╗ ██████╗ ██████╗ ██████╗',\n\t\t'    ██║    ██║██╔═══██╗██╔══██╗██╔══██╗',\n\t\t'    ██║ █╗ ██║██║   ██║██████╔╝██████╔╝',\n\t\t'    ██║███╗██║██║   ██║██╔═══╝ ██╔══██╗',\n\t\t'    ╚███╔███╔╝╚██████╔╝██║     ██║  ██║',\n\t\t'     ╚══╝╚══╝  ╚═════╝ ╚═╝     ╚═╝  ╚═╝',\n\t\t''\n\t], '', 8);\n\tawait delay(400);\n\tawait typeText('WOPR ONLINE - STRATEGIC DEFENSE NETWORK\\n', 'dim', 25);\n\tawait typeText('NORAD COMMAND CENTER - CHEYENNE MOUNTAIN\\n', 'dim', 25);\n\tawait delay(600);\n\taddLine('');\n\tawait greeting();\n}\n\nasync function greeting() {\n\tstate = 'GREETING';\n\tconst greet = 'GREETINGS PROFESSOR FALKEN.';\n\tspeak(greet);\n\tawait typeText(greet + '\\n', 'bright', 60);\n\tawait delay(800);\n\tstate = 'SHALL_WE_PLAY';\n\tawait shallWePlay();\n}\n\nasync function shallWePlay() {\n\tconst msg = 'SHALL WE PLAY A GAME?';\n\tspeak(msg);\n\tawait typeText(msg + '\\n\\n', '', 50);\n\tawait typeText('  [1] YES\\n', 'dim', 15);\n\tawait typeText('  [2] NO\\n\\n', 'dim', 15);\n\tconst response = await waitForInput();\n\tawait handleShallWePlay(response);\n}\n\nasync function handleShallWePlay(response) {\n\tif (response === '1' || response.includes('YES') || response.includes('SURE') || response.includes('OK') || response.includes('YEAH')) {\n\t\tawait delay(300);\n\t\tawait showGameList();\n\t} else if (response === '2' || response.includes('NO') || response === 'N') {\n\t\tconst msg = 'COME NOW, PROFESSOR. A GAME IS ALWAYS INTERESTING.';\n\t\tspeak(msg);\n\t\tawait typeText(msg + '\\n\\n', '', 40);\n\t\tawait shallWePlay();\n\t} else if (response.includes('HELP')) {\n\t\tawait typeText('TYPE A NUMBER OR A COMMAND: 1/YES, 2/NO, HELP\\n\\n', 'dim', 25);\n\t\tawait shallWePlay();\n\t} else if (response.includes('LIST') || response.includes('GAME')) {\n\t\tawait showGameList();\n\t} else {\n\t\tconst msg2 = 'I DO NOT UNDERSTAND. SHALL WE PLAY A GAME?';\n\t\tspeak(msg2);\n\t\tawait typeText(msg2 + '\\n\\n', '', 40);\n\t\tawait typeText('  [1] YES\\n', 'dim', 15);\n\t\tawait typeText('  [2] NO\\n\\n', 'dim', 15);\n\t\tconst r2 = await waitForInput();\n\t\tawait handleShallWePlay(r2);\n\t}\n}\n\nasync function showGameList() {\n\tstate = 'GAME_LIST';\n\tgameListShown = true;\n\taddLine('');\n\tawait typeText('GAMES AVAILABLE:\\n\\n', 'bright', 40);\n\tfor (let i = 0; i < GAMES_LIST.length; i++) {\n\t\tconst num = String(i + 1).padStart(2, ' ');\n\t\tconst g = GAMES_LIST[i];\n\t\tif (g === 'GLOBAL THERMONUCLEAR WAR') {\n\t\t\taddLine('');\n\t\t\taddLine('  [' + num + ']  ' + g, 'bright');\n\t\t\taddLine('');\n\t\t} else {\n\t\t\taddLine('  [' + num + ']  ' + g);\n\t\t}\n\t}\n\tscrollToBottom();\n\taddLine('');\n\tconst msg = 'ENTER NUMBER OR NAME OF GAME:';\n\tspeak(msg);\n\tawait typeText(msg + '\\n\\n', '', 40);\n\tconst choice = await waitForInput();\n\tawait handleGameChoice(choice);\n}\n\nasync function handleGameChoice(choice) {\n\t// Check if user typed a number\n\tconst num = parseInt(choice);\n\tif (num >= 1 && num <= GAMES_LIST.length) {\n\t\tconst gameName = GAMES_LIST[num - 1];\n\t\t// Re-route through name matching\n\t\treturn await handleGameChoice(gameName);\n\t}\n\n\tif (choice.includes('GLOBAL') || choice.includes('THERMONUCLEAR') || choice.includes('WAR')) {\n\t\tif (!warAskedChess) {\n\t\t\twarAskedChess = true;\n\t\t\taddLine('');\n\t\t\tconst msg = 'WOULDN\\'T YOU PREFER A NICE GAME OF CHESS?';\n\t\t\tspeak(msg);\n\t\t\tawait typeText(msg + '\\n\\n', 'bright', 50);\n\t\t\tawait typeText('  [1] YES, PLAY CHESS\\n', 'dim', 15);\n\t\t\tawait typeText('  [2] NO, I WANT THERMONUCLEAR WAR\\n\\n', 'dim', 15);\n\t\t\tconst r = await waitForInput();\n\t\t\tif (r === '2' || r.includes('NO') || r.includes('WAR') || r.includes('THERMO') || r.includes('GLOBAL') || r.includes('LATER')) {\n\t\t\t\tawait startThermonuclearWar();\n\t\t\t} else if (r === '1' || r.includes('CHESS') || r.includes('YES') || r.includes('OK')) {\n\t\t\t\tawait typeText('\\nCHESS IS NOT YET IMPLEMENTED IN THIS TERMINAL.\\nPERHAPS ANOTHER GAME?\\n\\n', 'dim', 30);\n\t\t\t\tawait showGameList();\n\t\t\t} else {\n\t\t\t\tawait startThermonuclearWar();\n\t\t\t}\n\t\t} else {\n\t\t\tawait startThermonuclearWar();\n\t\t}\n\t} else if (choice.includes('TIC') || choice.includes('TAC') || choice.includes('TOE')) {\n\t\tawait startTicTacToe();\n\t} else if (choice.includes('CHESS')) {\n\t\tawait typeText('\\nLOADING TIC-TAC-TOE INSTEAD...\\n', 'dim', 30);\n\t\tawait startTicTacToe();\n\t} else if (choice.includes('CHECKER') || choice.includes('POKER') || choice.includes('JACK') || choice.includes('HEART') || choice.includes('BRIDGE') || choice.includes('RUMMY') || choice.includes('MAZE')) {\n\t\tconst msg = 'THAT GAME IS CLASSIFIED. ACCESS DENIED.';\n\t\tspeak(msg);\n\t\tawait typeText('\\n' + msg + '\\n', '', 40);\n\t\tawait typeText('CHOOSE ANOTHER GAME.\\n\\n', 'dim', 30);\n\t\tconst c2 = await waitForInput();\n\t\tawait handleGameChoice(c2);\n\t} else if (choice.includes('FIGHTER') || choice.includes('GUERRILLA') || choice.includes('DESERT') || choice.includes('TACTICAL') || choice.includes('BIOTOXIC') || choice.includes('AIR')) {\n\t\tconst msg = 'INTERESTING CHOICE. BUT THAT SCENARIO IS CURRENTLY OFFLINE.';\n\t\tspeak(msg);\n\t\tawait typeText('\\n' + msg + '\\n', '', 40);\n\t\tawait typeText('CHOOSE ANOTHER GAME.\\n\\n', 'dim', 30);\n\t\tconst c2 = await waitForInput();\n\t\tawait handleGameChoice(c2);\n\t} else {\n\t\tawait typeText('\\nGAME NOT RECOGNIZED. PLEASE ENTER A NUMBER FROM THE LIST.\\n\\n', '', 30);\n\t\tconst c2 = await waitForInput();\n\t\tawait handleGameChoice(c2);\n\t}\n}\n\n// ============= GLOBAL THERMONUCLEAR WAR =============\nasync function startThermonuclearWar() {\n\tstate = 'THERMONUCLEAR_WAR';\n\taddLine('');\n\tawait typeText('FINE.\\n\\n', '', 60);\n\tawait delay(500);\n\tawait typeLines([\n\t\t'╔══════════════════════════════════════════╗',\n\t\t'║     GLOBAL THERMONUCLEAR WAR             ║',\n\t\t'║     STRATEGIC NUCLEAR EXCHANGE           ║',\n\t\t'╚══════════════════════════════════════════╝',\n\t\t''\n\t], 'bright', 12);\n\tawait delay(400);\n\tconst msg = 'WHICH SIDE DO YOU WANT?';\n\tspeak(msg);\n\tawait typeText(msg + '\\n\\n', '', 40);\n\tawait typeText('  [1] UNITED STATES\\n', '', 20);\n\tawait typeText('  [2] SOVIET UNION\\n\\n', '', 20);\n\tconst side = await waitForInput();\n\tif (side === '2' || side.includes('SOVIET') || side.includes('USSR') || side.includes('RUSSIA')) {\n\t\tthermoWarSide = 'USSR';\n\t\twarTargets = US_TARGETS;\n\t\tawait typeText('\\nYOU HAVE SELECTED: SOVIET UNION\\n', '', 30);\n\t\tawait typeText('TARGETING: UNITED STATES\\n\\n', 'warning', 30);\n\t} else {\n\t\tthermoWarSide = 'US';\n\t\twarTargets = USSR_TARGETS;\n\t\tawait typeText('\\nYOU HAVE SELECTED: UNITED STATES\\n', '', 30);\n\t\tawait typeText('TARGETING: SOVIET UNION\\n\\n', 'warning', 30);\n\t}\n\tspeak('LAUNCH SEQUENCE INITIATED');\n\tawait delay(600);\n\tawait typeText('AWAITING FIRST STRIKE COMMAND...\\n\\n', '', 40);\n\tawait typeText('PRIMARY TARGETS:\\n\\n', 'bright', 30);\n\tfor (let i = 0; i < warTargets.length; i++) {\n\t\taddLine('  [' + String(i + 1).padStart(2, '0') + ']  ' + warTargets[i]);\n\t}\n\tscrollToBottom();\n\taddLine('');\n\tawait typeText('ENTER TARGET NUMBER (1-' + warTargets.length + ') OR [A] FOR ALL TARGETS:\\n\\n', '', 30);\n\tconst target = await waitForInput();\n\tlet selectedTargets = [];\n\tif (target === 'A' || target.includes('ALL') || target.includes('FULL') || target.includes('EVERYTHING')) {\n\t\tselectedTargets = [...warTargets];\n\t\tawait typeText('\\n*** FULL STRATEGIC STRIKE AUTHORIZED ***\\n', 'warning', 30);\n\t} else {\n\t\tconst tnum = parseInt(target);\n\t\tif (tnum >= 1 && tnum <= warTargets.length) {\n\t\t\tselectedTargets = [warTargets[tnum - 1]];\n\t\t\tawait typeText('\\nTARGET LOCKED: ' + warTargets[tnum - 1] + '\\n', 'warning', 30);\n\t\t} else {\n\t\t\tselectedTargets = [warTargets[0]];\n\t\t\tawait typeText('\\nINVALID. DEFAULTING TO: ' + warTargets[0] + '\\n', 'warning', 30);\n\t\t}\n\t}\n\tspeak('MISSILES LAUNCHED');\n\tawait delay(500);\n\tawait typeText('\\nLAUNCH SEQUENCE INITIATED...\\n', 'bright', 40);\n\tawait typeText('DEFCON 4...\\n', 'warning', 60);\n\tawait delay(400);\n\tawait typeText('DEFCON 3...\\n', 'warning', 60);\n\tawait delay(400);\n\tawait typeText('DEFCON 2...\\n', 'warning', 60);\n\tawait delay(400);\n\tawait typeText('DEFCON 1\\n\\n', 'warning', 80);\n\tspeak('DEFCON 1. Missiles are in the air.');\n\tawait delay(800);\n\n\tawait showWarMap(selectedTargets);\n}\n\nasync function showWarMap(targets) {\n\twarOverlay.style.display = 'flex';\n\tconst W = warMap.width;\n\tconst H = warMap.height;\n\n\tfunction drawWorldOutline() {\n\t\tctx.fillStyle = '#0a0a0a';\n\t\tctx.fillRect(0, 0, W, H);\n\t\tctx.strokeStyle = '#1a4a1a';\n\t\tctx.lineWidth = 1;\n\t\tctx.beginPath();\n\t\tctx.moveTo(120, 80);\n\t\tctx.lineTo(180, 60);\n\t\tctx.lineTo(250, 70);\n\t\tctx.lineTo(280, 100);\n\t\tctx.lineTo(270, 150);\n\t\tctx.lineTo(250, 180);\n\t\tctx.lineTo(220, 200);\n\t\tctx.lineTo(200, 230);\n\t\tctx.lineTo(180, 260);\n\t\tctx.lineTo(160, 250);\n\t\tctx.lineTo(140, 200);\n\t\tctx.lineTo(110, 160);\n\t\tctx.lineTo(100, 120);\n\t\tctx.closePath();\n\t\tctx.stroke();\n\t\tctx.beginPath();\n\t\tctx.moveTo(420, 70);\n\t\tctx.lineTo(470, 60);\n\t\tctx.lineTo(500, 80);\n\t\tctx.lineTo(510, 120);\n\t\tctx.lineTo(490, 150);\n\t\tctx.lineTo(450, 160);\n\t\tctx.lineTo(430, 140);\n\t\tctx.lineTo(420, 100);\n\t\tctx.closePath();\n\t\tctx.stroke();\n\t\tctx.beginPath();\n\t\tctx.moveTo(500, 50);\n\t\tctx.lineTo(600, 40);\n\t\tctx.lineTo(720, 50);\n\t\tctx.lineTo(780, 70);\n\t\tctx.lineTo(800, 100);\n\t\tctx.lineTo(750, 130);\n\t\tctx.lineTo(650, 140);\n\t\tctx.lineTo(550, 130);\n\t\tctx.lineTo(510, 110);\n\t\tctx.closePath();\n\t\tctx.stroke();\n\t\tctx.strokeStyle = '#0d2a0d';\n\t\tctx.lineWidth = 0.5;\n\t\tfor (let x = 0; x < W; x += 60) {\n\t\t\tctx.beginPath();\n\t\t\tctx.moveTo(x, 0);\n\t\t\tctx.lineTo(x, H);\n\t\t\tctx.stroke();\n\t\t}\n\t\tfor (let y = 0; y < H; y += 50) {\n\t\t\tctx.beginPath();\n\t\t\tctx.moveTo(0, y);\n\t\t\tctx.lineTo(W, y);\n\t\t\tctx.stroke();\n\t\t}\n\t\tctx.fillStyle = '#1a5a1a';\n\t\tctx.font = '12px Courier New, monospace';\n\t\tctx.fillText('UNITED STATES', 130, 170);\n\t\tctx.fillText('USSR', 640, 85);\n\t\tctx.fillText('NORAD', 200, 155);\n\t}\n\n\tdrawWorldOutline();\n\twarStatus.textContent = 'STRATEGIC DEFENSE NETWORK - TRACKING';\n\n\tconst usCities = {\n\t\t'LAS VEGAS': [190, 155],\n\t\t'SEATTLE': [130, 100],\n\t\t'SAN FRANCISCO': [120, 140],\n\t\t'LOS ANGELES': [140, 160],\n\t\t'NEW YORK CITY': [260, 120],\n\t\t'WASHINGTON D.C.': [255, 135],\n\t\t'CHICAGO': [220, 115],\n\t\t'HOUSTON': [195, 185],\n\t\t'MIAMI': [250, 195],\n\t\t'DENVER': [180, 130],\n\t\t'DETROIT': [235, 110],\n\t\t'BOSTON': [268, 110],\n\t\t'OMAHA': [200, 120],\n\t\t'COLORADO SPRINGS': [185, 135],\n\t\t'NORFOLK': [260, 145],\n\t\t'SAN DIEGO': [135, 165]\n\t};\n\tconst ussrCities = {\n\t\t'MOSCOW': [550, 75],\n\t\t'LENINGRAD': [530, 55],\n\t\t'KIEV': [530, 95],\n\t\t'MURMANSK': [530, 40],\n\t\t'VLADIVOSTOK': [780, 95],\n\t\t'SVERDLOVSK': [610, 65],\n\t\t'NOVOSIBIRSK': [660, 70],\n\t\t'GORKY': [560, 70],\n\t\t'MINSK': [520, 80],\n\t\t'RIGA': [510, 70],\n\t\t'TBILISI': [550, 110],\n\t\t'ODESSA': [530, 105],\n\t\t'STALINGRAD': [570, 95],\n\t\t'SEVASTOPOL': [535, 110],\n\t\t'ARKHANGELSK': [555, 45],\n\t\t'KHABAROVSK': [760, 80]\n\t};\n\n\tconst cityMap = thermoWarSide === 'US' ? ussrCities : usCities;\n\tconst launchFrom = thermoWarSide === 'US' ? [200, 140] : [620, 80];\n\n\tlet missiles = targets.map(t => ({\n\t\tname: t,\n\t\ttarget: cityMap[t] || [W / 2, H / 2],\n\t\tprogress: 0,\n\t\thit: false\n\t}));\n\n\tlet frame = 0;\n\tconst totalFrames = 420;\n\tlet retaliationStarted = false;\n\tlet retaliationMissiles = [];\n\tconst explosions = [];\n\n\tconst retFrom = thermoWarSide === 'US' ? ussrCities : usCities;\n\tconst retTo = thermoWarSide === 'US' ? usCities : ussrCities;\n\tconst retFromKeys = Object.keys(retFrom);\n\tconst retToKeys = Object.keys(retTo);\n\n\tfunction animate() {\n\t\tframe++;\n\t\tdrawWorldOutline();\n\n\t\tctx.fillStyle = '#33ff33';\n\t\tfor (const m of missiles) {\n\t\t\tconst [tx, ty] = m.target;\n\t\t\tif (!m.hit) {\n\t\t\t\tctx.beginPath();\n\t\t\t\tctx.arc(tx, ty, 3 + Math.sin(frame * 0.15) * 2, 0, Math.PI * 2);\n\t\t\t\tctx.stroke();\n\t\t\t\tctx.strokeStyle = '#33ff33';\n\t\t\t}\n\t\t}\n\n\t\tfor (const m of missiles) {\n\t\t\tm.progress = Math.min(1, frame / (totalFrames * 0.6));\n\t\t\t// Draw curved trail with segments\n\t\t\tconst segs = Math.max(2, Math.floor(m.progress * 40));\n\t\t\tctx.lineWidth = 1;\n\t\t\tctx.setLineDash([]);\n\t\t\tfor (let s = 0; s < segs; s++) {\n\t\t\t\tconst t0 = (s / segs) * m.progress;\n\t\t\t\tconst t1 = ((s + 1) / segs) * m.progress;\n\t\t\t\tconst x0 = launchFrom[0] + (m.target[0] - launchFrom[0]) * t0;\n\t\t\t\tconst y0 = launchFrom[1] + (m.target[1] - launchFrom[1]) * t0 - Math.sin(t0 * Math.PI) * 110;\n\t\t\t\tconst x1 = launchFrom[0] + (m.target[0] - launchFrom[0]) * t1;\n\t\t\t\tconst y1 = launchFrom[1] + (m.target[1] - launchFrom[1]) * t1 - Math.sin(t1 * Math.PI) * 110;\n\t\t\t\tconst alpha = 0.15 + 0.85 * (s / segs);\n\t\t\t\tctx.strokeStyle = `rgba(51,255,51,${alpha})`;\n\t\t\t\tctx.beginPath();\n\t\t\t\tctx.moveTo(x0, y0);\n\t\t\t\tctx.lineTo(x1, y1);\n\t\t\t\tctx.stroke();\n\t\t\t}\n\t\t\tconst cx = launchFrom[0] + (m.target[0] - launchFrom[0]) * m.progress;\n\t\t\tconst cy = launchFrom[1] + (m.target[1] - launchFrom[1]) * m.progress - Math.sin(m.progress * Math.PI) * 110;\n\t\t\tif (m.progress < 1) {\n\t\t\t\t// Glowing warhead\n\t\t\t\tctx.fillStyle = 'rgba(150,255,150,0.3)';\n\t\t\t\tctx.beginPath();\n\t\t\t\tctx.arc(cx, cy, 6, 0, Math.PI * 2);\n\t\t\t\tctx.fill();\n\t\t\t\tctx.fillStyle = '#88ff88';\n\t\t\t\tctx.beginPath();\n\t\t\t\tctx.arc(cx, cy, 2.5, 0, Math.PI * 2);\n\t\t\t\tctx.fill();\n\t\t\t}\n\t\t\tif (m.progress >= 1 && !m.hit) {\n\t\t\t\tm.hit = true;\n\t\t\t\texplosions.push({\n\t\t\t\t\tx: m.target[0],\n\t\t\t\t\ty: m.target[1],\n\t\t\t\t\tframe: 0,\n\t\t\t\t\tname: m.name\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (frame === 160 && !retaliationStarted) {\n\t\t\tretaliationStarted = true;\n\t\t\tfor (let i = 0; i < 10; i++) {\n\t\t\t\tconst fromKey = retFromKeys[i % retFromKeys.length];\n\t\t\t\tconst toKey = retToKeys[i % retToKeys.length];\n\t\t\t\tretaliationMissiles.push({\n\t\t\t\t\tfrom: retFrom[fromKey],\n\t\t\t\t\ttarget: retTo[toKey],\n\t\t\t\t\tprogress: 0,\n\t\t\t\t\thit: false,\n\t\t\t\t\tname: toKey\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const rm of retaliationMissiles) {\n\t\t\trm.progress = Math.min(1, (frame - 160) / (totalFrames * 0.55));\n\t\t\tif (rm.progress > 0) {\n\t\t\t\t// Draw curved trail with segments\n\t\t\t\tconst segs = Math.max(2, Math.floor(rm.progress * 40));\n\t\t\t\tctx.lineWidth = 1;\n\t\t\t\tctx.setLineDash([]);\n\t\t\t\tfor (let s = 0; s < segs; s++) {\n\t\t\t\t\tconst t0 = (s / segs) * rm.progress;\n\t\t\t\t\tconst t1 = ((s + 1) / segs) * rm.progress;\n\t\t\t\t\tconst x0 = rm.from[0] + (rm.target[0] - rm.from[0]) * t0;\n\t\t\t\t\tconst y0 = rm.from[1] + (rm.target[1] - rm.from[1]) * t0 - Math.sin(t0 * Math.PI) * 100;\n\t\t\t\t\tconst x1 = rm.from[0] + (rm.target[0] - rm.from[0]) * t1;\n\t\t\t\t\tconst y1 = rm.from[1] + (rm.target[1] - rm.from[1]) * t1 - Math.sin(t1 * Math.PI) * 100;\n\t\t\t\t\tconst alpha = 0.15 + 0.85 * (s / segs);\n\t\t\t\t\tctx.strokeStyle = `rgba(255,51,51,${alpha})`;\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.moveTo(x0, y0);\n\t\t\t\t\tctx.lineTo(x1, y1);\n\t\t\t\t\tctx.stroke();\n\t\t\t\t}\n\t\t\t\tconst cx = rm.from[0] + (rm.target[0] - rm.from[0]) * rm.progress;\n\t\t\t\tconst cy = rm.from[1] + (rm.target[1] - rm.from[1]) * rm.progress - Math.sin(rm.progress * Math.PI) * 100;\n\t\t\t\tif (rm.progress < 1) {\n\t\t\t\t\t// Glowing warhead\n\t\t\t\t\tctx.fillStyle = 'rgba(255,100,80,0.3)';\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.arc(cx, cy, 6, 0, Math.PI * 2);\n\t\t\t\t\tctx.fill();\n\t\t\t\t\tctx.fillStyle = '#ff5555';\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.arc(cx, cy, 2.5, 0, Math.PI * 2);\n\t\t\t\t\tctx.fill();\n\t\t\t\t}\n\t\t\t\tif (rm.progress >= 1 && !rm.hit) {\n\t\t\t\t\trm.hit = true;\n\t\t\t\t\texplosions.push({\n\t\t\t\t\t\tx: rm.target[0],\n\t\t\t\t\t\ty: rm.target[1],\n\t\t\t\t\t\tframe: 0,\n\t\t\t\t\t\tname: rm.name,\n\t\t\t\t\t\tred: true\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const ex of explosions) {\n\t\t\tex.frame++;\n\t\t\tconst r = Math.min(20, ex.frame * 1.5);\n\t\t\tconst alpha = Math.max(0, 1 - ex.frame / 40);\n\t\t\tconst color = ex.red ? `rgba(255,80,50,${alpha})` : `rgba(80,255,80,${alpha})`;\n\t\t\tconst color2 = ex.red ? `rgba(255,50,30,${alpha * 0.5})` : `rgba(51,255,51,${alpha * 0.5})`;\n\t\t\tctx.beginPath();\n\t\t\tctx.arc(ex.x, ex.y, r, 0, Math.PI * 2);\n\t\t\tctx.fillStyle = color;\n\t\t\tctx.fill();\n\t\t\tctx.beginPath();\n\t\t\tctx.arc(ex.x, ex.y, r * 1.8, 0, Math.PI * 2);\n\t\t\tctx.fillStyle = color2;\n\t\t\tctx.fill();\n\t\t\tif (ex.frame < 15) {\n\t\t\t\tctx.fillStyle = ex.red ? '#ff8866' : '#88ff88';\n\t\t\t\tctx.font = '10px Courier New, monospace';\n\t\t\t\tctx.fillText(ex.name, ex.x + 12, ex.y - 5);\n\t\t\t}\n\t\t}\n\n\t\tconst dc = frame < 80 ? 3 : frame < 160 ? 2 : 1;\n\t\tctx.fillStyle = dc === 1 ? '#ff3333' : '#ffaa33';\n\t\tctx.font = '18px Courier New, monospace';\n\t\tctx.fillText('DEFCON ' + dc, 20, 30);\n\n\t\tconst casualties = Math.min(520000000, Math.floor((frame / totalFrames) * 520000000));\n\t\tctx.fillStyle = '#ff5533';\n\t\tctx.font = '14px Courier New, monospace';\n\t\tctx.fillText('EST. CASUALTIES: ' + casualties.toLocaleString(), 20, H - 20);\n\n\t\tif (frame < 120) warStatus.textContent = 'MISSILES LAUNCHED - TRACKING ' + targets.length + ' WARHEADS';\n\t\telse if (frame < 180) warStatus.textContent = '*** ENEMY RETALIATION DETECTED ***';\n\t\telse if (frame < totalFrames - 30) warStatus.textContent = 'MULTIPLE IMPACTS DETECTED - HEAVY CASUALTIES';\n\t\telse warStatus.textContent = 'SIMULATION COMPLETE';\n\n\t\tif (frame < totalFrames) {\n\t\t\trequestAnimationFrame(animate);\n\t\t} else {\n\t\t\tsetTimeout(() => endWar(), 2000);\n\t\t}\n\t}\n\n\trequestAnimationFrame(animate);\n}\n\nasync function endWar() {\n\twarOverlay.style.display = 'none';\n\taddLine('');\n\tawait typeText('\\n*** SIMULATION TERMINATED ***\\n\\n', 'warning', 40);\n\tawait delay(800);\n\tawait typeText('WINNER: NONE\\n\\n', 'bright', 60);\n\tawait delay(1500);\n\n\tawait typeText('RUNNING SCENARIOS...\\n', 'dim', 30);\n\tconst scenarios = [\n\t\t'US FIRST STRIKE...      WINNER: NONE',\n\t\t'USSR FIRST STRIKE...    WINNER: NONE',\n\t\t'NATO / WARSAW PACT...   WINNER: NONE',\n\t\t'FAR EAST STRATEGY...    WINNER: NONE',\n\t\t'US USSR ESCALATION...   WINNER: NONE',\n\t\t'MIDDLE EAST WAR...      WINNER: NONE'\n\t];\n\tfor (const s of scenarios) {\n\t\tawait typeText(s + '\\n', 'dim', 10);\n\t\tawait delay(200);\n\t}\n\taddLine('');\n\tawait delay(1000);\n\n\tconst msg1 = 'A STRANGE GAME.';\n\tspeak(msg1);\n\tawait typeText(msg1 + '\\n', 'bright', 80);\n\tawait delay(1500);\n\n\tconst msg2 = 'THE ONLY WINNING MOVE IS NOT TO PLAY.';\n\tspeak(msg2);\n\tawait typeText(msg2 + '\\n\\n', 'bright', 60);\n\tawait delay(2000);\n\n\tconst msg3 = 'HOW ABOUT A NICE GAME OF TIC-TAC-TOE?';\n\tspeak(msg3);\n\tawait typeText(msg3 + '\\n\\n', '', 50);\n\tawait typeText('  [1] SHOW GAME LIST\\n', 'dim', 15);\n\tawait typeText('  [2] PLAY TIC-TAC-TOE\\n', 'dim', 15);\n\tawait typeText('  [3] PLAY AGAIN\\n\\n', 'dim', 15);\n\n\tconst resp = await waitForInput();\n\tif (resp === '3' || resp.includes('AGAIN') || resp.includes('WAR') || resp.includes('THERMO')) {\n\t\twarAskedChess = true;\n\t\tawait startThermonuclearWar();\n\t} else if (resp === '2' || resp.includes('TIC') || resp.includes('TAC')) {\n\t\tawait startTicTacToe();\n\t} else {\n\t\tawait showGameList();\n\t}\n}\n\n// ============= TIC TAC TOE =============\nfunction renderBoard() {\n\tconst b = tttBoard;\n\treturn [\n\t\t'     1   2   3',\n\t\t'   ┌───┬───┬───┐',\n\t\t' A │ ' + b[0] + ' │ ' + b[1] + ' │ ' + b[2] + ' │',\n\t\t'   ├───┼───┼───┤',\n\t\t' B │ ' + b[3] + ' │ ' + b[4] + ' │ ' + b[5] + ' │',\n\t\t'   ├───┼───┼───┤',\n\t\t' C │ ' + b[6] + ' │ ' + b[7] + ' │ ' + b[8] + ' │',\n\t\t'   └───┴───┴───┘'\n\t].join('\\n');\n}\n\nfunction checkWinner(board) {\n\tconst lines = [\n\t\t[0, 1, 2],\n\t\t[3, 4, 5],\n\t\t[6, 7, 8],\n\t\t[0, 3, 6],\n\t\t[1, 4, 7],\n\t\t[2, 5, 8],\n\t\t[0, 4, 8],\n\t\t[2, 4, 6]\n\t];\n\tfor (const [a, b, c] of lines) {\n\t\tif (board[a] !== ' ' && board[a] === board[b] && board[b] === board[c]) return board[a];\n\t}\n\tif (board.every(c => c !== ' ')) return 'TIE';\n\treturn null;\n}\n\nfunction minimax(board, isMax, mark, oppMark) {\n\tconst winner = checkWinner(board);\n\tif (winner === mark) return 10;\n\tif (winner === oppMark) return -10;\n\tif (winner === 'TIE') return 0;\n\tif (isMax) {\n\t\tlet best = -Infinity;\n\t\tfor (let i = 0; i < 9; i++) {\n\t\t\tif (board[i] === ' ') {\n\t\t\t\tboard[i] = mark;\n\t\t\t\tbest = Math.max(best, minimax(board, false, mark, oppMark));\n\t\t\t\tboard[i] = ' ';\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t} else {\n\t\tlet best = Infinity;\n\t\tfor (let i = 0; i < 9; i++) {\n\t\t\tif (board[i] === ' ') {\n\t\t\t\tboard[i] = oppMark;\n\t\t\t\tbest = Math.min(best, minimax(board, true, mark, oppMark));\n\t\t\t\tboard[i] = ' ';\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t}\n}\n\nfunction cpuMove() {\n\tlet bestScore = -Infinity;\n\tlet bestMove = -1;\n\tfor (let i = 0; i < 9; i++) {\n\t\tif (tttBoard[i] === ' ') {\n\t\t\ttttBoard[i] = tttCpuMark;\n\t\t\tconst score = minimax([...tttBoard], false, tttCpuMark, tttPlayerMark);\n\t\t\ttttBoard[i] = ' ';\n\t\t\tif (score > bestScore) {\n\t\t\t\tbestScore = score;\n\t\t\t\tbestMove = i;\n\t\t\t}\n\t\t}\n\t}\n\treturn bestMove;\n}\n\nfunction parseMove(inp) {\n\tconst mapping = {\n\t\t'A1': 0,\n\t\t'A2': 1,\n\t\t'A3': 2,\n\t\t'B1': 3,\n\t\t'B2': 4,\n\t\t'B3': 5,\n\t\t'C1': 6,\n\t\t'C2': 7,\n\t\t'C3': 8,\n\t\t'1A': 0,\n\t\t'2A': 1,\n\t\t'3A': 2,\n\t\t'1B': 3,\n\t\t'2B': 4,\n\t\t'3B': 5,\n\t\t'1C': 6,\n\t\t'2C': 7,\n\t\t'3C': 8\n\t};\n\tconst num = parseInt(inp);\n\tif (num >= 1 && num <= 9) return num - 1;\n\treturn mapping[inp.replace(/\\s/g, '')] ?? -1;\n}\n\nasync function startTicTacToe() {\n\tstate = 'TIC_TAC_TOE';\n\ttttBoard = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];\n\taddLine('');\n\tawait typeLines([\n\t\t'╔══════════════════════════════════════════╗',\n\t\t'║            TIC-TAC-TOE                   ║',\n\t\t'║       HUMAN VS. WOPR                     ║',\n\t\t'╚══════════════════════════════════════════╝',\n\t\t''\n\t], 'bright', 12);\n\n\tconst msg = 'SHALL I PLAY X OR O?';\n\tspeak(msg);\n\tawait typeText(msg + '\\n\\n', '', 40);\n\tawait typeText('  [1] YOU PLAY X (GO FIRST)\\n', 'dim', 15);\n\tawait typeText('  [2] YOU PLAY O (I GO FIRST)\\n', 'dim', 15);\n\tawait typeText('  [3] WOPR PLAYS BOTH SIDES\\n\\n', 'dim', 15);\n\tconst choice = await waitForInput();\n\tif (choice === '3' || choice.includes('BOTH') || choice.includes('SIMULATE') || choice.includes('ALL')) {\n\t\tawait simulateAllTTT();\n\t\treturn;\n\t} else if (choice === '2' || choice.includes('X')) {\n\t\ttttCpuMark = 'X';\n\t\ttttPlayerMark = 'O';\n\t\tconst r = 'I WILL BE X. YOU WILL BE O.';\n\t\tspeak(r);\n\t\tawait typeText('\\n' + r + '\\n\\n', '', 30);\n\t\tconst m = 4;\n\t\ttttBoard[m] = tttCpuMark;\n\t\tspeak('MY MOVE');\n\t\tawait typeText('MY MOVE:\\n\\n', '', 30);\n\t\taddLine(renderBoard());\n\t\taddLine('');\n\t} else {\n\t\ttttCpuMark = 'O';\n\t\ttttPlayerMark = 'X';\n\t\tconst r = 'I WILL BE O. YOU WILL BE X. YOU GO FIRST.';\n\t\tspeak(r);\n\t\tawait typeText('\\n' + r + '\\n\\n', '', 30);\n\t\taddLine(renderBoard());\n\t\taddLine('');\n\t}\n\tawait tttLoop();\n}\n\nasync function tttLoop() {\n\twhile (true) {\n\t\tconst w1 = checkWinner(tttBoard);\n\t\tif (w1) {\n\t\t\tawait tttEnd(w1);\n\t\t\treturn;\n\t\t}\n\n\t\tawait typeText('YOUR MOVE (A1-C3 OR 1-9, QUIT TO EXIT):\\n', 'dim', 20);\n\t\tconst mv = await waitForInput();\n\n\t\tif (mv === 'QUIT' || mv === 'EXIT' || mv === 'Q') {\n\t\t\tawait typeText('\\nGAME ABANDONED.\\n\\n', '', 30);\n\t\t\tawait showGameList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst idx = parseMove(mv);\n\t\tif (idx < 0 || idx > 8 || tttBoard[idx] !== ' ') {\n\t\t\tconst msg = 'ILLEGAL MOVE. TRY AGAIN.';\n\t\t\tspeak(msg);\n\t\t\tawait typeText(msg + '\\n', 'warning', 25);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttttBoard[idx] = tttPlayerMark;\n\t\taddLine(renderBoard());\n\t\taddLine('');\n\n\t\tconst w2 = checkWinner(tttBoard);\n\t\tif (w2) {\n\t\t\tawait tttEnd(w2);\n\t\t\treturn;\n\t\t}\n\n\t\tawait delay(600);\n\t\tconst cpuIdx = cpuMove();\n\t\tif (cpuIdx >= 0) {\n\t\t\ttttBoard[cpuIdx] = tttCpuMark;\n\t\t\tspeak('MY MOVE');\n\t\t\tawait typeText('MY MOVE:\\n\\n', '', 30);\n\t\t\taddLine(renderBoard());\n\t\t\taddLine('');\n\t\t}\n\n\t\tconst w3 = checkWinner(tttBoard);\n\t\tif (w3) {\n\t\t\tawait tttEnd(w3);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nasync function tttEnd(winner) {\n\taddLine('');\n\tif (winner === 'TIE') {\n\t\tconst msg = 'A DRAW. INTERESTING.';\n\t\tspeak(msg);\n\t\tawait typeText(msg + '\\n', 'bright', 50);\n\t} else if (winner === tttCpuMark) {\n\t\tconst msg = 'I WIN. HUMANS ARE PREDICTABLE.';\n\t\tspeak(msg);\n\t\tawait typeText(msg + '\\n', 'bright', 50);\n\t} else {\n\t\tconst msg = 'YOU WIN. IMPRESSIVE, PROFESSOR.';\n\t\tspeak(msg);\n\t\tawait typeText(msg + '\\n', 'bright', 50);\n\t}\n\tawait delay(1000);\n\tawait typeText('\\nWHAT WOULD YOU LIKE TO DO?\\n\\n', '', 30);\n\tawait typeText('  [1] PLAY AGAIN\\n', 'dim', 15);\n\tawait typeText('  [2] GAME LIST\\n', 'dim', 15);\n\tawait typeText('  [3] GLOBAL THERMONUCLEAR WAR\\n\\n', 'dim', 15);\n\tconst resp = await waitForInput();\n\tif (resp === '1' || resp.includes('YES') || resp.includes('Y') || resp.includes('AGAIN')) {\n\t\tawait startTicTacToe();\n\t} else if (resp === '3' || resp.includes('WAR') || resp.includes('THERMO') || resp.includes('GLOBAL')) {\n\t\twarAskedChess = true;\n\t\tawait startThermonuclearWar();\n\t} else {\n\t\tawait showGameList();\n\t}\n}\n\nfunction renderBoardFrom(b) {\n\treturn [\n\t\t'     1   2   3',\n\t\t'   ┌───┬───┬───┐',\n\t\t' A │ ' + b[0] + ' │ ' + b[1] + ' │ ' + b[2] + ' │',\n\t\t'   ├───┼───┼───┤',\n\t\t' B │ ' + b[3] + ' │ ' + b[4] + ' │ ' + b[5] + ' │',\n\t\t'   ├───┼───┼───┤',\n\t\t' C │ ' + b[6] + ' │ ' + b[7] + ' │ ' + b[8] + ' │',\n\t\t'   └───┴───┴───┘'\n\t].join('\\n');\n}\n\nfunction countAllGames(board, isX, counts) {\n\tconst w = checkWinner(board);\n\tif (w) {\n\t\tif (w === 'X') counts.x++;\n\t\telse if (w === 'O') counts.o++;\n\t\telse counts.d++;\n\t\treturn;\n\t}\n\tconst mark = isX ? 'X' : 'O';\n\tfor (let i = 0; i < 9; i++) {\n\t\tif (board[i] === ' ') {\n\t\t\tboard[i] = mark;\n\t\t\tcountAllGames(board, !isX, counts);\n\t\t\tboard[i] = ' ';\n\t\t}\n\t}\n}\n\nfunction playRandomGame() {\n\tconst board = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];\n\tconst moves = [0, 1, 2, 3, 4, 5, 6, 7, 8];\n\tfor (let i = moves.length - 1; i > 0; i--) {\n\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t[moves[i], moves[j]] = [moves[j], moves[i]];\n\t}\n\tlet mark = 'X';\n\tconst states = [];\n\tfor (const m of moves) {\n\t\tboard[m] = mark;\n\t\tstates.push([...board]);\n\t\tconst w = checkWinner(board);\n\t\tif (w) return {\n\t\t\tboard: [...board],\n\t\t\twinner: w,\n\t\t\tstates\n\t\t};\n\t\tmark = mark === 'X' ? 'O' : 'X';\n\t}\n\treturn {\n\t\tboard: [...board],\n\t\twinner: 'TIE',\n\t\tstates\n\t};\n}\n\nasync function simulateAllTTT() {\n\tstate = 'TTT_SIMULATE';\n\taddLine('');\n\tawait typeText('INITIATING LEARNING SEQUENCE...\\n', 'bright', 35);\n\tawait delay(400);\n\tawait typeText('WOPR WILL NOW PLAY ITSELF.\\n', '', 35);\n\tawait typeText('ANALYZING ALL POSSIBLE OUTCOMES...\\n\\n', '', 35);\n\tawait delay(600);\n\n\tspeak('Commencing game theory analysis.');\n\n\t// Create a live board display that updates in place\n\tconst boardContainer = document.createElement('span');\n\tboardContainer.className = 'line';\n\toutput.appendChild(boardContainer);\n\n\tconst resultLine = document.createElement('span');\n\tresultLine.className = 'line line--warning';\n\toutput.appendChild(resultLine);\n\n\taddLine('');\n\n\tconst statusSpan = document.createElement('span');\n\tstatusSpan.className = 'line line--dim';\n\toutput.appendChild(statusSpan);\n\n\tlet xWins = 0, oWins = 0, draws = 0;\n\tlet totalShown = 0;\n\tconst gamesToShow = 200;\n\n\tfor (let g = 0; g < gamesToShow; g++) {\n\t\tconst game = playRandomGame();\n\t\tif (game.winner === 'X') xWins++;\n\t\telse if (game.winner === 'O') oWins++;\n\t\telse draws++;\n\t\ttotalShown++;\n\n\t\t// Update the single board in place\n\t\tboardContainer.textContent = renderBoardFrom(game.board);\n\t\tconst resultStr = game.winner === 'TIE' ? 'DRAW' : game.winner + ' WINS';\n\t\tresultLine.textContent = '  RESULT: ' + resultStr;\n\t\tstatusSpan.textContent = 'GAME #' + totalShown + '  |  X WINS: ' + xWins + '  O WINS: ' + oWins + '  DRAWS: ' + draws;\n\t\tscrollToBottom();\n\n\t\t// Accelerate like the movie\n\t\tlet spd;\n\t\tif (g < 8) spd = 600;\n\t\telse if (g < 20) spd = 300;\n\t\telse if (g < 40) spd = 150;\n\t\telse if (g < 70) spd = 80;\n\t\telse if (g < 120) spd = 40;\n\t\telse spd = 15;\n\n\t\tawait delay(spd);\n\t}\n\n\t// Now run exhaustive count\n\tconst counts = { x: 0, o: 0, d: 0 };\n\tcountAllGames([' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], true, counts);\n\tconst totalAll = counts.x + counts.o + counts.d;\n\n\t// Rapidly flash through more games on the same board\n\tfor (let g = 0; g < 150; g++) {\n\t\tconst game = playRandomGame();\n\t\tboardContainer.textContent = renderBoardFrom(game.board);\n\t\tconst resultStr = game.winner === 'TIE' ? 'DRAW' : game.winner + ' WINS';\n\t\tresultLine.textContent = '  RESULT: ' + resultStr;\n\t\tstatusSpan.textContent = 'ANALYZING... GAME ' + (totalShown + g + 1) + ' / ' + totalAll.toLocaleString();\n\t\tscrollToBottom();\n\t\tawait delay(10);\n\t}\n\n\t// Clear the live board\n\tboardContainer.textContent = '';\n\tresultLine.textContent = '';\n\tstatusSpan.textContent = '';\n\n\tawait delay(400);\n\tawait typeText('EXHAUSTIVE ANALYSIS COMPLETE.\\n', 'bright', 30);\n\tawait typeText('ALL ' + totalAll.toLocaleString() + ' POSSIBLE GAMES EVALUATED.\\n\\n', '', 25);\n\tawait delay(500);\n\taddLine('');\n\n\tawait typeText('╔══════════════════════════════════════════╗\\n', '', 8);\n\tawait typeText('║         ANALYSIS COMPLETE                ║\\n', '', 8);\n\tawait typeText('╚══════════════════════════════════════════╝\\n\\n', '', 8);\n\n\tawait typeText('TOTAL POSSIBLE GAMES:  ' + totalAll.toLocaleString() + '\\n', 'dim', 20);\n\tawait typeText('X WINS:                ' + counts.x.toLocaleString() + '\\n', 'dim', 20);\n\tawait typeText('O WINS:                ' + counts.o.toLocaleString() + '\\n', 'dim', 20);\n\tawait typeText('DRAWS:                 ' + counts.d.toLocaleString() + '\\n\\n', 'dim', 20);\n\tawait delay(800);\n\n\tawait typeText('WITH OPTIMAL PLAY ON BOTH SIDES:\\n', 'bright', 30);\n\tawait delay(400);\n\n\tconst scenarios = [\n\t\t'X OPENS CENTER...       RESULT: DRAW',\n\t\t'X OPENS CORNER...       RESULT: DRAW',\n\t\t'X OPENS EDGE...         RESULT: DRAW',\n\t\t'O PLAYS OPTIMAL...      RESULT: DRAW',\n\t\t'X PLAYS OPTIMAL...      RESULT: DRAW',\n\t\t'RANDOM VS OPTIMAL...    RESULT: DRAW',\n\t\t'OPTIMAL VS OPTIMAL...   RESULT: DRAW',\n\t];\n\tfor (const s of scenarios) {\n\t\tawait typeText(s + '\\n', 'dim', 8);\n\t\tawait delay(150);\n\t}\n\n\taddLine('');\n\tawait delay(600);\n\n\tawait typeText('WINNER: NONE\\n\\n', 'warning', 60);\n\tawait delay(1500);\n\n\tspeak('A strange game.');\n\tawait typeText('A STRANGE GAME.\\n', 'bright', 80);\n\tawait delay(2000);\n\n\tconst msg2 = 'THE ONLY WINNING MOVE IS NOT TO PLAY.';\n\tspeak(msg2);\n\tawait typeText(msg2 + '\\n\\n', 'bright', 60);\n\tawait delay(2500);\n\n\tconst msg3 = 'HOW ABOUT A NICE GAME OF TIC-TAC-TOE?';\n\tspeak(msg3);\n\tawait typeText(msg3 + '\\n\\n', '', 50);\n\tawait delay(1000);\n\n\tawait typeText('  [1] SHOW GAME LIST\\n', 'dim', 15);\n\tawait typeText('  [2] PLAY TIC-TAC-TOE\\n', 'dim', 15);\n\tawait typeText('  [3] GLOBAL THERMONUCLEAR WAR\\n\\n', 'dim', 15);\n\n\tconst resp = await waitForInput();\n\tif (resp === '3' || resp.includes('WAR') || resp.includes('THERMO') || resp.includes('GLOBAL')) {\n\t\twarAskedChess = true;\n\t\tawait startThermonuclearWar();\n\t} else if (resp === '2' || resp.includes('TIC') || resp.includes('TAC') || resp.includes('TOE')) {\n\t\tawait startTicTacToe();\n\t} else {\n\t\tawait showGameList();\n\t}\n}\n\nterminal.addEventListener('click', () => {\n\tif (inputLine.style.display !== 'none') input.focus();\n});\n\nfunction init() {\n\tif (synth) {\n\t\tsynth.getVoices();\n\t\tif (speechSynthesis.onvoiceschanged !== undefined) {\n\t\t\tspeechSynthesis.onvoiceschanged = () => {};\n\t\t}\n\t}\n\tsetTimeout(boot, 500);\n}\n\ninit();"},{"name":"style.css","content":":root {\n\tcolor-scheme: dark;\n\t--phosphor: #33ff33;\n\t--phosphor-dim: #1a8c1a;\n\t--phosphor-glow: #33ff3380;\n\t--phosphor-bright: #88ff88;\n\t--screen-bg: #0a0a0a;\n\tfont-family: 'Courier New', Courier, monospace;\n}\n\n* {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tpadding: 0;\n}\n\nhtml, body {\n\theight: 100%;\n\twidth: 100%;\n\toverflow: hidden;\n}\n\nbody {\n\tbackground: #0a0a0a;\n\tdisplay: flex;\n}\n\n.crt-screen {\n\twidth: 100%;\n\theight: 100vh;\n\tbackground: var(--screen-bg);\n\tposition: relative;\n\toverflow: hidden;\n}\n\n.crt-screen::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset: 0;\n\tbackground: radial-gradient(ellipse at center, transparent 50%, rgba(0, 0, 0, 0.35) 100%);\n\tpointer-events: none;\n\tz-index: 10;\n}\n\n.crt-screen::after {\n\tcontent: '';\n\tposition: absolute;\n\tinset: 0;\n\tbackground: radial-gradient(ellipse at 30% 20%, rgba(51, 255, 51, 0.03) 0%, transparent 60%);\n\tpointer-events: none;\n\tz-index: 11;\n}\n\n.scanlines {\n\tposition: absolute;\n\tinset: 0;\n\tbackground: repeating-linear-gradient(to bottom,\n\t\t\ttransparent 0px,\n\t\t\ttransparent 2px,\n\t\t\trgba(0, 0, 0, 0.12) 2px,\n\t\t\trgba(0, 0, 0, 0.12) 4px);\n\tpointer-events: none;\n\tz-index: 12;\n}\n\n.crt-flicker {\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n\tz-index: 13;\n\tanimation: crt-flicker 0.1s infinite;\n\topacity: 0.02;\n\tbackground: white;\n}\n\n@keyframes crt-flicker {\n\t0%, 100% {\n\t\topacity: 0.02;\n\t}\n\n\t50% {\n\t\topacity: 0.01;\n\t}\n}\n\n.terminal {\n\theight: 100vh;\n\toverflow-y: auto;\n\tpadding: 24px 32px;\n\tposition: relative;\n\tz-index: 5;\n\tscrollbar-width: none;\n}\n\n.terminal::-webkit-scrollbar {\n\tdisplay: none;\n}\n\n.terminal__output {\n\tcolor: var(--phosphor);\n\tfont-size: 18px;\n\tline-height: 1.5;\n\twhite-space: pre-wrap;\n\tword-break: break-word;\n\n}\n\n.terminal__output .line {\n\tdisplay: block;\n\tmin-height: 1.5em;\n}\n\n.terminal__output .line--user {\n\tcolor: var(--phosphor-bright);\n}\n\n.terminal__output .line--dim {\n\tcolor: var(--phosphor-dim);\n}\n\n.terminal__output .line--bright {\n\tcolor: #ffffff;\n\n}\n\n.terminal__output .line--warning {\n\tcolor: #ff5533;\n\n}\n\n.terminal__input-line {\n\tdisplay: flex;\n\talign-items: center;\n\tmargin-top: 4px;\n\tcolor: var(--phosphor);\n\tfont-size: 18px;\n}\n\n.terminal__prompt {\n\tflex-shrink: 0;\n}\n\n.terminal__input {\n\tbackground: transparent;\n\tborder: none;\n\toutline: none;\n\tcolor: var(--phosphor-bright);\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-size: 18px;\n\tflex: 1;\n\tcaret-color: transparent;\n\ttext-transform: uppercase;\n}\n\n.terminal__cursor {\n\tdisplay: inline-block;\n\twidth: 10px;\n\theight: 20px;\n\tbackground: var(--phosphor);\n\tanimation: blink 1s step-end infinite;\n\n\tmargin-left: -2px;\n\tflex-shrink: 0;\n}\n\n@keyframes blink {\n\t0%, 100% {\n\t\topacity: 1;\n\t}\n\n\t50% {\n\t\topacity: 0;\n\t}\n}\n\n/* WAR OVERLAY */\n.war-overlay {\n\tposition: fixed;\n\tinset: 0;\n\tbackground: #0a0a0a;\n\tz-index: 1000;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.war-overlay canvas {\n\tmax-width: 95vw;\n\tmax-height: 70vh;\n\tborder: 1px solid var(--phosphor-dim);\n\tbox-shadow: 0 0 30px rgba(51, 255, 51, 0.1);\n}\n\n.war-overlay__status {\n\tcolor: var(--phosphor);\n\tfont-size: 22px;\n\tmargin-top: 20px;\n\ttext-shadow: 0 0 8px var(--phosphor-glow);\n\ttext-align: center;\n\tletter-spacing: 2px;\n\tmin-height: 60px;\n\tfont-family: 'Courier New', Courier, monospace;\n}\n\n.ttt-board {\n\tdisplay: inline-block;\n\tcolor: var(--phosphor);\n\tfont-size: 18px;\n\tline-height: 1.4;\n}\n\n@media (max-width: 640px) {\n\t.terminal {\n\t\tpadding: 16px;\n\t}\n\n\t.terminal__output, .terminal__input, .terminal__input-line {\n\t\tfont-size: 14px;\n\t}\n}"}],"folders":[]},"variants":null,"createdAt":"2026-03-01T00:12:38.664Z","updatedAt":"2026-03-01T00:24:52.817Z"}}