claude-arcade
Version:
Add classic arcade games to your Claude Code workflow with Ctrl+G
158 lines (157 loc) • 5.65 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BreakoutGame = void 0;
class BreakoutGame {
constructor() {
this.ball = { x: 25, y: 10, vx: 1, vy: 1 };
this.paddle = { x: 21 };
this.blocks = [];
this.score = 0;
this.playing = false;
this.WIDTH = 50;
this.HEIGHT = 20;
this.PADDLE_WIDTH = 7;
}
isPlaying() {
return this.playing;
}
getScore() {
return this.score;
}
initBlocks() {
this.blocks = [];
const colors = ['red', 'yellow', 'green', 'magenta'];
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 10; col++) {
this.blocks.push({
x: col * 5,
y: row,
active: true,
color: colors[row]
});
}
}
}
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
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));
}
if (this.ball.y <= 0) {
this.ball.vy *= -1;
this.ball.y = 0;
}
// Paddle hit
const ballX = Math.round(this.ball.x);
const ballY = Math.round(this.ball.y);
if (ballY >= this.HEIGHT - 2 && ballX >= this.paddle.x &&
ballX < this.paddle.x + this.PADDLE_WIDTH && this.ball.vy > 0) {
this.ball.vy *= -1;
const hitPos = (this.ball.x - this.paddle.x) / this.PADDLE_WIDTH;
if (hitPos < 0.3)
this.ball.vx = -1;
else if (hitPos > 0.7)
this.ball.vx = 1;
}
// Block hit
for (const block of this.blocks) {
if (!block.active)
continue;
if (ballX >= block.x && ballX < block.x + 5 && ballY === block.y) {
block.active = false;
this.ball.vy *= -1;
this.score += 10;
break;
}
}
// Win/Lose
if (this.blocks.every(b => !b.active)) {
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', RED = '\x1b[31m';
const GREEN = '\x1b[32m', MAGENTA = '\x1b[35m', RESET = '\x1b[0m';
const WHITE = '\x1b[37m';
const colors = { red: RED, yellow: YELLOW, green: GREEN, magenta: MAGENTA };
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.active && 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 += colors[block.color] + '█' + 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 + 'Press Q to exit back to Claude | ←→ or A/D to move | P to 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\n` + RESET;
output += GREEN + 'Press P to play again | Press Q to exit back to Claude\n' + RESET;
return output;
}
drawWelcome() {
const CYAN = '\x1b[36m', GREEN = '\x1b[32m', YELLOW = '\x1b[33m', RESET = '\x1b[0m';
return '\x1b[2J\x1b[10;1H' + CYAN + 'BREAKOUT GAME\n\n' + RESET +
GREEN + 'Press P to start!\n' +
YELLOW + 'Press Q to exit back to Claude\n' + RESET;
}
}
exports.BreakoutGame = BreakoutGame;