How to make a roguelike with AI
Replace Math.random with one seeded generator before anything else. It is six lines, and it turns every crash from a story into a bug you can hand over.
Jump to a section
Ask for a generated dungeon, short runs and a death screen, and insist that every random choice comes from one seeded generator rather than from Math.random. That single constraint is what makes the genre workable with a model. Without it, half of what goes wrong happened once and can never be shown to anybody again.
A roguelike is built on randomness, which means it is built on the one thing that makes debugging hard. A seeded generator keeps all of the variety and gives back the ability to play the same floor twice. Print the seed where the player can see it, and let them type one in.
Four steps to a run you can play twice#
It writes a seeded dungeon, two kinds of enemy, short floors and a death screen that names the thing that got you.
A wall you could walk through, a stairway in a sealed room, an enemy spawned on top of you. The seed is the whole report.
If it does not happen again, something is still calling the unseeded generator, and that is the fault to chase first.
Floor count, enemy counts and health, one change at a time. A run that outlives your patience is the usual first fault.
Build a small roguelike as ONE self-contained .html file. No
frameworks and no images. Draw the dungeon on a canvas with shapes.
SEED: write a tiny seeded random number generator and route every
random choice in the game through it. Math.random must not appear
anywhere. One run uses one generator, built from one integer seed.
START SCREEN: a play button and a text box where a seed can be typed.
Left empty, take a seed from the clock and display it.
GENERATION: rooms joined by corridors on a grid, laid out with the
seeded generator. Every room reachable from the start. A stairway down
placed somewhere other than the room the player begins in.
THE RUN: five floors, each slightly larger and more dangerous than
the one above it. A whole run should be over quickly, win or lose.
MOVEMENT: arrow keys or WASD move one tile. Enemies move only when
the player does, so nothing happens while the player is thinking.
ENEMIES: two kinds. One chases across the floor. One guards a room
and hits harder. Both placed by the seeded generator.
ITEMS: health, and one item that changes how fighting works. Placed
by the seeded generator, so one seed always gives the same items in
the same rooms.
DEATH SCREEN: say what killed the player, on which floor, after how
many turns. Show the seed in large type, with a button that copies it
and a button that replays that exact seed.
PHONE: a swipe moves one tile in that direction. Include
canvas { touch-action: none; } so swiping never scrolls the page.
Animate the steps and the damage flashes from the seconds that
elapsed since the previous frame, clamped so it can never pass 0.05.
Keep floor count, room sizes, enemy counts, damage and starting
health in one CONFIG object at the top, each with a comment.
Change the CONFIG numbers and the two enemy behaviours freely. The SEED paragraph is the one to leave exactly as it is, including the sentence forbidding Math.random. Models reach for it by habit, and one stray call is enough to make a seed stop reproducing a run.
What a seeded generator actually buys you#
The usual way this goes wrong is quiet. You play, something absurd happens, you reload to look at it properly, and it is gone. The next twenty runs behave. You cannot describe the fault precisely, so you describe it loosely, and a loose description gets a loose fix that may not touch the real cause.
A seeded generator removes the guessing. The generator is a function of one integer, so the same integer produces the same sequence, which produces the same dungeon. Paste the seed into a message with the thing that went wrong and the model is working from the same floor you were.
// A small seeded generator. Same seed in, same sequence out.
function rng(seed) {
let a = seed >>> 0;
return function () {
a = (a + 0x6D2B79F5) >>> 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// One per run, built from whatever the start screen supplied.
const seed = Number(seedBox.value) || (Date.now() % 1e9);
const rand = rng(seed);
// Everywhere else in the game, rand() replaces Math.random().
const roomWidth = CONFIG.minRoom + Math.floor(rand() * CONFIG.roomSpread);
It also buys you something the player can use. Two people can compare the same dungeon, which turns a score into a fair comparison rather than a report of how lucky somebody was. Posting a hard seed and daring other people to clear it is a genuine reason to come back.
Run length, and what survives a death#
A run has to be short enough that losing it is annoying rather than painful. If a death costs an hour, players stop taking risks, and a roguelike with careful players is a slow one. Short runs let people experiment, and experimenting is where the genre gets its replay value.
The distinction worth holding is between knowledge and advantage. Learning that the guard enemy cannot follow you through a corridor is progress and it costs nothing. Starting the next run with saved gold is advantage, and it eats the tension the whole design runs on.
Adding to the pool is the one safe form of unlocked content. Find a strange item once and it becomes something later runs might offer. The player gains variety rather than strength, so the game is wider than it was yesterday and no easier.
A death screen that says what killed you#
Most first builds print the word dead and a score. That is the biggest wasted moment in the genre. Death is the one point where the player is paying full attention to what just happened, and wondering whether any of it was their own fault.
- Name the cause. Not died. Killed by the guard on floor three, with two health left, after eighty one turns. The player either accepts that or argues with it, and both mean they are still engaged.
- Show the seed large. It is the one thing on the screen you want copied. Put a copy button next to it and a replay button under it.
- Offer the same seed again. A player who nearly cleared a floor wants that floor, not a new one. This is also how you test a fix in seconds.
- Keep the best run visible. Depth reached and turns taken. It is the only scoreboard the genre needs and it costs two lines of storage.
Causes of death are also your best source of balance information. If every death screen names the same enemy, that enemy is doing the work of the entire game. If one is never mentioned, it is not a threat and the floor would read the same without it.
💀Roguelikes written by AI
Common questions#
Can AI make a roguelike?
Yes, and generated levels are one of the things a model is genuinely good at. The part you have to insist on is the seeding. Ask for it in the first prompt, because retrofitting means finding every random call in a file you did not write.
Why can I not reproduce the bug I just saw?
Something is still calling Math.random. One stray call is enough, because it pulls the generation off the sequence your seed produced. Search the file for the word random and route every hit through the seeded generator.
What makes a roguelike different from an RPG?
A roguelike loses everything on death and builds the world fresh each time. An RPG keeps a party and a world and grows them. That changes how you build. A roguelike needs a generator you can trust, and an RPG needs a fight worth repeating.
How long should one run take?
Short enough that a death costs almost nothing. A player who has invested an hour stops opening doors, and a cautious roguelike is a dull one. Start it far shorter than feels right and grow it only after people ask for more.
Should anything carry between runs?
Records and variety, never strength. Best depth, seeds you have beaten, and items added to the pool after you first meet one. Saved health, gear or currency all make the next attempt easier, which removes the reason the current one was tense.
How do I stop the generator making sealed rooms?
Ask for the layout to be checked after it is built, and rebuilt from the next seed if anything is cut off. State it as a rule in the prompt. It is also the fault that proves seeding was worth it, since you can hand over the exact seed that broke.
Where to go next#
When a run is one you want to beat, put it up. It gets a page recording the model and the prompt behind it, and a leaderboard where somebody else will take your best depth.
The general method is in how to make a game with AI. If you want a party and a world that persist instead, the RPG guide has the build order for that. Wording for common faults sits in the prompt guide, and the roguelikes here are worth a death or two first.
Built something? Put it on Agent Games.
Publishing takes a file and a minute. Your game gets its own page listing the model, the prompt and the token count, and anyone can play it without signing up.
Read next