Chess
bonsai 27b · composer

Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 14,820 bytes · SHA-256 f7facd5e5edd
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chess — Minimax AI Opponent</title>
<style>
/* ── css: layout ── */
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden;background:#1a1a2e;color:#c8c8c8;font-family:'Segoe UI',system-ui,sans-serif}
#app{display:flex;flex-direction:column;height:100%;position:relative}
.game-header{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#16213e;border-bottom:1px solid #2a2a5c;font-size:15px}
.title{font-size:28px;font-weight:700;color:#e8d9b7;letter-spacing:3px;text-transform:uppercase;margin-right:auto}
.ctrl-btn,button,select{cursor:pointer;background:none;border:1px solid #4a4a7a;color:#c8c8c8;padding:6px 12px;border-radius:4px;font-size:13px;transition:all .2s}
.ctrl-btn:hover,.btn-small:hover,.mob-btn:hover,#select:hover{background:#2a2a5c;color:white}
.ctrl-btn,button:disabled{opacity:.45;cursor:not-allowed}
.select-btn{appearance:none;-webkit-appearance:none;background:#2a2a5c;border:1px solid #4a4a7a;padding:6px 10px;border-radius:4px;color:#c8c8c8;font-size:13px;outline:none}
.game-panel{display:flex;height:calc(100vh-56px);overflow:hidden}
.side-panel{width:200px;background:#0f1a2e;border-right:1px solid #2a2a5c;padding:14px 12px;display:flex;flex-direction:column;gap:16px}
.info-box{font-size:18px;color:#c8c8c8;line-height:1.4}
.info-box h3{color:#e8d9b7;font-weight:600;margin-bottom:4px}
.move-list-section{flex:1;overflow-y:auto}
.move-list-section h4{font-size:12px;color:#888;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.move-item{display:flex;align-items:center;padding:3px 0;font-size:12.5px;border-bottom:1px solid #1a1a3a}
.move-item:last-child{border-bottom:none}
.move-item .from,.move-item .to,.move-item .result,.move-item .type{color:#c8c8c8}
.move-item .type{font-size:10.5px;color:#666;font-family:'Courier New',monospace}
.btn-small{width:100%;padding:7px 12px;border-radius:4px;margin-top:8px;font-size:12.5px}
.tray-section h4{font-size:12px;color:#888;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.tray{display:flex;gap:4px;flex-wrap:wrap;margin-top:2px;font-size:20px;min-height:30px}
.controls-section h4{font-size:12px;color:#888;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.controls-section select{width:100%;padding:6px 10px;border-radius:4px;font-size:13px}
.game-main{flex:1;display:flex;align-items:center;justify-content:center;background:#0a0a2e;padding:8px}
.board-wrapper{position:relative}
#gameCanvas{display:block;border-radius:6px}
.overlay{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(10,10,30,.92);border:1px solid #4a4a7a;padding:18px;border-radius:8px;z-index:10}
.overlay h5{font-size:16px;color:#e8d9b7;margin-bottom:10px;text-align:center}
promo-buttons{display:flex;gap:6px}
.game-over-overlay{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(10,10,30,.97);border:2px solid #e8d9b7;padding:40px;border-radius:12px;z-index:20;display:none;flex-direction:column;align-items:center;text-align:center}
.game-over-overlay h3{font-size:32px;color:#e8d9b7;margin-bottom:6px}
.game-over-overlay p{color:#c8c8c8;margin-bottom:18px;font-size:15px}
.btn-large{padding:12px 40px;border-radius:6px;font-size:16px;font-weight:600;background:#e8d9b7;color:#1a1a2e;border:none;cursor:pointer}
.mobile-controls{display:flex;gap:14px;justify-content:center;padding:12px;width:100%;margin:0 auto}
.mob-btn{width:56px;height:56px;border-radius:50%;border:1px solid #4a4a7a;color:white;font-size:20px;background:#2a2a5c;cursor:pointer;display:flex;align-items:center;justify-content:center}
.hints{text-align:center;padding:8px 20px;font-size:11px;color:#666}
/* ── css: board ── */
/* --- Board rendering --- */
.board{display:none}
.square{width:52px;height:52px;border-radius:3px}
.square.w{background:#d4a86b}
.square.b{background:#b8974e}
/* Piece colors */
.pw{color:#f0c878}
.pb{color:#4a4a6a}
/* Highlighted squares */
.hl{opacity:.35}
.hl.capturing{border:2px solid #ff4444;border-radius:50%}
.hl.own{border:1px solid #66cc44;border-radius:4px}
/* Check indicator on king square */
.check-king .square{background:#ff3333;opacity:.55;}
.check-king .square::after{content:'';position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}
/* Last-move highlight */
.lmh.square{background:#66cc44;opacity:.3}
/* Promotion overlay buttons */
.promo-buttons button{padding:8px 12px;border-radius:6px;margin:2px;border:1px solid #4a4a7a;background:#2a2a5c;color:white;font-size:18px}
.promo-buttons button:hover{background:#e8d9b7;color:#1a1a2e}
/* Checkmate overlay */
.checkmate-glow{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:5;animation:pulse 1.2s infinite}
@keyframes pulse{0%,100%{opacity:.6}50%{opacity:.9}}
/* Mobile responsive */
@media(max-width:640px){
.game-panel{width:100%;height:auto;flex-direction:column}
.side-panel{width:100%;padding:8px}
.mobile-controls{position:fixed;bottom:0;left:0;width:100%;z-index:100;display:flex;justify-content:center;gap:12px}
.board-wrapper{border-radius:none}
.game-over-overlay{top:auto;bottom:64px}
}
</style>
</head>
<body>
<header class="game-header">
<div class="title" id="titleDisplay">Chess</div>
<button class="ctrl-btn" id="newGameBtn">← New Game</button>
<button class="ctrl-btn" id="undoBtn" disabled="">✔ Undo</button>
<button class="ctrl-btn" id="muteBtn">🔊</button>
</header>
<div class="game-panel">
<aside class="side-panel">
<section class="info-box">
<h3 id="turnLabel">White to Move</h3>
<p id="statusLabel"></p>
</section>
<section class="move-list-section">
<h4>Move List</h4>
<div class="move-list" id="moveList"></div>
<button class="btn-small" id="clearMovesBtn">Clear Moves</button>
</section>
<section class="tray-section">
<h4>Captured Pieces</h4>
<div class="tray" id="trayWhite"></div>
<div class="tray" id="trayBlack"></div>
</section>
<section class="controls-section">
<h4>Difficulty</h4>
<select id="depthSelect">
<option value="1">Depth 1 (Easy)</option>
<option value="2" selected="">Depth 2 (Medium)
</option><option value="3">Depth 3 (Hard)</option>
</select>
</section>
<section class="controls-section">
<h4>Side Selector</h4>
<p id="sideLabel">Play as White</p>
<button class="btn-small" id="flipSideBtn">Flip Side</button>
</section>
</aside>
<main class="game-main">
<div class="board-wrapper">
<canvas id="gameCanvas"></canvas>
<div class="overlay" id="promotionOverlay" style="display:none;">
<h5>Promote</h5>
<div class="promo-buttons">
<button data-piece="Queen">Q</button>
<button data-piece="Rook">R</button>
<button data-piece="Bishop">B</button>
<button data-piece="Knight">N</button>
</div>
</div>
</div>
<div class="game-over-overlay" id="gameOverOverlay" style="display:none;">
<h3 id="resultTitle"></h3>
<p id="resultMessage"></p>
<button class="btn-large" id="playAgainBtn">Play Again</button>
</div>
</main>
</div>
<div class="mobile-controls" id="mobileControls"></div>
<div class="game-main" id="mainGameArea"></div>
<div class="mobile-controls" id="mobileControls">
<button class="mob-btn" data-action="newGame">←</button>
<button class="mob-btn" data-action="undo">✔ Undo</button>
<button class="mob-btn" data-action="mute">✾</button>
</div>
<div class="hints">Click to move • Drag to move • Space/Enter on promotion</div>
<script>
'use strict';
// ── const: COLORS ──
const COLORS={W:'white',B:'black'};
// ── const: ALPHABET ──
const ALPHABET='abcdefgh';
// ── const: EMPTY ──
const EMPTY=0;
// ── const: WHITE_P ──
const WHITE_P=1;
// ── const: BLACK_P ──
const BLACK_P=9;
// ── const: WHITE_N ──
const WHITE_N=2;
// ── const: BLACK_N ──
const BLACK_N=10;
// ── const: WHITE_B ──
const WHITE_B=3;
// ── const: BLACK_B ──
const BLACK_B=11;
// ── const: WHITE_R ──
const WHITE_R=4;
// ── const: BLACK_R ──
const BLACK_R=12;
// ── const: WHITE_Q ──
const WHITE_Q=5;
// ── const: BLACK_Q ──
const BLACK_Q=13;
// ── const: WHITE_K ──
const WHITE_K=6;
// ── const: BLACK_K ──
const BLACK_K=14;
// ── const: CASTLING ──
const CASTLING={LEFT:0,RIGHT:1,KING:2,QUEEN:3};
// ── const: ALL_CASTLING ──
const ALL_CASTLING=7;
// ── const: WKS ──
const WKS=6;
// ── const: WKQ ──
const WKQ=2;
// ── const: BKQ ──
const BKQ=9;
// ── const: BKS ──
const BKS=13;
// ── function: initBoard ──
function initBoard(){const b=[];for(let i=0;i<64;i++)b[i]=EMPTY;b[56]=WHITE_R;b[57]=WHITE_N;b[58]=WHITE_B;b[59]=WHITE_Q;b[60]=WHITE_K;b[61]=WHITE_Q;b[62]=WHITE_B;b[63]=WHITE_N;for(let i=40;i<=47;i++)b[i]=WHITE_P;for(let i=8;i<=15;i++)b[i]=BLACK_P;return b;}
// ── function: pieceInfo ──
function pieceInfo(p){if(!p||p===EMPTY) return null;const color=p<8?COLORS.W:COLORS.B;let t='P';switch(p%8){case 1:t='n';break;case 2:t='b';break;case 3:t='r';break;case 4:t='q';break;case 5:t='k';break;}return {color,piece:t};}
// ── function: foo ──
function foo(){return 1}
// ── const: idxToCoord ──
const idxToCoord=i=>({f:ALPHABET[i%8],r:i/8|0})
// ── const: coordToIdx ──
const coordToIdx=(f,r)=>((63-r)*8+(f.charCodeAt(0)-97))
// ── const: isWhite ──
const isWhite=p=>p>=0&&p<=7;
// ── const: isBlack ──
const isBlack=p=>p>=8&&p<=14;
// ── const: moveFrom ──
const moveFrom=(i,j)=>(63-i)*8+j;
// ── const: moveTo ──
const moveTo=(f,r)=>(63-r)*8+(f.charCodeAt(0)-97);
// ── const: getPieceType ──
const getPieceType=p=>{switch(p){case 1:return'P';case 2:return'n';case 3:return'b';case 4:return'r';case 5:return'q';case 6:return'k';default:return p%8==1?'P':p%8==1?'n':'b'};};
// ── const: getKnightMoves ──
const getKnightMoves=(b,i,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];for(let dx=-2;dx<=2;dx++)for(let dy=-2;dy<=2;dy++){if(Math.abs(dx)+Math.abs(dy)!=3){const ni=(i/8|0)+(i%8+dx);if(ni>=0&&ni<64&&!b[ni]||b[ni]==isWhite(turn)?WHITE_P:BLACK_P)moves.push({from:i,to:ni});}}return moves;};
// ── const: getBishopMoves ──
const getBishopMoves=(b,i,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];const directions=[[-1,-1],[-1,1],[1,-1],[1,1]];for(const[dx,dy]of directions){let ni=(i/8|0)+(i%8+dx);while(ni>=0&&ni<64&&!b[ni])moves.push({from:i,to:ni});if(b[ni]==isWhite(turn)?WHITE_P:BLACK_P)moves.push({from:i,to:ni,capture:true});else break;}return moves;};
// ── const: getRookMoves ──
const getRookMoves=(b,i,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];const directions=[[-1,0],[1,0],[0,-1],[0,1]];for(const[dx,dy]of directions){let ni=(i/8|0)+(i%8+dx);while(ni>=0&&ni<64&&!b[ni])moves.push({from:i,to:ni});if(b[ni]==isWhite(turn)?WHITE_P:BLACK_P)moves.push({from:i,to:ni,capture:true});else break;}return moves;};
// ── const: getQueenMoves ──
const getQueenMoves=(b,i,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];const directions=[[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];for(const[dx,dy]of directions){let ni=(i/8|0)+(i%8+dx);while(ni>=0&&ni<64&&!b[ni])moves.push({from:i,to:ni});if(b[ni]==isWhite(turn)?WHITE_P:BLACK_P)moves.push({from:i,to:ni,capture:true});else break;}return moves;};
// ── const: getKingMoves ──
const getKingMoves=(b,i,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];for(let dx=-1;dx<=1;dx++)for(let dy=-1;dy<=1;dy++){if(dx===0&&dy===0) continue;const ni=(i/8|0)+(i%8+dx);if(ni>=0&&ni<64&&!b[ni])moves.push({from:i,to:ni});}return moves;};
// ── const: getLegalMoves ──
const getLegalMoves=(b,i,castlingRights,epSQ,turn)=>{const p=b[i];if(!p) return [];const isMyPiece=isWhite(turn)?isWhite(p):isBlack(p);if(!isMyPiece) return [];let moves=[];const piece=getPieceType(p);if(piece==='P')moves.push(...getPawnMoves(b,i,epSQ,castlingRights,turn));else if(piece==='N')moves.push(...getKnightMoves(b,i,turn));else if(piece==='B')moves.push(...getBishopMoves(b,i,turn));else if(piece==='R')moves.push(...getRookMoves(b,i,turn));else if(piece==='Q')moves.push(...getQueenMoves(b,i,turn),...getKingMoves(b,i,turn));else if(piece==='K'){moves.push(...getKingMoves(b,i,turn));if(turn===COLORS.W&&castlingRights&ALL_CASTLING)moves.push({from:i,to:WKS+6,B:WHITE_K,R:WHITE_R,type:'castle'});else if(turn===COLORS.B&&castlingRights&ALL_CASTLING)moves.push({from:i,to:BKS+13,B:BLACK_K,R:BLACK_R,type:'castle'});}return moves;};
// ── const: applyMove ──
const applyMove=(b,mv,castlingRights,epSQ,turn)=>{let newBoard=b.map(x=>x);const [from,to]=mv;newBoard[from]=EMPTY;const p=newBoard[to];if(p===WHITE_P) newBoard[to]=BLACK_P;else if(p===BLACK_P) newBoard[to]=WHITE_P;else if(p===WHITE_N) newBoard[to]=BLACK_N;else if(p===BLACK_N) newBoard[to]=WHITE_N;else if(p===WHITE_B) newBoard[to]=BLACK_B;else if(p===BLACK_B) newBoard[to]=WHITE_B;else if(p===WHITE_R) newBoard[to]=BLACK_R;else if(p===BLACK_R) newBoard[to]=WHITE_R;else if(p===WHITE_Q) newBoard[to]=BLACK_Q;else if(p===BLACK_Q) newBoard[to]=WHITE_Q;else if(p===WHITE_K) newBoard[to]=BLACK_K;else if(p===BLACK_K) newBoard[to]=WHITE_K;if(mv.type==='castle'){if(newBoard[WKS+6]===WHITE_K&&newBoard[WKS+13]===WHITE_R){castlingRights=0;}else if(newBoard[BKS+13]===BLACK_K&&newBoard[BKS+6]===BLACK_R){castlingRights=0;}}return{board:newBoard,castlingRights,epSQ};};
// ── const: isInCheck ──
const isInCheck=(b,turn)=>{const p=b[idxToIdx(ALPHABET[0],6)];if(!p||isWhite(turn)&&p<=7||isBlack(turn)&&p>=8) return false;const kingColor=isWhite(turn)?WHITE_K:BLACK_K;for(const ni of[56+1,57+1,58+1,59+1,60+1,61+1,62+1,63+1]){if(b[ni]===kingColor) return true;}return false;};
// ── const: isCheckmate ──
const isCheckmate=(b,turn)=>{const kingColor=getKingIndex(turn);for(const i of[56+1,57+1,58+1,59+1,60+1,61+1,62+1,63+1]){if(b[i]===kingColor) return false;}return true;};
// ── const: getKingIndex ──
const getKingIndex=(turn)=>{return isWhite(turn)?WHITE_K:BLACK_K};
</script>
</body>
</html>