import { describe, it, expect } from 'vitest';
import { renderLevel, formatSolverResult } from './ascii-renderer.js';
import type { DraftState } from './types.js';
function makeDraft(overrides?: Partial<DraftState>): DraftState {
return {
id: null,
name: 'Test',
description: '',
gridWidth: 5,
gridHeight: 5,
par: 0,
startPosition: { x: 1, y: 3 },
goalPosition: { x: 3, y: 1 },
obstacles: [],
warpPairs: [],
thinIceTiles: [],
pushableRocks: [],
pressurePlate: null,
barrier: null,
isDirty: false,
lastSolverResult: null,
...overrides,
};
}
describe('renderLevel', () => {
it('should render basic grid with walls', () => {
const draft = makeDraft();
const output = renderLevel(draft);
expect(output).toContain('#');
expect(output).toContain('S');
expect(output).toContain('G');
expect(output).toContain('.');
});
it('should render obstacles correctly', () => {
const draft = makeDraft({
obstacles: [
{ x: 2, y: 2, type: 'rock' },
{ x: 3, y: 3, type: 'lava' },
],
});
const output = renderLevel(draft);
expect(output).toContain('R');
expect(output).toContain('L');
});
it('should render all special elements', () => {
const draft = makeDraft({
gridWidth: 8,
gridHeight: 8,
obstacles: [
{ x: 2, y: 2, type: 'hot_coals' },
{ x: 3, y: 3, type: 'lava' },
],
thinIceTiles: [{ x: 4, y: 4 }],
pushableRocks: [{ x: 5, y: 5 }],
warpPairs: [{ id: 'w1', positions: [{ x: 2, y: 5 }, { x: 5, y: 2 }] }],
pressurePlate: { x: 3, y: 5 },
barrier: { x: 5, y: 3 },
});
const output = renderLevel(draft);
expect(output).toContain('^'); // hot coals
expect(output).toContain('L'); // lava
expect(output).toContain('~'); // thin ice
expect(output).toContain('P'); // pushable rock
expect(output).toContain('W'); // warp
expect(output).toContain('!'); // pressure plate
expect(output).toContain('B'); // barrier
});
it('should show coordinate numbers when enabled', () => {
const draft = makeDraft();
const output = renderLevel(draft, { showCoords: true });
expect(output).toContain('0');
expect(output).toContain('1');
});
it('should show solution when provided', () => {
const draft = makeDraft();
const output = renderLevel(draft, {
showSolution: true,
solution: ['right', 'up'],
});
expect(output).toContain('SOLVABLE');
expect(output).toContain('2 moves');
});
it('should show unsolvable when solution is null', () => {
const draft = makeDraft();
const output = renderLevel(draft, { showSolution: true, solution: null });
expect(output).toContain('UNSOLVABLE');
});
it('should render step marker overlay when requested', () => {
const draft = makeDraft({
gridWidth: 8,
gridHeight: 8,
startPosition: { x: 1, y: 6 },
goalPosition: { x: 6, y: 1 },
});
const output = renderLevel(draft, {
showCoords: true,
showStepNumbers: true,
stepPositions: [
{ x: 1, y: 6 },
{ x: 4, y: 6 },
{ x: 4, y: 2 },
{ x: 6, y: 2 },
{ x: 6, y: 1 },
],
});
expect(output).toContain('Step Marker Key:');
expect(output).toContain('1=step 1 (4,6)');
expect(output).toContain('4=goal (6,1)');
});
});
describe('formatSolverResult', () => {
it('should format solvable result', () => {
const result = formatSolverResult({
solvable: true,
moves: 5,
solution: ['up', 'right', 'down', 'left', 'up'],
iterations: 100,
visitedCount: 50,
});
expect(result).toContain('SOLVABLE');
expect(result).toContain('5');
});
it('should format unsolvable result', () => {
const result = formatSolverResult({
solvable: false,
moves: null,
solution: null,
iterations: 1000,
visitedCount: 500,
});
expect(result).toContain('UNSOLVABLE');
});
it('should handle null', () => {
expect(formatSolverResult(null)).toContain('Not yet solved');
});
});
describe('renderLevel OOB warnings', () => {
it('should show warnings for out-of-bounds obstacles', () => {
const draft = makeDraft({
gridWidth: 5,
gridHeight: 5,
obstacles: [
{ x: -1, y: -1, type: 'rock' }, // Out of bounds
{ x: 100, y: 100, type: 'lava' }, // Way out of bounds
{ x: 2, y: 2, type: 'hot_coals' }, // Valid
],
});
const output = renderLevel(draft);
expect(output).toContain('[WARNINGS]');
expect(output).toContain('Obstacle rock at (-1,-1) is outside grid');
expect(output).toContain('Obstacle lava at (100,100) is outside grid');
});
});