# Trying to find a truly ancient computer game from vague memory

**URL:** <https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192>\
**Category:** The Game Room\
**Tags:** video-games-e-games\
**Created:** [October 27, 2026, 2:26pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192 "2026-10-27T14:26:20Z")\
**Posts on this page:** 9\
**Page:** 2

<div class="post-metadata">

**Author:** ![RitterSport](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/rittersport/32/6326_2.png) [@RitterSport](https://boards.straightdope.com/u/RitterSport)\
**Post date:** [October 30, 2026, 4:51pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/21 "2026-10-30T16:51:51Z")

</div>

Yeah, seems to be. The OP could take my prompt and modify it as necessary to make it closer.

The OP describes it as more like an Asteroids game where you’re controlling the bullet in flight.

---

<div class="post-metadata">

**Author:** ![RitterSport](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/rittersport/32/6326_2.png) [@RitterSport](https://boards.straightdope.com/u/RitterSport)\
**Post date:** [October 30, 2026, 7:52pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/22 "2026-10-30T19:52:37Z")

</div>

Is this version any closer?

> **Summary**
>
> ```auto
> <!DOCTYPE html>
> <html lang="en">
> <head>
> <meta charset="UTF-8">
> <meta name="viewport" content="width=device-width, initial-scale=1.0">
> <title>Altair 8800 BASIC - TARGET (1977)</title>
> <script src="https://cdn.tailwindcss.com"></script>
> <style>
> @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
> 
> :root {
> --term-green: #33ff33;
> --term-green-glow: rgba(51, 255, 51, 0.4);
> --term-bg: #050a05;
> --term-dim: #1a5e1a;
> }
> 
> .theme-amber {
> --term-green: #ffb000;
> --term-green-glow: rgba(255, 176, 0, 0.4);
> --term-bg: #0a0700;
> --term-dim: #5e4100;
> }
> 
> .theme-bw {
> --term-green: #e0e0e0;
> --term-green-glow: rgba(224, 224, 224, 0.25);
> --term-bg: #0a0a0a;
> --term-dim: #555555;
> }
> 
> body {
> background-color: #020202;
> color: var(--term-green);
> font-family: 'VT323', monospace;
> user-select: none;
> overflow: hidden;
> }
> 
> .crt-container {
> position: relative;
> background-color: var(--term-bg);
> border: 16px solid #1c1d22;
> border-radius: 20px;
> box-shadow: inset 0 0 80px rgba(0, 0, 0, 0.8), 0 0 30px rgba(0, 0, 0, 0.9);
> text-shadow: 0 0 6px var(--term-green-glow);
> transition: color 0.3s ease, background-color 0.3s ease;
> }
> 
> /* Scanline Overlay */
> .crt-container::before {
> content: " ";
> display: block;
> position: absolute;
> top: 0; left: 0; bottom: 0; right: 0;
> background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.35) 50%), 
> linear-gradient(90deg, rgba(255, 0, 0, 0.03), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.03));
> z-index: 20;
> background-size: 100% 4px, 6px 100%;
> pointer-events: none;
> border-radius: 8px;
> }
> 
> /* Screen Flicker */
> @keyframes flicker {
> 0% { opacity: 0.98; }
> 50% { opacity: 1; }
> 100% { opacity: 0.97; }
> }
> 
> .crt-screen {
> animation: flicker 0.15s infinite;
> }
> 
> /* Standardized 80x24 ASCII display */
> #terminal {
> display: block;
> white-space: pre;
> font-family: 'VT323', monospace;
> line-height: 1.05;
> letter-spacing: 0px;
> color: var(--term-green);
> }
> 
> .btn-retro {
> background-color: #111;
> border: 1px solid var(--term-green);
> color: var(--term-green);
> padding: 4px 10px;
> border-radius: 4px;
> font-family: 'VT323', monospace;
> transition: all 0.15s ease;
> }
> 
> .btn-retro:hover {
> background-color: var(--term-green);
> color: #000;
> box-shadow: 0 0 10px var(--term-green-glow);
> }
> 
> /* Key binding help pill */
> .key-badge {
> background-color: rgba(255, 255, 255, 0.1);
> border: 1px solid var(--term-dim);
> padding: 1px 5px;
> border-radius: 3px;
> }
> </style>
> </head>
> <body class="h-screen w-screen flex flex-col items-center justify-center p-2 sm:p-4">
> 
> <!-- CRT Monitor Frame -->
> <div class="crt-container w-full max-w-5xl p-4 md:p-6 flex flex-col items-center justify-between">
>         
> <!-- Header Banner -->
> <div class="w-full flex justify-between items-center border-b border-dashed pb-2 mb-2 text-xs sm:text-sm md:text-base opacity-90" style="border-color: var(--term-dim);">
> <div>MITS ALTAIR 8800 / TELETYPE Model 33</div>
> <div>ALTAIR BASIC v4.1 (8K)</div>
> <div id="audio-indicator">SOUND: [ON]</div>
> </div>
> 
> <!-- Terminal Screen Box -->
> <div class="crt-screen w-full flex justify-center items-center my-1 overflow-x-auto">
> <pre id="terminal" class="text-xs sm:text-sm md:text-base lg:text-lg select-none"></pre>
> </div>
> 
> <!-- On-Screen Controls Footer -->
> <div class="w-full border-t border-dashed pt-2 mt-2 flex flex-wrap justify-between items-center gap-2 text-xs sm:text-sm opacity-90" style="border-color: var(--term-dim);">
> <div class="flex flex-wrap gap-2">
> <span class="key-badge">W/A/S/D / Arrows</span>: Move
> <span class="key-badge">B</span>: Step Budget
> <span class="key-badge">T</span>: Target Quota
> <span class="key-badge">X</span>: Symbol
> </div>
> <div class="flex flex-wrap gap-2">
> <span class="key-badge">C</span>: Color Phosphor
> <span class="key-badge">M</span>: Sound
> <span class="key-badge">P</span>: Pause
> <span class="key-badge">R</span>: Restart/Reset
> </div>
> </div>
> </div>
> 
> <!-- Interactive Button Bar for Touch / Mouse Users -->
> <div class="mt-3 flex flex-wrap justify-center gap-2 max-w-5xl w-full text-xs sm:text-sm">
> <button class="btn-retro" onclick="game.handleInput('Up')">▲ [W]</button>
> <button class="btn-retro" onclick="game.handleInput('Down')">▼ [S]</button>
> <button class="btn-retro" onclick="game.handleInput('Left')">◄ [A]</button>
> <button class="btn-retro" onclick="game.handleInput('Right')">► [D]</button>
> <button class="btn-retro" onclick="game.toggleStepBudget()">Budget [B]</button>
> <button class="btn-retro" onclick="game.toggleTargetQuota()">Quota [T]</button>
> <button class="btn-retro" onclick="game.toggleSymbol()">Sprite [X]</button>
> <button class="btn-retro" onclick="game.cycleTheme()">Color [C]</button>
> <button class="btn-retro" onclick="audio.toggle()">Sound [M]</button>
> <button class="btn-retro" onclick="game.startNewGame(game.mode)">Restart [R]</button>
> </div>
> 
> <script>
> /**
> * Web Audio Synthesizer for Retro Switch/Teletype Effects
> */
> class SoundSystem {
> constructor() {
> this.ctx = null;
> this.enabled = true;
> }
> 
> init() {
> if (!this.ctx) {
> const AudioContext = window.AudioContext || window.webkitAudioContext;
> if (AudioContext) {
> this.ctx = new AudioContext();
> }
> }
> }
> 
> playStep() {
> if (!this.enabled) return;
> this.init();
> if (!this.ctx) return;
> 
> try {
> const osc = this.ctx.createOscillator();
> const gain = this.ctx.createGain();
> osc.type = 'square';
> osc.frequency.setValueAtTime(180, this.ctx.currentTime);
> osc.frequency.exponentialRampToValueAtTime(60, this.ctx.currentTime + 0.03);
> 
> gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
> gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.03);
> 
> osc.connect(gain);
> gain.connect(this.ctx.destination);
> 
> osc.start();
> osc.stop(this.ctx.currentTime + 0.03);
> } catch(e) {}
> }
> 
> playHit() {
> if (!this.enabled) return;
> this.init();
> if (!this.ctx) return;
> 
> try {
> const notes = [261.63, 329.63, 392.00, 523.25];
> notes.forEach((freq, idx) => {
> const osc = this.ctx.createOscillator();
> const gain = this.ctx.createGain();
> osc.type = 'triangle';
> osc.frequency.setValueAtTime(freq, this.ctx.currentTime + idx * 0.05);
> 
> gain.gain.setValueAtTime(0.12, this.ctx.currentTime + idx * 0.05);
> gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + idx * 0.05 + 0.12);
> 
> osc.connect(gain);
> gain.connect(this.ctx.destination);
> 
> osc.start(this.ctx.currentTime + idx * 0.05);
> osc.stop(this.ctx.currentTime + idx * 0.05 + 0.12);
> });
> } catch(e) {}
> }
> 
> playGameOver(victory = true) {
> if (!this.enabled) return;
> this.init();
> if (!this.ctx) return;
> 
> try {
> const freqs = victory ? [300, 400, 500, 700] : [500, 400, 300, 200];
> freqs.forEach((freq, idx) => {
> const osc = this.ctx.createOscillator();
> const gain = this.ctx.createGain();
> osc.type = victory ? 'sine' : 'sawtooth';
> osc.frequency.setValueAtTime(freq, this.ctx.currentTime + idx * 0.1);
> 
> gain.gain.setValueAtTime(0.15, this.ctx.currentTime + idx * 0.1);
> gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + idx * 0.1 + 0.18);
> 
> osc.connect(gain);
> gain.connect(this.ctx.destination);
> 
> osc.start(this.ctx.currentTime + idx * 0.1);
> osc.stop(this.ctx.currentTime + idx * 0.1 + 0.18);
> });
> } catch(e) {}
> }
> 
> toggle() {
> this.enabled = !this.enabled;
> const indicator = document.getElementById('audio-indicator');
> if (indicator) {
> indicator.textContent = `SOUND: [${this.enabled ? 'ON' : 'OFF'}]`;
> }
> }
> }
> 
> const audio = new SoundSystem();
> 
> /**
> * Game Engine and Grid Render Logic
> */
> const COLS = 80;
> const ROWS = 24;
> 
> const GAME_STATES = {
> MENU: 'MENU',
> PLAYING: 'PLAYING',
> PAUSED: 'PAUSED',
> GAMEOVER: 'GAMEOVER'
> };
> 
> const MODES = {
> STATIC: 1,
> WANDERING: 2,
> EVASIVE: 3,
> MULTI: 4,
> TIME_ATTACK: 5
> };
> 
> class TargetGame {
> constructor() {
> this.state = GAME_STATES.MENU;
> this.mode = MODES.STATIC;
>                 
> // Player properties
> this.px = 40;
> this.py = 12;
> this.playerSymbol = 'O';
> 
> // Target system
> this.targets = []; // Array of {x, y, active, initialDist}
> this.targetQuota = 10; // Default hits needed to complete round
> this.targetsHit = 0;
> 
> // Move and step budget settings
> this.stepsTaken = 0;
> this.stepBudgetEnabled = false;
> this.maxSteps = 100;
> 
> // Score metrics
> this.score = 0;
> this.totalOptimumSteps = 0;
> 
> // Time Attack properties
> this.timeRemaining = 60;
> this.timerId = null;
> 
> // Visual theme settings
> this.themes = ['', 'theme-amber', 'theme-bw'];
> this.themeIndex = 0;
> 
> // Explosion visual effect buffer
> this.fxBuffer = []; // {x, y, char, frame}
> 
> // Animation loop tracking
> this.lastWanderTime = 0;
> this.highScores = {
> 1: 0, 2: 0, 3: 0, 4: 0, 5: 0
> };
> }
> 
> init() {
> this.render();
> setInterval(() => this.updateLoop(), 150);
> }
> 
> startNewGame(selectedMode) {
> this.mode = selectedMode;
> this.state = GAME_STATES.PLAYING;
> this.px = 40;
> this.py = 12;
> this.stepsTaken = 0;
> this.targetsHit = 0;
> this.score = 0;
> this.totalOptimumSteps = 0;
> this.fxBuffer = [];
> 
> if (this.timerId) clearInterval(this.timerId);
> 
> if (this.mode === MODES.TIME_ATTACK) {
> this.timeRemaining = 60;
> this.timerId = setInterval(() => {
> if (this.state === GAME_STATES.PLAYING) {
> this.timeRemaining--;
> if (this.timeRemaining <= 0) {
> this.timeRemaining = 0;
> this.endGame(true, "TIME EXPIRED!");
> }
> }
> }, 1000);
> }
> 
> this.spawnTargets();
> audio.playStep();
> }
> 
> spawnTargets() {
> this.targets = [];
> const count = (this.mode === MODES.MULTI) ? 5 : 1;
> 
> for (let i = 0; i < count; i++) {
> let tx, ty, dist;
> do {
> tx = Math.floor(Math.random() * (COLS - 4)) + 2;
> ty = Math.floor(Math.random() * (ROWS - 6)) + 3;
> dist = Math.abs(tx - this.px) + Math.abs(ty - this.py);
> } while (dist < 5); // Ensure target doesn't spawn right next to player
> 
> this.targets.push({
> x: tx,
> y: ty,
> active: true,
> initialDist: dist
> });
> }
> }
> 
> movePlayer(dx, dy) {
> if (this.state !== GAME_STATES.PLAYING) return;
> 
> const newX = this.px + dx;
> const newY = this.py + dy;
> 
> // Playfield boundaries (reserving header and footer lines)
> if (newX >= 1 && newX <= COLS - 2 && newY >= 3 && newY <= ROWS - 3) {
> this.px = newX;
> this.py = newY;
> this.stepsTaken++;
> audio.playStep();
> 
> // Check Step Budget Violation
> if (this.stepBudgetEnabled && this.stepsTaken >= this.maxSteps) {
> this.endGame(false, "STEP BUDGET EXCEEDED!");
> return;
> }
> 
> // Evasive Target reaction logic
> if (this.mode === MODES.EVASIVE) {
> this.targets.forEach(t => {
> if (t.active) {
> const dist = Math.abs(t.x - this.px) + Math.abs(t.y - this.py);
> if (dist < 4) {
> // Move away from player
> const escapeX = t.x + Math.sign(t.x - this.px);
> const escapeY = t.y + Math.sign(t.y - this.py);
> if (escapeX >= 2 && escapeX <= COLS - 3) t.x = escapeX;
> if (escapeY >= 4 && escapeY <= ROWS - 4) t.y = escapeY;
> }
> }
> });
> }
> 
> this.checkCollisions();
> }
> }
> 
> checkCollisions() {
> let hitAny = false;
> 
> this.targets.forEach(t => {
> if (t.active && t.x === this.px && t.y === this.py) {
> t.active = false;
> hitAny = true;
> 
> // Add explosion effect
> this.fxBuffer.push({ x: t.x, y: t.y, char: '*', frame: 0 });
> this.fxBuffer.push({ x: t.x - 1, y: t.y, char: '+', frame: 0 });
> this.fxBuffer.push({ x: t.x + 1, y: t.y, char: '+', frame: 0 });
> this.fxBuffer.push({ x: t.x, y: t.y - 1, char: '+', frame: 0 });
> this.fxBuffer.push({ x: t.x, y: t.y + 1, char: '+', frame: 0 });
> 
> this.targetsHit++;
> this.score += 100 + Math.max(0, 50 - Math.abs(t.initialDist));
> this.totalOptimumSteps += t.initialDist;
> }
> });
> 
> if (hitAny) {
> audio.playHit();
> 
> // Check target quota completion
> if (this.targetQuota !== 0 && this.targetsHit >= this.targetQuota) {
> this.endGame(true, "TARGET QUOTA REACHED!");
> return;
> }
> 
> // Respawn targets if all active ones are hit
> if (!this.targets.some(t => t.active)) {
> this.spawnTargets();
> }
> }
> }
> 
> updateLoop() {
> // Handle explosion particle frames
> if (this.fxBuffer.length > 0) {
> this.fxBuffer.forEach(f => f.frame++);
> this.fxBuffer = this.fxBuffer.filter(f => f.frame < 3);
> }
> 
> // Handle Wandering Targets movement
> if (this.state === GAME_STATES.PLAYING && this.mode === MODES.WANDERING) {
> const now = Date.now();
> if (now - this.lastWanderTime > 800) {
> this.lastWanderTime = now;
> this.targets.forEach(t => {
> if (t.active && Math.random() < 0.6) {
> const dirX = Math.floor(Math.random() * 3) - 1;
> const dirY = Math.floor(Math.random() * 3) - 1;
> const nx = t.x + dirX;
> const ny = t.y + dirY;
> if (nx >= 2 && nx <= COLS - 3) t.x = nx;
> if (ny >= 4 && ny <= ROWS - 4) t.y = ny;
> }
> });
> this.checkCollisions();
> }
> }
> 
> this.render();
> }
> 
> endGame(victory, reasonMessage) {
> this.state = GAME_STATES.GAMEOVER;
> if (this.timerId) clearInterval(this.timerId);
> 
> // Update High Scores
> if (this.score > this.highScores[this.mode]) {
> this.highScores[this.mode] = this.score;
> }
> 
> this.endReason = reasonMessage;
> this.isVictory = victory;
> audio.playGameOver(victory);
> }
> 
> toggleStepBudget() {
> if (!this.stepBudgetEnabled) {
> this.stepBudgetEnabled = true;
> this.maxSteps = 100;
> } else if (this.maxSteps === 100) {
> this.maxSteps = 200;
> } else if (this.maxSteps === 200) {
> this.maxSteps = 300;
> } else {
> this.stepBudgetEnabled = false;
> }
> audio.playStep();
> }
> 
> toggleTargetQuota() {
> if (this.targetQuota === 5) this.targetQuota = 10;
> else if (this.targetQuota === 10) this.targetQuota = 20;
> else if (this.targetQuota === 20) this.targetQuota = 0; // Infinite
> else this.targetQuota = 5;
> audio.playStep();
> }
> 
> toggleSymbol() {
> this.playerSymbol = (this.playerSymbol === 'O') ? 'X' : 'O';
> audio.playStep();
> }
> 
> cycleTheme() {
> this.themeIndex = (this.themeIndex + 1) % this.themes.length;
> document.body.className = "h-screen w-screen flex flex-col items-center justify-center p-2 sm:p-4 " + this.themes[this.themeIndex];
> audio.playStep();
> }
> 
> handleInput(command) {
> if (command === 'Up') this.movePlayer(0, -1);
> else if (command === 'Down') this.movePlayer(0, 1);
> else if (command === 'Left') this.movePlayer(-1, 0);
> else if (command === 'Right') this.movePlayer(1, 0);
> }
> 
> render() {
> const term = document.getElementById('terminal');
> let buffer = [];
> 
> // Initialize empty 80x24 grid
> for (let r = 0; r < ROWS; r++) {
> buffer[r] = new Array(COLS).fill(' ');
> }
> 
> if (this.state === GAME_STATES.MENU) {
> this.renderMenu(buffer);
> } else {
> this.renderHUD(buffer);
> this.renderPlayfield(buffer);
> 
> if (this.state === GAME_STATES.PAUSED) {
> this.renderOverlayBox(buffer, ["--- GAME PAUSED ---", "", "PRESS [P] TO RESUME"]);
> } else if (this.state === GAME_STATES.GAMEOVER) {
> const eff = this.stepsTaken > 0 ? Math.min(100, Math.round((this.totalOptimumSteps / this.stepsTaken) * 100)) : 0;
> this.renderOverlayBox(buffer, [
> this.isVictory ? "=== MISSION ACCOMPLISHED ===" : "!!! GAME OVER !!!",
> this.endReason || "",
> "",
> `FINAL SCORE: ${this.score}`,
> `TARGETS HIT: ${this.targetsHit}`,
> `STEPS TAKEN: ${this.stepsTaken}`,
> `NAV EFFICIENCY: ${eff}%`,
> "",
> "PRESS [R] TO PLAY AGAIN OR [M] FOR MENU"
> ]);
> }
> }
> 
> // Render array lines to string
> term.textContent = buffer.map(row => row.join('')).join('\n');
> }
> 
> renderMenu(buffer) {
> const lines = [
> "================================================================================",
> " ALTAIR 8800 BASIC - TARGET EMULATOR (1977) ",
> "================================================================================",
> "",
> " SELECT GAME MODE:",
> " [1] STATIC TARGET - Standard coordinate matching & pursuit",
> " [2] WANDERING TARGET - Target moves randomly around grid",
> " [3] EVASIVE TARGET - Target flees as player gets close",
> " [4] MULTI-TARGET - Multiple targets active simultaneously",
> " [5] TIME ATTACK - 60-second speed-matching challenge",
> "",
> " SETTINGS & CONTROLS:",
> ` [B] STEP BUDGET : ${this.stepBudgetEnabled ? this.maxSteps + ' STEPS' : 'DISABLED'}`,
> ` [T] TARGET QUOTA : ${this.targetQuota === 0 ? 'INFINITE' : this.targetQuota + ' TARGETS'}`,
> ` [X] PLAYER SYMBOL : [${this.playerSymbol}]`,
> ` [C] COLOR PHOSPHOR : GREEN / AMBER / B&W`,
> "",
> " OBJECTIVE:",
> " Navigate your player symbol to match coordinates with the target (*).",
> " Minimize total step count to achieve maximum telemetry efficiency.",
> "",
> "================================================================================",
> " PRESS NUMBER KEY [1-5] TO LOAD PROGRAM AND START RUN "
> ];
> 
> lines.forEach((line, r) => {
> if (r < ROWS) {
> for (let c = 0; c < line.length && c < COLS; c++) {
> buffer[r][c] = line[c];
> }
> }
> });
> }
> 
> renderHUD(buffer) {
> // Header Border
> const line1 = "="+ "=".repeat(COLS - 2) + "=";
>                 
> // Telemetry Data Bar
> let nearestDist = "--";
> const activeTargets = this.targets.filter(t => t.active);
> if (activeTargets.length > 0) {
> const nearest = activeTargets.reduce((min, t) => {
> const d = Math.abs(t.x - this.px) + Math.abs(t.y - this.py);
> return d < min ? d : min;
> }, 999);
> nearestDist = nearest.toString();
> }
> 
> const modeNames = ["", "STATIC", "WANDER", "EVASIVE", "MULTI", "TIME-ATT"];
> const budgetStr = this.stepBudgetEnabled ? `${this.stepsTaken}/${this.maxSteps}` : `${this.stepsTaken}`;
> const quotaStr = this.targetQuota === 0 ? `${this.targetsHit}/INF` : `${this.targetsHit}/${this.targetQuota}`;
> const timeStr = this.mode === MODES.TIME_ATTACK ? ` TIME:${this.timeRemaining}s` : '';
> 
> const line2 = ` MODE:${modeNames[this.mode]} | POS:(${this.px},${this.py}) | DIST:${nearestDist} | STEPS:${budgetStr} | TGT:${quotaStr}${timeStr} | SCORE:${this.score} `;
> const line3 = "-".repeat(COLS);
> 
> for (let c = 0; c < COLS; c++) {
> buffer[0][c] = line1[c] || ' ';
> buffer[1][c] = line2[c] || ' ';
> buffer[2][c] = line3[c] || ' ';
> buffer[ROWS - 1][c] = line1[c] || ' ';
> }
> }
> 
> renderPlayfield(buffer) {
> // Draw Playfield Box Bounds
> for (let r = 3; r < ROWS - 1; r++) {
> buffer[r][0] = '|';
> buffer[r][COLS - 1] = '|';
> }
> 
> // Render Targets
> this.targets.forEach(t => {
> if (t.active && t.x > 0 && t.x < COLS - 1 && t.y >= 3 && t.y < ROWS - 1) {
> buffer[t.y][t.x] = '*';
> }
> });
> 
> // Render Explosion VFX
> this.fxBuffer.forEach(f => {
> if (f.x > 0 && f.x < COLS - 1 && f.y >= 3 && f.y < ROWS - 1) {
> buffer[f.y][f.x] = f.char;
> }
> });
> 
> // Render Player
> if (this.px > 0 && this.px < COLS - 1 && this.py >= 3 && this.py < ROWS - 1) {
> buffer[this.py][this.px] = this.playerSymbol;
> }
> }
> 
> renderOverlayBox(buffer, textLines) {
> const boxWidth = 50;
> const boxHeight = textLines.length + 4;
> const startR = Math.floor((ROWS - boxHeight) / 2);
> const startC = Math.floor((COLS - boxWidth) / 2);
> 
> for (let r = 0; r < boxHeight; r++) {
> const currentR = startR + r;
> if (currentR < 0 || currentR >= ROWS) continue;
> 
> for (let c = 0; c < boxWidth; c++) {
> const currentC = startC + c;
> if (currentC < 0 || currentC >= COLS) continue;
> 
> if (r === 0 || r === boxHeight - 1) {
> buffer[currentR][currentC] = '+';
> } else if (c === 0 || c === boxWidth - 1) {
> buffer[currentR][currentC] = '|';
> } else {
> buffer[currentR][currentC] = ' ';
> }
> }
> }
> 
> // Print Overlay Text
> textLines.forEach((line, idx) => {
> const currentR = startR + 2 + idx;
> const padding = Math.max(0, Math.floor((boxWidth - 2 - line.length) / 2));
> const startTextC = startC + 1 + padding;
> 
> for (let i = 0; i < line.length; i++) {
> if (startTextC + i < startC + boxWidth - 1) {
> buffer[currentR][startTextC + i] = line[i];
> }
> }
> });
> }
> }
> 
> // Initialize Game Instance
> const game = new TargetGame();
> 
> // Keyboard Event Dispatcher
> window.addEventListener('keydown', (e) => {
> // Prevent default arrow key scrolling
> if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) {
> e.preventDefault();
> }
> 
> if (game.state === GAME_STATES.MENU) {
> if (['Digit1', 'Numpad1'].includes(e.code)) game.startNewGame(MODES.STATIC);
> else if (['Digit2', 'Numpad2'].includes(e.code)) game.startNewGame(MODES.WANDERING);
> else if (['Digit3', 'Numpad3'].includes(e.code)) game.startNewGame(MODES.EVASIVE);
> else if (['Digit4', 'Numpad4'].includes(e.code)) game.startNewGame(MODES.MULTI);
> else if (['Digit5', 'Numpad5'].includes(e.code)) game.startNewGame(MODES.TIME_ATTACK);
> else if (e.code === 'KeyB') game.toggleStepBudget();
> else if (e.code === 'KeyT') game.toggleTargetQuota();
> else if (e.code === 'KeyX' || e.code === 'KeyS') game.toggleSymbol();
> else if (e.code === 'KeyC') game.cycleTheme();
> else if (e.code === 'KeyM') audio.toggle();
> } else if (game.state === GAME_STATES.PLAYING) {
> if (e.code === 'ArrowLeft' || e.code === 'KeyA') game.movePlayer(-1, 0);
> else if (e.code === 'ArrowRight' || e.code === 'KeyD') game.movePlayer(1, 0);
> else if (e.code === 'ArrowUp' || e.code === 'KeyW') game.movePlayer(0, -1);
> else if (e.code === 'ArrowDown' || e.code === 'KeyS') game.movePlayer(0, 1);
> else if (e.code === 'KeyP') game.state = GAME_STATES.PAUSED;
> else if (e.code === 'KeyR') game.startNewGame(game.mode);
> else if (e.code === 'KeyB') game.toggleStepBudget();
> else if (e.code === 'KeyT') game.toggleTargetQuota();
> else if (e.code === 'KeyX') game.toggleSymbol();
> else if (e.code === 'KeyC') game.cycleTheme();
> else if (e.code === 'KeyM') audio.toggle();
> } else if (game.state === GAME_STATES.PAUSED) {
> if (e.code === 'KeyP') game.state = GAME_STATES.PLAYING;
> } else if (game.state === GAME_STATES.GAMEOVER) {
> if (e.code === 'KeyR') game.startNewGame(game.mode);
> else if (e.code === 'KeyM') game.state = GAME_STATES.MENU;
> }
> });
> 
> // Initialize display on window load
> window.onload = () => {
> game.init();
> };
> </script>
> </body>
> </html>
> 
> ```

---

<div class="post-metadata">

**Author:** ![DigitalC](https://avatars.discourse-cdn.com/v4/letter/d/ebca7d/32.png) [@DigitalC](https://boards.straightdope.com/u/DigitalC)\
**Post date:** [October 30, 2026, 11:41pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/23 "2026-10-30T23:41:23Z")

</div>

> [@Jasmine](#):
>
> If you found the game, I seriously doubt you could find a machine to run it.

He said he still has it in the attic! Now, whether it works or not is a different question…

---

<div class="post-metadata">

**Author:** ![Jasmine](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/jasmine/32/2964_2.png) [@Jasmine](https://boards.straightdope.com/u/Jasmine)\
**Post date:** [November 2, 2026, 1:15pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/24 "2026-11-02T13:15:13Z")

</div>

> [@DigitalC](#):
>
> He said he still has it in the attic!

I’m impressed! 💯

---

<div class="post-metadata">

**Author:** ![StarvingButStrong](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/starvingbutstrong/32/335_2.png) [@StarvingButStrong](https://boards.straightdope.com/u/StarvingButStrong)\
**Post date:** [November 2, 2026, 4:12pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/25 "2026-11-02T16:12:33Z")

</div>

I’m sorry about vanishing for a few days. I was truly overwhelmed by how much effort so many of you put into my question, though in truth most of it went totally over my head. What I probably needed was a link to some hobbyist who had a web page of replicas you could simply play what looked like the game with a browser. I know there’s at least one for old Zork type games, so just maybe?

I was never into the hands-on side of things. My brother did all the tech stuff: he’d boot the computer, load the game, laugh at my frequent ineptitude at playing whatever it was.

After I posted that message, I finally realized what was going on with me. My Eldest Brother and I were part of a large family … and we were the two outsiders. All the other boys (and a couple of the girls!) were stereotypical jocks through and through. It was sports. sports, sports plus later on lots of booze and in some cases drugs, and in one bad case a career of crime to support it. With the sort of aftermath you might expect.

We two simply didn’t fit, and I think our overburdened parents just had no idea what to do with us. We were both excellent students – I think we fled to school – and we were polite and followed the rules so I guess they figured they could just concentrate on the needs of the noisier mob.

I actually got more involved with the computers after he’d moved on to CP/M and later some CP/M-DOS hybrid and so on. A friend of his had invented a game creation system that would turn out text games like Zork and its ilk. It was not at all demanding of true programming skills, what it took was creative writing to come up with your scenarios and puzzles and descriptions. Those I was good at, while Brother would loyally always expand the matrixe(?maybe?) so I could have more and more verb and objects as my games grew. We’d spend hours, me creating the game, him engineering it, and finally being my first player.

Wow. More detail than you need, sorry. Anyway, time passed, and that phase of things passed. I moved basically into writing stories that didn’t have to define down to verb-object phrases.

Brother was, no surprise, a software engineer. He had a bad heart attack, but seemed to recover well. He lost extra weight and started an exercise program under medical supervision and things seemed to be going well. Then it was October, which here in New England means falling leaves. And he got the idea that he was feeling great so why not rake up leaves and haul them away…

His backyard had a lot of trees, and was sort of secluded. The autopsy said he’d been dead for several hours before a neighbor happened to spot him lying there.

And it’s now October again, and every year I get sort of melancholy when the leaves start to fall.

Which is a long lead up to saying, I didn’t realize at first I wasn’t missing a computer game I was suddenly remembering.

Thank you all for your kind attempts to help, sorry for the waste of your time.

---

<div class="post-metadata">

**Author:** ![Baal\_Houtham](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/baal_houtham/32/13604_2.png) [@Baal\_Houtham](https://boards.straightdope.com/u/Baal_Houtham)\
**Post date:** [November 2, 2026, 4:36pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/26 "2026-11-02T16:36:46Z")

</div>

Sad story, but also lovely

---

<div class="post-metadata">

**Author:** ![DPRK](https://avatars.discourse-cdn.com/v4/letter/d/4491bb/32.png) [@DPRK](https://boards.straightdope.com/u/DPRK)\
**Post date:** [November 2, 2026, 6:39pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/27 "2026-11-02T18:39:11Z")

</div>

FWIW I tried loading and running a bunch of game disks I found on the Internet under CP/M 2.2 in the SIMH emulator, and they worked fine. Zork and what not; none of them had the Target described in the OP, only the Basic Computer Game of that name. If you can _find_ the disk, running the game was never going to be a problem. There are also various web-based simulators where everything runs in a web page.

---

<div class="post-metadata">

**Author:** ![Reply](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/reply/32/15952_2.png) [@Reply](https://boards.straightdope.com/u/Reply)\
**Post date:** [November 2, 2026, 8:16pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/28 "2026-11-02T20:16:29Z")

</div>

> [@StarvingButStrong](#):
>
> Which is a long lead up to saying, I didn’t realize at first I wasn’t missing a computer game I was suddenly remembering.
> 
> Thank you all for your kind attempts to help, sorry for the waste of your time.

Thanks for sharing that story. Sorry about your brother. Those are nice memories to have had.

There’s no waste of time here. We were all just curious too.

---

<div class="post-metadata">

**Author:** ![Chronos](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/chronos/32/134_2.png) [@Chronos](https://boards.straightdope.com/u/Chronos)\
**Post date:** [November 2, 2026, 11:00pm UTC](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192/29 "2026-11-02T23:00:49Z")

</div>

Have you seen the thread on nostalgia for text-adventure games?

> [@A hollow voice says 'Fool.'](https://boards.straightdope.com/t/a-hollow-voice-says-fool/1034313/):
>
> Who loved and maybe still loves those old school interactive fiction games? I actually downloaded an emulator that plays the games on my phone which has way more juice than a Radio Shack Tandy ever did, I love those games so much. Who else recalls reading the New Zork Times? Who remembers typing 'XYZZY" to see that happened? Any of you deviants finish “Leather Goddesses of Phobos?” Fess up!

[Previous page](https://boards.straightdope.com/t/trying-to-find-a-truly-ancient-computer-game-from-vague-memory/1034192.md?page=1)
