UNPKG

claude-arcade

Version:

Add classic arcade games to your Claude Code workflow with Ctrl+G

174 lines (173 loc) 6.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BrickBreakerGame = void 0; class BrickBreakerGame { constructor() { this.ball = { x: 25, y: 10, vx: 0.7, vy: 0.8 }; this.paddle = { x: 21 }; this.blocks = []; this.score = 0; this.playing = false; this.WIDTH = 50; this.HEIGHT = 20; this.PADDLE_WIDTH = 7; // Strength levels: 4=red, 3=magenta, 2=yellow, 1=cyan this.STRENGTH_COLORS = { 4: '\x1b[31m', // Red 3: '\x1b[35m', // Magenta 2: '\x1b[33m', // Yellow 1: '\x1b[36m' // Cyan }; } isPlaying() { return this.playing; } getScore() { return this.score; } initBlocks() { this.blocks = []; // Create 4 rows of blocks with different initial strengths for (let row = 0; row < 4; row++) { const strength = 4 - row; // Top row strongest (4), bottom weakest (1) for (let col = 0; col < 10; col++) { this.blocks.push({ x: col * 5, y: row, strength: strength }); } } } reset() { this.ball = { x: 25, y: 10, vx: 1, vy: -1 }; this.paddle = { x: 21 }; this.score = 0; this.initBlocks(); } start() { this.playing = true; this.reset(); } stop() { this.playing = false; } update() { this.ball.x += this.ball.vx; this.ball.y += this.ball.vy; // Wall bounce - simple and predictable if (this.ball.x <= 0 || this.ball.x >= this.WIDTH - 1) { this.ball.vx *= -1; this.ball.x = Math.max(0, Math.min(this.WIDTH - 1, this.ball.x)); } // Top wall bounce if (this.ball.y <= 0) { this.ball.vy *= -1; this.ball.y = 0; } const ballX = Math.round(this.ball.x); const ballY = Math.round(this.ball.y); // Paddle hit if (ballY >= this.HEIGHT - 2 && ballX >= this.paddle.x && ballX < this.paddle.x + this.PADDLE_WIDTH && this.ball.vy > 0) { this.ball.vy *= -1; // Adjust horizontal speed based on where ball hits paddle const hitPos = (this.ball.x - this.paddle.x) / this.PADDLE_WIDTH; if (hitPos < 0.35) { this.ball.vx = -1; // Hit left side, go left } else if (hitPos > 0.65) { this.ball.vx = 1; // Hit right side, go right } // Middle hits keep current horizontal velocity this.ball.y = this.HEIGHT - 3; } // Block collision for (const block of this.blocks) { if (block.strength === 0) continue; if (ballX >= block.x && ballX < block.x + 5 && ballY === block.y) { block.strength--; this.ball.vy *= -1; this.score += (5 - block.strength) * 10; // More points for stronger blocks break; } } // Win/Lose if (this.blocks.every(b => b.strength === 0)) { this.playing = false; return { won: true }; } if (this.ball.y >= this.HEIGHT) { this.playing = false; return { lost: true }; } return {}; } movePaddleLeft() { this.paddle.x = Math.max(0, this.paddle.x - 5); } movePaddleRight() { this.paddle.x = Math.min(this.WIDTH - this.PADDLE_WIDTH, this.paddle.x + 5); } draw() { const YELLOW = '\x1b[33m', CYAN = '\x1b[36m', RESET = '\x1b[0m'; const GREEN = '\x1b[32m', WHITE = '\x1b[37m'; let output = '\x1b[2J\x1b[1;1H' + YELLOW + `Score: ${this.score}` + RESET; const ballX = Math.round(this.ball.x); const ballY = Math.round(this.ball.y); const paddleY = this.HEIGHT - 2; // Top border output += `\x1b[2;1H` + WHITE + '┌' + '─'.repeat(this.WIDTH) + '┐' + RESET; for (let y = 0; y < this.HEIGHT; y++) { output += `\x1b[${y + 3};1H` + WHITE + '│' + RESET; for (let x = 0; x < this.WIDTH; x++) { const block = this.blocks.find(b => b.strength > 0 && y === b.y && x >= b.x && x < b.x + 5); const isBall = ballX === x && ballY === y; const isPaddle = y === paddleY && x >= this.paddle.x && x < this.paddle.x + this.PADDLE_WIDTH; if (block) { output += this.STRENGTH_COLORS[block.strength] + '█' + RESET; } else if (isBall) { output += YELLOW + '●' + RESET; } else if (isPaddle) { output += CYAN + '═' + RESET; } else { output += ' '; } } output += WHITE + '│' + RESET; } // Bottom border output += `\x1b[${this.HEIGHT + 3};1H` + WHITE + '└' + '─'.repeat(this.WIDTH) + '┘' + RESET; output += `\x1b[${this.HEIGHT + 5};1H` + GREEN + 'Q/Ctrl+C: Exit | ←→ or A/D: Move | P: Restart' + RESET; return output; } drawGameOver(won) { const GREEN = '\x1b[32m', RED = '\x1b[31m', YELLOW = '\x1b[33m', RESET = '\x1b[0m'; let output = '\x1b[2J\x1b[10;1H'; if (won) { output += GREEN + '🎉 YOU WIN! 🎉\n\n' + RESET; } else { output += RED + '💀 GAME OVER! 💀\n\n' + RESET; } output += YELLOW + `Final Score: ${this.score}\n` + RESET; return output; } drawWelcome() { const CYAN = '\x1b[36m', GREEN = '\x1b[32m', YELLOW = '\x1b[33m', RESET = '\x1b[0m'; const RED = '\x1b[31m', MAGENTA = '\x1b[35m'; return '\x1b[2J\x1b[10;1H' + CYAN + '🧱 BRICK BREAKER 🧱\n\n' + RESET + YELLOW + 'Break all the bricks!\n\n' + RESET + RED + '█' + RESET + ' Strong (40pts) → ' + MAGENTA + '█' + RESET + ' (30pts) → ' + YELLOW + '█' + RESET + ' (20pts) → ' + CYAN + '█' + RESET + ' Weak (10pts)\n\n' + GREEN + 'Press P to start!\n' + YELLOW + 'Press Q or Ctrl+C to exit back to Claude\n' + RESET; } } exports.BrickBreakerGame = BrickBreakerGame;