SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,680
Folders
433
Scanned Size
3.89 GB
PHP Files
988
Editable Text Files
12,938
File viewer
guarded to /htdocs
/downloads/BATTLESHIP.HTML
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" /> <title>SIMON ARCADE • Battleship (Player vs Computer)</title> <meta name="theme-color" content="#070b16" /> <style> :root{ --bg:#070b16; --ink:#eaf2ff; --muted:#a9b6d9; --edge:rgba(255,255,255,.14); --panel:rgba(255,255,255,.06); --panel2:rgba(255,255,255,.03); --acc:#6ae0ff; --acc2:#5b7dff; --ok:#3dde8a; --warn:#ffd36b; --danger:#ff6b6b; --miss:#95a3c3; --hit:#ff6b6b; --sunk:#ff3b6e; --water:#1a2547; --ship:#6d83ff; } *{box-sizing:border-box} html,body{height:100%} body{ margin:0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Inter, Roboto; color:var(--ink); background: radial-gradient(1200px 800px at 80% -10%, #142a66 0%, #070b16 55%, #04070f 100%); } .wrap{max-width:1100px; margin:0 auto; padding:16px; display:grid; gap:12px} header{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:8px 12px; background:var(--panel); border:1px solid var(--edge); border-radius:16px; box-shadow: 0 6px 20px rgba(0,0,0,.25), inset 0 0 0 1px rgba(255,255,255,.04); } .logo{font-weight:900; letter-spacing:.14em; text-transform:uppercase; font-size:clamp(18px,4vw,28px)} .controls{display:flex; gap:8px; flex-wrap:wrap} button{ background:linear-gradient(180deg, var(--acc), var(--acc2)); color:#001; border:0; padding:10px 14px; border-radius:12px; font-weight:700; cursor:pointer; box-shadow: 0 6px 16px rgba(20,60,255,.35); } button.secondary{ background:var(--panel); color:var(--ink); border:1px solid var(--edge); box-shadow:none } button:disabled{ opacity:.6; cursor:not-allowed } .boards{ display:grid; grid-template-columns:1fr; gap:12px; } @media (min-width:900px){ .boards{ grid-template-columns:1fr 1fr } } .board-card{ background:var(--panel); border:1px solid var(--edge); border-radius:16px; padding:10px; box-shadow: 0 6px 20px rgba(0,0,0,.25), inset 0 0 0 1px rgba(255,255,255,.04); } .board-title{ display:flex; align-items:center; justify-content:space-between; gap:8px; margin:4px 2px 10px; } .board-title h2{margin:0; font-size:18px; letter-spacing:.06em} .legend{font-size:12px; color:var(--muted)} .grid{ --cell: min(36px, 8.5vw); display:grid; grid-template-columns: repeat(10, var(--cell)); grid-auto-rows: var(--cell); gap:4px; justify-content:center; touch-action: manipulation; } .cell{ border-radius:8px; background:linear-gradient(180deg, #0b1535, var(--water)); border:1px solid rgba(255,255,255,.08); box-shadow: inset 0 0 18px rgba(0,0,0,.35); display:flex; align-items:center; justify-content:center; font-size:12px; user-select:none; -webkit-tap-highlight-color: transparent; } .cell.btn{ cursor:pointer } .cell:hover{ outline:2px solid rgba(106,224,255,.35) } .me .ship{ background:linear-gradient(180deg, #253077, var(--ship)); } .hit{ background: radial-gradient(circle at 40% 35%, #ff9aa7 0%, #ff6b6b 40%, #7a0b0b 100%); border-color:#ffb3b3 } .miss{ background: linear-gradient(180deg, #1e2747, #0e142c); border-style:dashed; border-color:var(--miss) } .sunk{ background: linear-gradient(180deg, #861c38, var(--sunk)); border-color:#ff7a96 } .status{ background:var(--panel); border:1px solid var(--edge); border-radius:16px; padding:12px; display:grid; gap:8px; grid-template-columns:1fr; } @media (min-width:700px){ .status{ grid-template-columns: 2fr 1fr } } .log{ min-height:72px; max-height:160px; overflow:auto; padding:8px; border-radius:12px; background:var(--panel2); border:1px dashed var(--edge); font-size:14px; line-height:1.45; } .badges{ display:flex; gap:8px; flex-wrap:wrap } .badge{ padding:6px 10px; border-radius:999px; font-size:12px; background:var(--panel2); border:1px solid var(--edge); } footer{ text-align:center; color:var(--muted); font-size:12px; padding:8px } .sr{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden } </style> </head> <body> <div class="wrap"> <header> <div class="logo">SIMON ARCADE · Battleship</div> <div class="controls"> <button id="newGameBtn" title="Start a new game">New Game</button> <button id="showShipsBtn" class="secondary" title="Toggle showing your ships">Toggle My Ships</button> </div> </header> <section class="boards"> <article class="board-card me"> <div class="board-title"> <h2>Your Fleet</h2> <div class="legend">You can see your ships. Red = hit, gray = miss.</div> </div> <div id="playerGrid" class="grid" aria-label="Your board"></div> </article> <article class="board-card"> <div class="board-title"> <h2>Enemy Waters</h2> <div class="legend">Tap a cell to fire. Sink all enemy ships to win.</div> </div> <div id="computerGrid" class="grid" aria-label="Computer board"></div> </article> </section> <section class="status"> <div> <strong>Status</strong> <div class="log" id="log" aria-live="polite"></div> </div> <div> <strong>Score</strong> <div class="badges" id="scoreBadges"></div> </div> </section> <footer>© 2025 gaylordsinclair.com · Battleship v1.0</footer> </div> <script> (function(){ const SIZE = 10; const SHIPS = [ { name:"Carrier", size:5 }, { name:"Battleship", size:4 }, { name:"Cruiser", size:3 }, { name:"Submarine", size:3 }, { name:"Destroyer", size:2 }, ]; const els = { playerGrid: document.getElementById('playerGrid'), computerGrid: document.getElementById('computerGrid'), log: document.getElementById('log'), newGameBtn: document.getElementById('newGameBtn'), showShipsBtn: document.getElementById('showShipsBtn'), scoreBadges: document.getElementById('scoreBadges'), }; let state; function newEmptyBoard(){ // cells: { shipId: null|number, hit:false, miss:false, sunk:false } const grid = []; for(let r=0;r<SIZE;r++){ const row=[]; for(let c=0;c<SIZE;c++){ row.push({ shipId:null, hit:false, miss:false, sunk:false }); } grid.push(row); } return grid; } function placeFleetRandomly(board){ const ships = SHIPS.map((s,i)=>({ id:i, name:s.name, size:s.size, coords:[], hits:0, sunk:false })); for(const ship of ships){ let placed=false, tries=0; while(!placed && tries<1000){ tries++; const horizontal = Math.random()<0.5; const r = Math.floor(Math.random()*SIZE); const c = Math.floor(Math.random()*SIZE); if(canPlace(board, r, c, horizontal, ship.size)){ const coords=[]; for(let k=0;k<ship.size;k++){ const rr = r + (horizontal?0:k); const cc = c + (horizontal?k:0); board[rr][cc].shipId = ship.id; coords.push([rr,cc]); } ship.coords = coords; placed = true; } } if(!placed) throw new Error('Failed to place ships'); } return ships; } function canPlace(board, r, c, horizontal, len){ if(horizontal){ if(c+len>SIZE) return false; for(let k=0;k<len;k++){ if(board[r][c+k].shipId!==null) return false; } } else { if(r+len>SIZE) return false; for(let k=0;k<len;k++){ if(board[r+k][c].shipId!==null) return false; } } return true; } function init(){ state = { turn: 'player', // or 'computer' playerBoard: newEmptyBoard(), computerBoard: newEmptyBoard(), playerShips: null, computerShips: null, showShips: true, // AI memory aiTried: new Set(), // "r,c" aiTargets: [], // queue of smart targets aiLastHit: null, // last hit coord gameOver: false, score: { playerHits:0, compHits:0, playerSunk:0, compSunk:0 } }; state.playerShips = placeFleetRandomly(state.playerBoard); state.computerShips = placeFleetRandomly(state.computerBoard); renderBoards(); renderScore(); logClear(); log("New game started. Your move!"); } function renderBoards(){ // Player board els.playerGrid.innerHTML = ''; for(let r=0;r<SIZE;r++){ for(let c=0;c<SIZE;c++){ const cell = document.createElement('div'); cell.className = 'cell'; const data = state.playerBoard[r][c]; if(state.showShips && data.shipId!==null) cell.classList.add('ship'); if(data.hit) cell.classList.add('hit'); if(data.miss) cell.classList.add('miss'); if(data.sunk) cell.classList.add('sunk'); cell.setAttribute('aria-label', `Your cell ${r+1},${c+1}`); els.playerGrid.appendChild(cell); } } // Computer board els.computerGrid.innerHTML = ''; for(let r=0;r<SIZE;r++){ for(let c=0;c<SIZE;c++){ const cell = document.createElement('div'); cell.className = 'cell btn'; const data = state.computerBoard[r][c]; // Don't show ships here, only results if(data.hit) cell.classList.add('hit'); if(data.miss) cell.classList.add('miss'); if(data.sunk) cell.classList.add('sunk'); cell.dataset.r = r; cell.dataset.c = c; cell.setAttribute('role','button'); cell.setAttribute('tabindex','0'); cell.setAttribute('aria-label', `Fire at ${r+1},${c+1}`); cell.addEventListener('click', onPlayerFire, {passive:true}); cell.addEventListener('keydown', (e)=>{ if(e.key==='Enter' || e.key===' '){ onPlayerFire.call(cell,e); e.preventDefault(); }}); els.computerGrid.appendChild(cell); } } } function renderScore(){ const psunk = state.score.playerSunk; const csunk = state.score.compSunk; const ph = state.score.playerHits; const ch = state.score.compHits; els.scoreBadges.innerHTML = ` <div class="badge">Enemy ships sunk: <strong>${psunk}/${SHIPS.length}</strong></div> <div class="badge">Your ships sunk: <strong>${csunk}/${SHIPS.length}</strong></div> <div class="badge">Your hits: <strong>${ph}</strong></div> <div class="badge">Computer hits: <strong>${ch}</strong></div> `; } function onPlayerFire(e){ if(state.gameOver || state.turn!=='player') return; const r = +this.dataset.r; const c = +this.dataset.c; const cell = state.computerBoard[r][c]; if(cell.hit || cell.miss || cell.sunk) { log("You already fired there."); return; } if(cell.shipId!==null){ cell.hit = true; state.score.playerHits++; const ship = state.computerShips[cell.shipId]; ship.hits++; log(`Hit! (${ship.name}) at ${r+1},${c+1}`); if(ship.hits>=ship.size){ ship.sunk = true; markSunk(state.computerBoard, ship); state.score.playerSunk++; log(`You sank the enemy ${ship.name}!`); } checkWin(); // Player gets to continue? Traditional rules alternate; we'll alternate. state.turn = 'computer'; renderBoards(); renderScore(); if(!state.gameOver) setTimeout(computerTurn, 420); } else { cell.miss = true; log(`Miss at ${r+1},${c+1}.`); state.turn = 'computer'; renderBoards(); renderScore(); if(!state.gameOver) setTimeout(computerTurn, 420); } } function markSunk(board, ship){ for(const [r,c] of ship.coords){ board[r][c].sunk = true; } } function checkWin(){ if(state.score.playerSunk===SHIPS.length){ log("🎉 You win! All enemy ships sunk."); state.gameOver = true; } if(state.score.compSunk===SHIPS.length){ log("💥 You lose. All your ships were sunk."); state.gameOver = true; } } // --- Computer AI (hunt + target) --- function computerTurn(){ if(state.gameOver) return; let target; // Prefer targets in queue (adjacent to previous hits) while(state.aiTargets.length){ const cand = state.aiTargets.shift(); if(!state.aiTried.has(key(cand[0], cand[1]))){ target = cand; break; } } if(!target){ // Hunt mode: choose random cell not tried yet, prefer checkerboard for efficiency const candidates = []; for(let r=0;r<SIZE;r++){ for(let c=0;c<SIZE;c++){ if((r+c)%2===0){ // checkerboard if(!state.aiTried.has(key(r,c))) candidates.push([r,c]); } } } if(candidates.length===0){ // fallback any cell for(let r=0;r<SIZE;r++){ for(let c=0;c<SIZE;c++){ if(!state.aiTried.has(key(r,c))) candidates.push([r,c]); } } } target = candidates[Math.floor(Math.random()*candidates.length)]; } const [r,c] = target; state.aiTried.add(key(r,c)); const cell = state.playerBoard[r][c]; if(cell.shipId!==null){ cell.hit = true; state.score.compHits++; const ship = state.playerShips[cell.shipId]; ship.hits++; log(`Enemy hit your ${ship.name} at ${r+1},${c+1}!`); // enqueue neighbors as intelligent targets enqueueNeighbors(r,c); if(ship.hits>=ship.size){ ship.sunk = true; markSunk(state.playerBoard, ship); state.score.compSunk++; log(`⚠️ Enemy sank your ${ship.name}!`); // Clear targets that are not part of any remaining hits can be left; simple approach keeps them. } } else { cell.miss = true; log(`Enemy missed at ${r+1},${c+1}.`); } renderBoards(); renderScore(); checkWin(); if(!state.gameOver) state.turn = 'player'; } function enqueueNeighbors(r,c){ const dirs = [[1,0],[-1,0],[0,1],[0,-1]]; for(const [dr,dc] of dirs){ const rr = r+dr, cc = c+dc; if(inBounds(rr,cc) && !state.aiTried.has(key(rr,cc))){ // Avoid duplicates in queue: simple check if(!state.aiTargets.some(p=>p[0]===rr && p[1]===cc)){ state.aiTargets.push([rr,cc]); } } } } function inBounds(r,c){ return r>=0 && r<SIZE && c>=0 && c<SIZE } function key(r,c){ return r+','+c } // --- Logging --- function log(msg){ const p = document.createElement('div'); p.textContent = msg; els.log.appendChild(p); els.log.scrollTop = els.log.scrollHeight; } function logClear(){ els.log.innerHTML = '' } // --- Controls --- els.newGameBtn.addEventListener('click', ()=>{ init(); }); els.showShipsBtn.addEventListener('click', ()=>{ state.showShips = !state.showShips; renderBoards(); }); // Start init(); })(); </script> </body> </html>
Save file
Quick jump
open a path
Open