"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Game2048 = void 0;
const DEFAULT = { mode: 'default', value: 0 };
const DARK_GRAY = { mode: 'palette', value: 8 };
const TILE_COLORS = {
    2: { mode: 'palette', value: 7 },
    4: { mode: 'palette', value: 3 },
    8: { mode: 'palette', value: 208 },
    16: { mode: 'palette', value: 1 },
    32: { mode: 'palette', value: 5 },
    64: { mode: 'palette', value: 9 },
    128: { mode: 'palette', value: 11 },
    256: { mode: 'palette', value: 10 },
    512: { mode: 'palette', value: 14 },
    1024: { mode: 'palette', value: 12 },
    2048: { mode: 'palette', value: 10 },
};
const TILE_BG_COLORS = {
    2: { mode: 'palette', value: 235 },
    4: { mode: 'palette', value: 235 },
    8: { mode: 'palette', value: 52 },
    16: { mode: 'palette', value: 88 },
    32: { mode: 'palette', value: 53 },
    64: { mode: 'palette', value: 88 },
    128: { mode: 'palette', value: 58 },
    256: { mode: 'palette', value: 22 },
    512: { mode: 'palette', value: 23 },
    1024: { mode: 'palette', value: 52 },
    2048: { mode: 'palette', value: 22 },
};
function tileColor(value) {
    return TILE_COLORS[value] ?? { mode: 'palette', value: 13 };
}
function tileBgColor(value) {
    return TILE_BG_COLORS[value] ?? { mode: 'palette', value: 53 };
}
class Game2048 {
    name = '2048';
    width = 0;
    height = 0;
    board = [];
    score = 0;
    _paused = false;
    _gameOver = false;
    won = false;
    init(width, height) {
        this.width = Math.max(1, width);
        this.height = Math.max(1, height);
        this.reset();
    }
    tick(_deltaMs) {
        // Turn-based game — nothing to do on tick.
    }
    handleInput(key) {
        if (this._paused) {
            if (key === 'pause')
                this.resume();
            return;
        }
        if (this._gameOver) {
            if (key === 'reset' || key === 'space')
                this.reset();
            return;
        }
        switch (key) {
            case 'up':
            case 'down':
            case 'left':
            case 'right':
                this.move(key);
                break;
            case 'pause':
                this.pause();
                break;
            case 'reset':
                this.reset();
                break;
        }
    }
    getState() {
        const grid = [];
        for (let r = 0; r < this.height; r++) {
            grid[r] = [];
            for (let c = 0; c < this.width; c++) {
                grid[r][c] = { char: ' ', fg: DEFAULT, bg: DEFAULT };
            }
        }
        this.renderBoard(grid);
        let statusMessage;
        if (this._gameOver)
            statusMessage = 'GAME OVER - Press SPACE or R';
        else if (this._paused)
            statusMessage = 'PAUSED - Ctrl+Space to resume';
        else if (this.won)
            statusMessage = 'YOU WIN! Keep going or R:Reset';
        return {
            grid,
            score: this.score,
            status: this._gameOver ? 'gameover' : this._paused ? 'paused' : 'playing',
            statusMessage,
        };
    }
    resize(width, height) {
        this.width = Math.max(1, width);
        this.height = Math.max(1, height);
    }
    isPaused() { return this._paused; }
    pause() { this._paused = true; }
    resume() { if (!this._gameOver)
        this._paused = false; }
    isGameOver() { return this._gameOver; }
    reset() {
        this._gameOver = false;
        this._paused = false;
        this.won = false;
        this.score = 0;
        this.board = Array.from({ length: 4 }, () => [0, 0, 0, 0]);
        this.spawnTile();
        this.spawnTile();
    }
    // ── Core mechanics ──────────────────────────────────────────────
    move(dir) {
        const before = this.boardSnapshot();
        switch (dir) {
            case 'left':
                this.slideLeft();
                break;
            case 'right':
                this.slideRight();
                break;
            case 'up':
                this.slideUp();
                break;
            case 'down':
                this.slideDown();
                break;
        }
        if (!this.boardsEqual(before, this.board)) {
            if (!this.won)
                this.checkWin();
            this.spawnTile();
            if (!this.hasValidMoves())
                this._gameOver = true;
        }
    }
    slideLeft() {
        for (let r = 0; r < 4; r++) {
            this.board[r] = this.mergeRow(this.board[r]);
        }
    }
    slideRight() {
        for (let r = 0; r < 4; r++) {
            this.board[r] = this.mergeRow(this.board[r].slice().reverse()).reverse();
        }
    }
    slideUp() {
        for (let c = 0; c < 4; c++) {
            const col = [this.board[0][c], this.board[1][c], this.board[2][c], this.board[3][c]];
            const merged = this.mergeRow(col);
            for (let r = 0; r < 4; r++)
                this.board[r][c] = merged[r];
        }
    }
    slideDown() {
        for (let c = 0; c < 4; c++) {
            const col = [this.board[3][c], this.board[2][c], this.board[1][c], this.board[0][c]];
            const merged = this.mergeRow(col);
            for (let r = 0; r < 4; r++)
                this.board[3 - r][c] = merged[r];
        }
    }
    /** Slide and merge a single row toward index 0. */
    mergeRow(row) {
        // Compact non-zero values to the left.
        const compact = row.filter(v => v !== 0);
        const result = [];
        let i = 0;
        while (i < compact.length) {
            if (i + 1 < compact.length && compact[i] === compact[i + 1]) {
                const merged = compact[i] * 2;
                result.push(merged);
                this.score += merged;
                i += 2;
            }
            else {
                result.push(compact[i]);
                i++;
            }
        }
        while (result.length < 4)
            result.push(0);
        return result;
    }
    spawnTile() {
        const empty = [];
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (this.board[r][c] === 0)
                    empty.push({ r, c });
            }
        }
        if (empty.length === 0)
            return;
        const cell = empty[Math.floor(Math.random() * empty.length)];
        this.board[cell.r][cell.c] = Math.random() < 0.9 ? 2 : 4;
    }
    hasValidMoves() {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (this.board[r][c] === 0)
                    return true;
                if (c + 1 < 4 && this.board[r][c] === this.board[r][c + 1])
                    return true;
                if (r + 1 < 4 && this.board[r][c] === this.board[r + 1][c])
                    return true;
            }
        }
        return false;
    }
    boardSnapshot() {
        return this.board.map(row => row.slice());
    }
    checkWin() {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (this.board[r][c] >= 2048) {
                    this.won = true;
                    return;
                }
            }
        }
    }
    boardsEqual(a, b) {
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (a[r][c] !== b[r][c])
                    return false;
            }
        }
        return true;
    }
    // ── Rendering ───────────────────────────────────────────────────
    renderBoard(grid) {
        const tileW = 6; // characters per tile horizontally
        const tileH = 3; // rows per tile vertically
        const gridW = tileW * 4 + 1; // +1 for right border
        const gridH = tileH * 4 + 1; // +1 for bottom border
        // Center the rendered board within the panel.
        const offsetX = Math.max(0, Math.floor((this.width - gridW) / 2));
        const offsetY = Math.max(0, Math.floor((this.height - gridH) / 2));
        for (let tr = 0; tr < 4; tr++) {
            for (let tc = 0; tc < 4; tc++) {
                const value = this.board[tr][tc];
                const cellX = offsetX + tc * tileW;
                const cellY = offsetY + tr * tileH;
                this.renderTile(grid, cellX, cellY, tileW, tileH, value);
            }
        }
        // Draw grid lines.
        this.renderGridLines(grid, offsetX, offsetY, tileW, tileH);
    }
    renderTile(grid, x, y, w, h, value) {
        const fg = value === 0 ? DARK_GRAY : tileColor(value);
        const bg = value === 0 ? DEFAULT : tileBgColor(value);
        const label = value === 0 ? '·' : String(value);
        const midRow = y + Math.floor(h / 2);
        const labelStart = x + Math.max(0, Math.floor((w - label.length) / 2));
        for (let dy = 0; dy < h; dy++) {
            for (let dx = 0; dx < w; dx++) {
                const gr = y + dy;
                const gc = x + dx;
                if (gr < 0 || gr >= this.height || gc < 0 || gc >= this.width)
                    continue;
                grid[gr][gc] = { char: ' ', fg: DEFAULT, bg };
            }
        }
        for (let i = 0; i < label.length; i++) {
            const gc = labelStart + i;
            if (midRow >= 0 && midRow < this.height && gc >= 0 && gc < this.width) {
                grid[midRow][gc] = { char: label[i], fg, bg };
            }
        }
    }
    renderGridLines(grid, ox, oy, tileW, tileH) {
        const fg = DARK_GRAY;
        for (let i = 0; i <= 4; i++) {
            const row = oy + i * tileH;
            if (row < 0 || row >= this.height)
                continue;
            for (let col = ox; col < ox + tileW * 4 + 1 && col < this.width; col++) {
                if (col < 0)
                    continue;
                const isVLine = (col - ox) % tileW === 0;
                if (isVLine) {
                    const ci = (col - ox) / tileW;
                    let char;
                    if (i === 0)
                        char = ci === 0 ? '┌' : ci === 4 ? '┐' : '┬';
                    else if (i === 4)
                        char = ci === 0 ? '└' : ci === 4 ? '┘' : '┴';
                    else
                        char = ci === 0 ? '├' : ci === 4 ? '┤' : '┼';
                    grid[row][col] = { char, fg, bg: DEFAULT };
                }
                else {
                    grid[row][col] = { char: '─', fg, bg: DEFAULT };
                }
            }
        }
        for (let i = 0; i <= 4; i++) {
            const col = ox + i * tileW;
            if (col < 0 || col >= this.width)
                continue;
            for (let row = oy; row < oy + tileH * 4 + 1 && row < this.height; row++) {
                if (row >= 0 && (row - oy) % tileH !== 0) {
                    grid[row][col] = { char: '│', fg, bg: DEFAULT };
                }
            }
        }
    }
}
exports.Game2048 = Game2048;
//# sourceMappingURL=game-2048.js.map