edges2cats

The pix2pix image-to-image translation library has been having a booming time recently. For example, you can use it to draw cats.

Christopher Hesse also used it to make a building generator and a shoe generator, but we all know that you’re here for the cats. Lovecraftian cats, in some cases.

With a dataset of 2000 cat photos and automatic edge detection, the edges2cats generator tries to match the lines you input with the closest cat features it can detect. The edge detection missed some features (one of the perils of using imperfect automatic processes to create your data) so the cats sometimes come out a bit wrong, or with too many eyes. But they’re often recognizably cat-like-things.

You can play with the generators yourself: http://affinelayer.com/pixsrv/index.html




7DRL 2017

The 2017 Seven Day Roguelike Week is in full swing. There’s already dozens and dozens of roguelikes in development, some of which you can see previews of on the Twitter hashtag. There seem to be a lot of non-ASCII roguelikes this year, but that may just be the screenshot bias.

The 7 Day Roguelike Challenge started in 2005, partially in reaction to the big, grandiose Usenet-era roguelikes and cloud-in-the-sky projects that were dominating the discussion on r.g.r.d. Since then, there have been hundreds and hundreds of new roguelikes, with more added every year.

7DRL exemplifies something I like about game jams: demonstrating that you can build a small, complete game, making the first steps of game development achievable for a wider audience. Even if you end up taking a little longer on your first project, it still represents something achievable.

http://7drl.org/




NetHack Level Generation, Part 3

We’re back in makelevel(), at line 666. The rooms are placed, but they’re empty.

The one thing that every level needs are the stairs that will connect it to the levels above and below it. Unlike some other roguelikes with many stairs between levels, NetHack levels always have exactly one up stair, and every level except the bottom one also has one down stair. Plus, there is the possibility of a second down stair to one of the special branches of the dungeon.

To create the stairs, first pick a random room. If this isn’t the bottom level, place the down stair at a random location in this room. Now, check to see if there is more than one room. NetHack prefers to place the stairs in different rooms, so if there are at least two rooms, it picks a new random room. This time, instead of picking from all of the rooms, it picks from any room except the last one. This is in case it randomly picks the same room that the down stair is already in, in which case it picks the room with the next highest number.

Whichever room it has selected, it places the up stairs in a random, unoccupied location within that room, by randomly generating coordinates in a while loop until it finds one that returns false for occupied(). At this point, “occupied” mostly means “the down stairs are in this tile”. (This is terribly inefficient, but seldom matters.)

Then it checks to see if this level has a connection to a dungeon branch. This is where room_threshold finally gets set, with the ternary operator. If there is a branch, the threshold is 4; otherwise it is 3.

(If this is the special Rogue level, there’s a goto command here, to skip over this next bit. I told you this code was gnarly.)

The rooms are now connected with corridors via makecorridors().

First, it loops through the array of rooms, trying to join each room to the next one in the sequence. After each join, there’s a 2% chance that it’ll stop and go to the second step.

Second, it loops through the list again, this time trying to join each room to the room two steps down the array.

Third, it goes through the list of rooms, trying to join each room to every other room, but stopping once it runs out of rooms that aren’t the current room (e.g. if there’s only one room).

Finally, if there are more than two rooms, it picks a random number (based on the number of rooms), adds 4 to it, and then counts down, each loop attempting to link two random rooms. To keep the randomly selected rooms from being the same, it uses the same trick as with the stairs: a is random(number of rooms) and b is random(number of rooms minus two). If b is equal to or greater than a, add two to b.

As you can see, it attempts to add connections between nearly every room, so what is important here is the order the joins are attempted; join() tries to find places to put doors and then tries to dig corridors between them. It doesn’t always succeed, which the algorithm takes advantage of. Enough corridors are placed to result in NetHack’s characteristic look of rooms suspended in a sea of tunnels.

Once the corridors are placed, makelevel() calls make_niches()  to add closets  to the level, which are 1-square corridors-rooms that will either be connected to a room with a door (often a secret door) or which can only be reached by digging or teleportation.

For the number of niches, it picks a number between 0 and the number of rooms bitshifted to the right plus 1: rnd((nroom>>1) + 1). It also checks the depth: between level 5 and level 25 (noninclusive) there’s a chance for a trap door. And if the depth is greater than 15 and it’s a no-teleport level, there won’t be a teleport-trap niche.

Niche generation is handled by makeniche().

As long as the level hasn’t already exceeded DOORMAX, it runs a loop 8 times, picking a random room each time and attempting to place a connected niche. There’s some restrictions on where they’re allowed: only in ordinary rooms, only if there’s space to place it, etc.

If it can place a niche, it checks the requested trap type, and sets up the niche accordingly. Some traps get engravings (trap doors get “Vlad was here”).

Once there have been eight attempts at placing the niche, it finishes and returns, where we resume execution in makelevel().

Next time, we’ll talk about adding special rooms and secret treasure vaults.








Apocalypse Fuel

A generator by Sam Kabo Ashwell, to create factions and setting details for Apocalypse World games.

We’ve talked about many generators for tabletop roleplaying games before, of course. But this one has some unique features of its own.

First off, it’s written in Inform, the natural-language interactive fiction programming language. This makes its source code particularly readable, especially for people who don’t have a lot of experience with more conventional programming syntax.

Secondly, its results are quite literary. Though the tone the Apocalypse World game sets certainly helps, the writing should be commended for making everything flow.

How would you like to visit a place like this?

Scow’s Roadhouse is a Maestro D’s establishment, at the fringes of a hardhold, its status questionable. It mostly provides music, with sports and scene as lube. Its aesthetic: masks, eavesdropping and dancing. Its maestro d’ is Frisky Coco. There’s a constant supply of young fools willing to risk life and limb for glory and riches that come with the Grand Belt, but the setup makes a victory near-impossible. They claim to have invented roller derby, though this is hotly disputed. Their lead raconteur is pregnant and hiding it. Its defenses include an enthusiastic regular guest with far-reaching power and influence; and secrecy and subterfuge.

And I hope you don’t run into these jokers:

the Skunks are nomads, making only temporary camps. They are an army - 100 or more violent bastards. They travel in ex-military humvees. Their best vehicle is the Carrier, a fast and huge pickup, shaped around a massive roll-cage and with unusually high clearance. It occasionally catches on fire for no very clear reason.

They’re adequately armed, and heavily armored in pre-Fall riot gear. They are savage. They mostly care about arrogance - they see themselves as naturally superior. They are under the principled leadership of Lilian Iron. Right now they’re poking around in a burned-out hardhold, but this has interfered with the schemes of the Raccoons.

You can find Apocalypse Fuel at:

http://samkabo.com/ApocalypseFuel/index.html










Evolving Cellular Automata

Another project from Loren Schmidt, this is a rule-generator for cellular automata.

Cellular automata are handy, compact examples of emergent effects. The most well-known example is Conway’s Game of Life, which is a two-state cellular automata with the rules “B3/S23″. Cells are Born if they have three neighbors, and they Survive if they have 2 or 3. Other rules are possible: “B36/S23″, “B36/S125“, and “B4678/S35678“ are a few of the more interesting known rules.

This rule generator creates three-state automata, which opens up even more possibilities. It also uses evolutionary algorithms to create the next generation of rules: click on a pattern and get a set of rules similar to that pattern.

You can also save the rules you like in a numerical format you can use elsewhere, or go back to a saved rule and try evolving down a different path.

http://vacuumflowers.com/cellular_automata/rules.html










Voyageur


Voyageur is a just-released game inspired by both Fallen London and The Annals of the Parrigues. Your spaceship has a drive that only works in one direction: towards the galactic core. At each jump, you visit a new, procedurally generated planet and explore ongoing stories bit by bit.

The narrative structure draws from the quality-and-choice structure inspired by the works of Failbetter Games. Your stats, qualities, and cargo affect the results of your choices. And the small story moments often lead to other story nodes.

The planets use a system influenced by Parrigues, with an original aesthetic tarot: Chrysalis, Hammer, Star, Dome, and Ladder. I’m intrigued by the result, though I don’t feel like I’ve played enough yet to completely interpret all of their effects.

http://voyageur.space/






Black Closet

Mystery stories are difficult to make interactive. There’s no shortage of attempts: one of Infocom’s early games was a whodunnit titled Deadline, for example. But despite the attraction of marrying the puzzle-solving of detective work with the puzzle solving of gameplay, most attempts have been ill-fitting, with the occasional success.

I chalk Black Closet up as one of the successes, partially because it knows what it is and doesn’t try to be a mystery novel. It’s a visual novel, by the same designer as Long Live the Queen. But where Long Live The Queen is a single elaborate puzzlebox, Black Closet is a puzzle machine.

That’s because the cases are–you guessed it–procedural. You’ll never know which cases you’ll get this game, so rather than memorizing an optimal path, you get to balance what you know against what

The second move that I think makes it work is that it doesn’t try to be a Sherlock Holmes simulator. Many other detective games trip themselves up here. While the detective solving the case looks similar to a videogame’s content gate, where the player proves they can solve the puzzle, it takes a great deal of skill to pull that off. Making that work procedurally is trickier still.

While there are a few larger puzzles where you should probably figure out the truth, for the bulk of the cases in Black Closet your goal isn’t to lay out the correct solution to each case. Instead, as the president of the Absurdly Powerful Student Council, you merely have to resolve the situation in a way that reflects well on the school. Sometimes saving your resources is more optimal than uncovering the sordid truth.

By having a framing that works better for the interactive, changeable nature of the procedural mystery generator, Black Closet is one of the few successful entries in the videogame mystery oeuvre.

http://store.steampowered.com/app/400580/

http://www.hanakogames.com/closet.shtml




Nethack Level Generation, Part 2: Making Rooms

NetHack’s maps are based around rooms and corridors. In gameplay, rooms are open areas that are usually lit, which makes them visible at a distance, while corridors are the connecting paths that are dark, which means that by default you can only see monsters that are one tile away. This creates a tradeoff between the bottlenecked corridors that are prone to ambushes and the more open spaces where you can see threats before they attack you. Doors are placed where corridors connect to the rooms, and have a chance to be secret doors. More than one player has gone down the stairs only to find themselves in a room that has no visible exits.

To create the rooms, makelevel() starts by calling two functions: makerooms() and sort_rooms().

The core of makerooms() is a while loop that runs until it reaches the maximum number of rooms (which is defined as 40) [] or runs out of places to put new rooms.

Each time it goes through the loop, it first check to see if it can try to place a vault. If it isn’t placing a vault, instead it creates an ordinary room with -1 for all of the optional arguments. If it fails to place this room, it stops trying to place any more rooms, returning out of makerooms().

To place a vault requires the number of rooms to be at least one-sixth of the maximum (with the default max of 40 and C’s truncation towards zero, this is usually 6). It also requires that no vault has previously been tried, plus a 50% random chance. It then calls create_vault(), which is a preprocessor macro for create_room() with a different set of arguments: (-1, -1, 2, 2, -1, -1, VAULT, TRUE). This creates a vault with a fixed size of 2 and guaranteed to be lit.

Either way, the bulk of the work is done in create_room(). Since this is also used by the special level system, it has some flexibility for specifying more kinds of rooms than the basic generator uses. It takes eight arguments: the x position, the y position, the width, the height, xal, yal, the room type, and whether it is lit.

The first step in creating a room is to check the requested light value; if it is -1, the lighting state is randomly set based on how deep the level is; once the player reaches level 10, there’s an increasing chance that the room will be dark. (There’s also a 1-in-77 chance that it will be lit, no matter the result of the first random check.)

Similarly, if any of the other arguments are -1, they will be generated randomly.

Way back in clear_level_structures(), the game built an array of rectangles in the level. This started as one large rectangle that covers the entire level. In create_room() it now grabs a random rectangle from this array. If this is our first room, there’s only one rectangle to grab.

Rectangles are a struct with four variables: the low x and y coordinates, and the high x and y coordinates. (The terminology seems to date back at least to the early days of Hack, if not earlier.)

It picks some random coordinates based on the rectangle it grabbed:

image

The result of all of this is a set of coordinates (absolute upper left corner x position, room x width, absolute y position, room y height) that define where it wants the room placed. 

image

Using these values, it checks to see if a room will fit in that spot, shrinking it if necessary. If it fails, it starts over. If it fails more than 100 times, it gives up and returns with whatever rooms have already been created.

Assuming that a spot to place a room has been found, it splits the rectangle the new room is going to be in into smaller rectangles. It then adds the room to the array of rooms and writes the walls and floors onto the level map.

The next time through, create_room() will grab one of the smaller rectangles and attempt to put a room in it. If it fails completely, no more empty rectangles can be found, or MAXNROFROOMS is reached, then room creation is over and makerooms() returns.

Once makerooms() is done, sort_rooms() takes the array of rooms and runs a qsort on them, ordering them in the array according to their position on the map from left to right by their low x value.

(Unless you’re compiling on Unix System V or DG/UX, in which case it uses a slightly different qsort call that passes the number of rooms as an unsigned variable. Same behavior, but demonstrates the lengths the code goes through for portability.)

The order of the rooms is going to be important for the corridors connecting the rooms, because it first tries to connect each room to the next one in the array. With a few more complications, which we’ll get to next time in Part 3.







Animals in Random Images

One thing I’ve tried to stress here is combining things in out-of-the-box ways. This is a perfect example: Michael Trott used ImageIdentify to detect animal-like shapes in random noise.

I like the Petroglyph-like results. I also like the concept behind it: take something that is ordinarily meaningless and find meaning by imposing order on it.

Recognition algorithms like this give the computer the ability to look for shapes in clouds, and I think that’s something that has been under-explored. Rather than trying to construct an elaborate set of rules for how to build something, we can now tell the computer what the result should be like, and let it look for almost-right things on its own.

Machine pareidolia can be used creatively.

http://community.wolfram.com/groups/-/m/t/995095









Starflight (1986)

I found my record-album copy of Starflight! (While I was looking for something else, naturally. It was inside the Age of Empires collector’s edition box for some reason.)

Staring development before the release of Elite, Starflight had a rather different philosophy for procedural generation. You see, instead of generating a few trillion galaxies, it generates about 800 planets. Since the game came on two 360K floppy disks, this was rather a challenge.

It uses a fixed seed, so that every game has the same planets. It also remembers your actions, so that minerals you collected would still be gone if you returned.

Where it really stands out from its contemporaries is the story content; with a lot of surprisingly deep interactions. Combined with the on-planet gameplay, which is the part that uses the most procedural generation, this has been incredibly influential influential: the planetary exploration against the backdrop of an epic sandbox story is the prototype for everything from Star Control II to Mass Effect to the Forgotten Beasts in Dwarf Fortress.

These days, you can get a working copy of Starflight on GOG, which is way easier than the rigmarole I had to go through in the ‘90s when I got my second-hand copy. Do back up your save games though.