
Show HN: Advenjure – Interactive fiction on the terminal and in the browser - facundo_olano
https://facundoolano.github.io/advenjure
======
m48
A quick explanation of what this is, because it took me a bit to figure it
out: it appears to be an interactive fiction engine written in Clojure. The
linked example game is running through ClojureScript in the browser, but the
engine also works in the terminal.

Here's a quick link to the main code file defining the rooms and actions for
the example game: [https://github.com/facundoolano/advenjure-
example/blob/maste...](https://github.com/facundoolano/advenjure-
example/blob/master/src/example/rooms.cljc). I doubt I'm the only one that
likes looking at this type of example first when looking at an interactive
fiction engine, and it may help some people confused by the game.

The history of interactive fiction and Lisp is surprisingly intertwined. To
the best of my knowledge, all of the original Infocom games were written in
ZIL [0], an idiosyncratic Lisp variant that was meant to be a more portable
version of the programming language used to write the original mainframe Zork,
MDL—which was apparently designed by some of the same people who worked on
Scheme and Common Lisp [1].

There appears to be an active but still incomplete open source compiler for
ZIL written in C# [2], and a few Common Lisp experiments, but not many mature
projects combining interactive fiction and Lisp.

I hope projects like this one catch on more. I've had trouble grasping other
interactive fiction engines, which I often feel are trying to please
programmers and writers but hitting an awkward space in between. Lisp's "code
is data" idea seems like it could be a more graceful way of hitting that
balance.

[0] [http://www.ifwiki.org/index.php/ZIL](http://www.ifwiki.org/index.php/ZIL)

[1]
[https://en.wikipedia.org/wiki/MDL_(programming_language)](https://en.wikipedia.org/wiki/MDL_\(programming_language\))

[2]
[https://bitbucket.org/jmcgrew/zilf/overview](https://bitbucket.org/jmcgrew/zilf/overview)

~~~
WorldMaker
I think that's an astute observation that the history of IF languages seems to
be trying to find a balance between easy for programmers on one side and easy
for writes on the other, and that Lisp is certainly as intertwined in the
early history of IF as it is because it naturally hits an interesting place in
that balance given the S-Expression "code is data"/"data is code" simplicity.

I still find Inform 7 a deeply fascinating example simply for trying a "Prose
is code" approach that tries to favor writers first, somewhat at the expense
of sometimes making programmers frustrated.

------
PhasmaFelis

      There was a small table there. The small table contained:
        A bottle. The bottle contained a amount of water
    
      @Bedroom [0] > get all
      I didn't see that.
     
      @Bedroom [1] > get bottle
      I couldn't take that.
     
      @Bedroom [2] > take bottle
      I couldn't take that.
     
      @Bedroom [3] > drink water
      I didn't know how to do that.
    
      @Bedroom [4] > open bottle
      I couldn't open that.
    

I just wanted a drink. :(

~~~
cyberferret
My experience too. Couldn't help but be disappointed in the parsing engine of
this game. But I guess I am a little spoilt, having grown up on most of the
Infocom adventure games...

~~~
facundo_olano
I think in this particular case, the game example script is more to blame than
the parser. I don't even remember putting that bottle there, but I should've
marked it to be take-able and drink-able.

I made it so it's fairly simple to extend the supported verbs (you can even
add your own verbs as a lib user, without modifying the lib code). It's just
that it hadn't been used much before today, so a lot of somewhat obvious verbs
are probably missing.

(full disclosure: I had little experience with infocom games myself, I'm more
used to graphic adventures, but this was a far more interesting programming
project to learn Clojure).

~~~
cyberferret
One of the 'shortcuts' in the Infocom Z-parser based games when I entered a
room that was rich in 'stuff' was to issue a 'take all' command. That would
immediately give me an idea of what was an object that could be manipulated vs
what wasn't. e.g.

> take all

bottle: taken

table: that's nailed to the floor

bed: that is too heavy to take

wallet: taken

rug: you can't take that!

This (a) automatically lets me pick up anything that I can (and drop the ones
that I don't immediately need), but (b) it also tells me that there is no
point in trying anything with the table & rug, but the BED might still be an
actionable item because of the response. Perhaps I could 'move' instead of
'take' the bed?

~~~
facundo_olano
Good, I didn't know about the "take all" feature, taking note.

In advenjure you can get a similar effect with the autocomplete. If you enter
"take " and hit tab you will get suggestions for all the items available in
the room.

Either case still requires the game scripter to try to guess what the players
will attempt and write specific responses for that, otherwise they'll get the
frustrating generic responses.

~~~
PhasmaFelis
> _Good, I didn 't know about the "take all" feature, taking note._

If you're serious about making a viable interactive fiction engine, you should
get really familiar with the Infocom games, the Z-machine engine and its
various ports, and the Inform compiler that a latter-day fan made for the
Z-machine (and the fan-made games that use it). That's the standard by which
your work will be judged.

If you're just fooling around, then do whatever you like. :) Some of your
ideas are pretty neat, like tab completion.

------
qwertyuiop924
Really neat. I actually wrote something similar but far more primitive in
Scheme (worse CL, primitive parser, minimal interactivity, and so on). I
wouldn't reccomend either system for serious IF, though. Tads, Inform and the
rest are far more capable.

------
gravypod
I think this implementation isn't tackling the root of the problem here.
Implementing this as a state machine that can load arbitrary node, status, and
links would better model the problem.

Good work though on keeping this very simple.

~~~
kmill
I'm curious what you've identified as the root of the problem for making these
sorts of parser-based games. It sounds to me that you'd rather it be a choose-
your-own-adventure game, which your suggestion would make sense for, but
parser-based games tend to model a virtual world of objects which your
character interacts with. OO-style ontology tends to work somewhat better than
state machines here (though I think rule-based dispatch has proved more
successful in Inform 7, or in a Python-based text adventure engine I once
made. Some complications are in expressing indirect objects for verbs and in
rules which only apply to certain instances of objects in certain situations
-- there is always a game which will complicate your simple world model).

Also, what is the harm in making it so that the data for the game is Clojure
source rather than some other format? "Code is data" allows for data being
code. It saves having to make a state machine interpreter which you have to
extend with exceptions for particular games which will eventually become a
poorly implemented lisp in Clojure in the JVM.

~~~
gravypod
>I'm curious what you've identified as the root of the problem for making
these sorts of parser-based games

It's not a parser based game. It's a _state_ based game. When you have to
track complex interactions with massive sets of states, nodes, and
interconnections you are writing a state machine.

To truely understand that this is the case you have to see an example. As such
I recommend looking at the Fallout 1/2/3/New Vegas quest flow charts that have
been generated. Here are a few:

Example of describing story with a state machine:
[http://i.imgur.com/mAENC.jpg](http://i.imgur.com/mAENC.jpg)

Example of describing spacial directions with state machine:
[http://i.imgur.com/qVnEH.png](http://i.imgur.com/qVnEH.png)

A Fallout NV mod as another example of story-as-state machine:
[http://www.thumbsticks.com/wp-
content/uploads/2015/02/Fallou...](http://www.thumbsticks.com/wp-
content/uploads/2015/02/Fallout-New-Vegas-flowchart.png)

These should all demonstrate what I mean. All that would need to happen is for
the state machine to interface with a player "inventory" and check the states
of that before actions are completed. It turns most of the game logic into
walking a tree and checking conditions.

> but parser-based games tend to model a virtual world of objects which your
> character interacts with.

That's not what I'm talking about. I'm talking about modeling the game as a
set of actions that can be taken but are blocked by sets of preconditions.

> Some complications are in expressing indirect objects for verbs and in rules
> which only apply to certain instances of objects in certain situations --
> there is always a game which will complicate your simple world model

I'm not saying to create the human interface using a state machine. I'm saying
to model the story as a state machine.

> Also, what is the harm in making it so that the data for the game is Clojure
> source rather than some other format? "Code is data" allows for data being
> code. It saves having to make a state machine interpreter which you have to
> extend with exceptions for particular games which will eventually become a
> poorly implemented lisp in Clojure in the JVM.

There are many reasons to do this. For one, it allows people who aren't
programmers to create stories for your engine. To take a look at the
interesting side effects of this I'd recommend watching this video:
[https://www.youtube.com/watch?v=FnFKEWCzVCo](https://www.youtube.com/watch?v=FnFKEWCzVCo)

It's again from one of the people involved with the fallout series but he goes
into how the scripting side of things enabled story writers to create an
entirely different experience. When you give non-programmers a safety-scissors
equivalent of a programming environment they can create cool things without
bothering you.

Another great side effect is that you've abstracted your problem. You could
pull your state machine code out of your game, turn it into a module and
interface with it there. Any other code that you need to use a state machine
will be able to now interface with it.

This is, I'd say, the most fundamental idea possible in computer science. The
idea of abstracting concepts to make the project being created simpler.

Finally, there is the problem of reusability. This game is pretty much locked
to it's engine. It can't be reimplemented or updated by people who don't have
knowledge of the code base.

On a side note this cannot be configured to run a story safely if it is
clojure code that is executed.

Basically, you're removing reusability of this engine, you're not creating a
solution to the root problem, and you're making it so the user cannot play
other stories in this engine: it's entirely unsafe to redistribute alternative
stories since the stories are executed at the same privileged level as the
rest of the game.

~~~
kmill
By "parser-based" I was referring to terminology from the interactive fiction
community. A parser-based game is one whose primary mode of interaction is a
parser reading user commands.

I agree that there is an underlying state machine, but that's true of any
program. I was saying that modeling the state transitions for these sorts of
games tends to work out better for authors when using an OO-style model, since
the game is simulating a player object interacting with other game objects.
Making a system to help organize running certain logic on certain conditions
is exactly one of the goals of blah-orientation, where "blah" is object,
functional, state machine, or whatever.

I've seen state transition diagrams like the ones you mention for the design
of interactive fiction, but only for high-level design. The interactions
between objects in these games tends to be too complicated to completely
describe that way. For instance, does the player character see anything in a
room if they put their only light source inside an opaque closable container?
What if the player is inside that container? Puzzles in IF quite often use
emergent behaviors of simulated environments, and there are large standard
libraries for them in, for instance, Inform 7 or TADS.

Ok, so what I'm gathering is that you have identified the root problem of
these sorts of games as being organizing the story as a state machine, making
it so that non-engine authors are able to make trusted content, and making it
so the engine can be reused.

But I think an adventure game engine is more along the lines of the underlying
game engine for Fallout 4 than the code inside Fallout 4 which helps drive the
story. For instance, where is the crafting system implemented? Is it really
thought of as a giant state transition diagram? I find that difficult to
believe.

Again, I believe you are thinking choose-your-own-adventure rather than this
genre of parser-based games. CYOA games tend to just disallow disallowed
actions, but parser-based games with a modeled world tend to attempt
reasonable responses to any (reasonable) action. Whether you agree games
should support these sorts of interactions is a different question from
whether these games should be implemented as state transition diagrams.

And sure, with this Clojure-based engine arbitrary code can be executed. There
are a couple differences between this and Fallout 4. The first is that the
cost of making interactive fiction is much less than a game like that, so one
or two people can easily produce one, reducing the need to abstract game logic
to a separate language. The second is that the engine can be compiled into the
game for distribution, just like most other games.

Also, it's conceivable that the game could run in a locked-down virtual
machine. The old Infocom games ran in a bytecode interpreter that their in-
house Lisp-like language targeted. In the modern day, people still distribute
interactive fiction in the same (but somewhat modernized) format.

> This is, I'd say, the most fundamental idea possible in computer science.
> The idea of abstracting concepts to make the project being created simpler.

I agree that abstraction is powerful and can make things simpler. But it also
requires the correct abstraction, and I'm just not convinced that modeling
interactive fiction games using state machine diagrams is actually simpler. I
found the discussion of ontology problems in the Inform 7 white paper
interesting:
[http://inform7.com/learn/documents/WhitePaper.pdf](http://inform7.com/learn/documents/WhitePaper.pdf)

------
kukx
Side note: if you are hungry for more interactive fiction, I highly recommend
"Lost Pig" by Grunk[0]:
[http://iplayif.com/?story=http%3A//mirror.ifarchive.org/if-a...](http://iplayif.com/?story=http%3A//mirror.ifarchive.org/if-
archive/games/zcode/LostPig.zblorb)

[0] [http://grunk.org/lostpig/](http://grunk.org/lostpig/)

------
nathell
Graham Nelson's "The Inform Designer's Manual, 4th Edition" [DM4] is an
essential read for those wishing to implement an interactive fiction authoring
system. Especially the chapters on Inform's world model and its flexibility.

[DM4]: [http://inform-fiction.org/manual/download_dm4.html](http://inform-
fiction.org/manual/download_dm4.html)

------
helloworld
Does anyone else remember playing Zork?

[http://mentalfloss.com/article/29885/eaten-grue-brief-
histor...](http://mentalfloss.com/article/29885/eaten-grue-brief-history-zork)

~~~
kmill
Yes, but not anytime near it came out (it was probably around 2000 C.E. for
me).

Earlier this year I was playing around with recompilation (reading the
Emscripten whitepaper) of z-code. The Infocom games used a virtual machine to
get their games onto lots of contemporary computers, and also to reasonably
implement a virtual memory system to fit the games into the small memory of
those computers.

Anyway, it isn't too hard to make a z-machine interpreter (at least version 5
of z-code), so I made one which recompiles the code into javascript:
[http://tmp.esoteri.casa/zmach/zmach.html](http://tmp.esoteri.casa/zmach/zmach.html)

The way z-code works makes it so you can't tell what is code and what is data
ahead of time, so it decompiles as you play. "Dump routines" gives you the the
code so far (as javascript). Part of the fun is making code which can pause
execution to wait for player input. (Turns out the technique is already in
some paper from some scheme workshop.)

[https://github.com/kmill/zmach](https://github.com/kmill/zmach) is the
project.

------
dmitripopov
Damn these text adventures are addictive...

