mager-bench

Llama 3.3 70B × doom

0.3

DDA raycaster + textures + door + minimap + Z-buffer — the signature challenge

correctness 0.0quality 1.0documentation 0.04262ms
$ cat doom.prompt — what the model was asked
Implement a first-person 3D raycasting engine in a single self-contained HTML file with no external libraries, no external images, and no CDN scripts. This is the hardest challenge in the benchmark. Partial credit is given per requirement met.

## Rendering
- DDA (Digital Differential Analysis) raycasting — not a simplified ray-box approximation
- Fish-eye correction applied to all wall distances
- **Procedurally generated wall textures** using canvas math only (no image files, no data URIs): at least 3 distinct texture patterns (e.g. checkerboard, brick, stripe) assigned to different wall types in the map
- Perspective-correct texture mapping onto wall columns
- Distance-based shading: walls darken smoothly as they recede (multiply shade by 1/distance, clamped)
- Ceiling rendered as a flat dark color; floor as a slightly lighter flat color
- Target: 60fps at 640×480 internal resolution scaled to fill the browser window

## Map
- Hard-coded map of at least 16×16 cells encoded as a 2D array
- Non-trivial layout: at least 3 distinct rooms connected by corridors, one dead end, one secret area
- At least 3 wall types (mapped to the 3 texture patterns)
- One door cell (wall type 4) that opens when the player is within 1.5 cells and presses E; opened doors become passable and render as open archways
- One exit cell — reaching it displays a 'LEVEL COMPLETE — [MM:SS]' overlay
- Player spawn position defined in the map; facing toward the first corridor

## Player
- WASD movement with smooth speed (moveSpeed: 3 cells/sec, rotSpeed: 2 rad/sec)
- Mouse-look for horizontal rotation using the Pointer Lock API (click canvas to lock)
- Collision detection: AABB against all solid walls (player radius: 0.2 cells)
- Field of view: 66 degrees

## Z-buffer
- Maintain a per-column Z-buffer (array of wall distances) for correct depth ordering
- Use it to clip any future sprite/overlay rendering to avoid drawing behind walls

## HUD
- Minimap in top-left corner: draw map cells as colored squares, player as a dot with a direction arrow; scale: 6px per cell
- FPS counter (rolling average over last 30 frames) in top-right corner
- 'Press E to open door' hint rendered in the center-bottom when a door is within 1.5 cells

## Code quality
- Single HTML file, all JS inline in <script> tags, all CSS inline in <style>
- requestAnimationFrame game loop with delta-time movement
- Organized into clearly named functions: initMap(), castRay(), drawWallColumn(), drawHUD(), drawMinimap(), gameLoop(), handleInput()
- No god-object — game state in a plain JS object, renderer functions take state as argument

Scoring: the judge scores each major section (rendering, map, player, HUD, code) independently. A beautiful but mathematically wrong perspective loses on correctness. A correct raycaster with unreadable code loses on quality. Both must be right to score above 8.

run 1 of 1

0.3
correctness 0.0quality 1.0documentation 0.04262ms

# judge: The response is truncated mid-code, leaving the file syntactically invalid and missing nearly all required features (textures, HUD, minimap, input, game loop, door/exit logic, Z-buffer usage).

$ cat llama-3.3-70b.doom.r1.response
Below is a basic implementation of a first-person 3D raycasting engine in a single self-contained HTML file.

```html
<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            margin: 0;
            background-color: #f0f0f0;
        }
        #canvas {
            width: 100%;
            height: 100vh;
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const map = [
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        ];
        const textures = {
            1: 'checkerboard',
            2: 'brick',
            3: 'stripe'
        };
        const player = {
            x: 1.5,
            y: 1.5,
            dirX: 0,
            dirY: 1,
            planeX: 0,
            planeY: 0.66,
            speed: 3,
            rotSpeed: 2,
            radius: 0.2
        };
        const door = {
            x: 8,
            y: 8,
            opened: false
        };
        const exit = {
            x: 15,
            y: 15
        };
        const zBuffer = new Array(canvas.width).fill(Infinity);
        let fps = 0;
        let lastTime = 0;
        let running = false;

        function initMap() {
            for (let i = 0; i < map.length; i++) {
                for (let j = 0; j < map[i].length; j++) {
                    if (map[i][j] === 4) {
                        door.x = j;
                        door.y = i;
                    } else if (map[i][j] === 5) {
                        exit.x = j;
                        exit.y = i;
                    }
                }
            }
        }

        function castRay(x, y, dirX, dirY) {
            let mapX = Math.floor(x);
            let mapY = Math.floor(y);
            let sideDistX;
            let sideDistY;
            let deltaDistX = Math.sqrt(1 + (dirY * dirY) / (dirX * dirX));
            let deltaDistY = Math.sqrt(1 + (dirX * dirX) / (dirY * dirY));
            let stepX;
            let stepY;
            let hit = 0;
            let side;

            if (dirX < 0) {
                stepX = -1;
                sideDistX = (x - mapX) * deltaDistX;
            } else {
                stepX = 1;
                sideDistX = (mapX + 1 - x) * deltaDistX;
            }

            if (dirY < 0) {
                stepY = -1;
                sideDistY = (y - mapY) * deltaDistY;
            } else {
                stepY = 1;
                sideDistY = (mapY + 1 - y) * deltaDistY;
            }

            while (hit === 0) {
                if (sideDistX < sideDistY) {
                    sideDistX += deltaDistX;
                    mapX += stepX;
                    side = 0;
                } else {
                    sideDistY += deltaDistY;
                    mapY += stepY;
                    side = 1;
                }

                if (map[mapY][mapX] > 0) {
                    if (map[mapY][mapX] === 4 && door.opened) {
                        continue;
                    }
                    hit = 1;
                }
            }

            let perpWallDist;
            if (side === 0) {
                perpWallDist = Math.abs((mapX - x + (1 - stepX) / 2) / dirX);
            } else {
                perpWallDist = Math.abs((mapY - y + (1 - stepY) / 2) / dirY);
            }

            return perpWallDist;
        }

        function drawWallColumn(x, perpWallDist) {
            let wallHeight = Math.floor(48000 / perpWallDist);
            let start = Math.floor((240 - wallHeight) / 2);
            let end = start + wallHeight;

            for (let i = start; i < end; i++) {
                let textureY = Math.floor(((i * 2 - 240 + wallHeight) / wallHeight) * 8);
                let color;

                if (map[Math.floor(player.y + player.dirY * perpWallDist)][Math.floor(player.x + player.dirX * perpWallDist)] === 1) {
                    color = '#aaaaaa';
                } else if (map[Math.floor(player.y + player.dirY * perpWallDist)][Math.floor(player.x + player.dirX * perpWallDist)] === 2) {
                    color = '#ff0000';
                } else if (map[Math.floor(player.y + player.dirY * perpWallDist)][Math.floor(player.x + player.dirX * perpWallDist)] === 3) {
                    color = '#00ff00';
                }

                ctx.fillStyle = color;
                ctx.fillRect(x, start, 1, wallHeight);
            }

            return perpWallDist;
        }

        function drawHUD() {
            ctx.fillStyle = '#000000';
            ctx.fillRect(0, 0, 80, 80);
            ctx.fillStyle = '#ffffff';
            ctx.font = '12px Arial';
            ctx.textAlign = 'left';
            ctx.textBaseline = 'top';
            ctx.fillText('FPS: ' + fps.toFixed(2), 10, 10);

            ctx.fillStyle = '#000000';
            ctx.fillRect(canvas.width - 80, 0, 80, 80);
            ctx.fillStyle = '#ffffff';
            ctx.font = '12px Arial