
Technical Breakdown of a new NES game written in Lisp - dustmop
http://www.dustmop.io/blog/2019/09/10/what-remains-technical-breakdown/
======
reikonomusha
This was an incredibly enjoyable read. A lesson to take away is that many of
the ideas of Lisp can be taken advantage of without reeling in the entirety of
an existing stack.

Writing a Lisp parser is easy. Walking Lisp code is easy. Serializing Lisp
code is easy. Adding a new primitive is easy. Adding very basic syntax
transforming macros is easy. All of these are virtually trivial if your host
language is a Lisp, as was the case with Co2.

What they didn’t do is what many people might think are table stakes with
Lisp: writing a garbage collector, writing a runtime, supporting lambdas, and
so on. Those are unreasonable asks for 2K RAM on a 6502. I wouldn’t say they
wrote a bonafide Lisp, but they made use of many ideas of Lisp successfully to
write a game that is very surprisingly readable while not being too abstract
over assembly.

Since Lisp began in the 1950s, it has always needed to stay tied to the low
level. Even today, with SBCL or CCL, you can write your own assembly code. One
relevant thing to the article is Baker’s COMFY 6502 language for writing
assembly code [0]. A few implementations can be found on GitHub.

[0]
[http://home.pipeline.com/~hbaker1/sigplannotices/sigcol04.pd...](http://home.pipeline.com/~hbaker1/sigplannotices/sigcol04.pdf)

~~~
zozbot234
If you aren't going to have a GC, "rich" runtime or lambda support, what does
LISP really bring you over FORTH? And implementations of the latter on 6502
have been commonplace since the 1980s...

~~~
neilv
I understand that Forth is powerful and elegant, and one of the last languages
I'd want to take on in a fight when wielded by a master, so let me pretend you
were asking about a stripped-down Lisp compared to, say, Pascal, instead:

* The simple syntax of stripped-down Lisp is very amenable to application-specific or domain-specific macros. This turns out to be a convenient way to do things that often the language or compiler alone can't do as well, if you used only functions, data, and conventions.

* That the syntax is so simple, and can also be first-class data that is displayed from the programming environment like it looks in syntax, makes it especially nice for things like intermediate representations that are refined incrementally. For example, you can show a translation series of steps that go from syntax parse, to resolutions, to phases of optimizations, to high-level assembler, to a very low-level target code (still represented with parentheses and "opcodes"), from which you write bytes. This can also be convenient.

In this particular case, they're using Racket (an implementation of a dialect
of Scheme) to implement a compiler for a Lisp dialect they invented. Using
Racket gives them both a nice general-purpose language for implementing their
compiler, and happens to already have a lot of tools for parsing their own
stripped-down Lisp and manipulating it.

IIUC, Naughty Dog used Racket for a similar purpose: to implement their own
Lisp. For a narrative DSL for some AAA titles.

~~~
reikonomusha
Naughty Dog used Allegro Common Lisp by (still alive and well) Franz Inc.

~~~
neilv
Neat, I didn't know Naughty Dog also used Allegro CL, in addition to Racket:

* "RacketCon 2013: Dan Liebgold - Racket on the Playstation 3? It's Not What you Think!" [https://www.youtube.com/watch?v=oSmqbnhHp1c](https://www.youtube.com/watch?v=oSmqbnhHp1c)

* "Functional mzScheme DSLs in Game Development" (MzScheme was the name of the main PLT Scheme interpreter that was renamed Racket) [http://cufp.org/conference/sessions/2011/functional-mzscheme...](http://cufp.org/conference/sessions/2011/functional-mzscheme-dsls-game-development)

------
emptybits
I loved Lisp upon my first exposure in the late 80s in university. Then I
"had" to professionally abandon Lisp leanings because I entered the game
industry which required, at the time, a commitment to 8-bit assembly code. No
problem. Lisp remained a hobby. Fast forward! Unexpected intersect! I love
this so much and thank you for the great writeup!

There's a podcast for present day NES developers called The Assembly Line.[1]
I'm sure they'd enjoy this story and talking to you.

[1]
[https://soundcloud.com/nesassemblyline](https://soundcloud.com/nesassemblyline)

------
nudpiedo
This is a complete and absolute hack and I love it. When reading the README
file of their github it is possible to see how "impure" pragmatic decisions
were made like for loops and not supporting proper recursion. I wish there
would be more projects like this one porting lisp runtimes to more and more
hardware.

In the other hand the racket lisp behind the scenes _generates_ the assembly
code based on some of the scheme primitives rather than porting its whole
Racket runtime there, which in spite of not being the same as running a lisp
in the NES hardware is still impressive.

~~~
TurboHaskal
Most Lispers and some Schemers are quite pragmatic in that regard. With the
former favouring OOP and looping over recursion and the latter using
imperative code when it matters.

With developer mindshare flocking to the Haskell view of FP, for the Lisp
family, only the Clojure users seem to still hold purity in high regard.

~~~
agentultra
Purity isn't in contrast with pragmatism; what Haskellers refer to as _purity_
is referential transparency.

You can still do this kind of work in Haskell as well. It is a great
imperative language.

Though as someone who has written assembler compilers in Common Lisp... it's
felt relatively easy to do in CL. I've only heard people talk about writing
control software for drones from Haskell. I have no idea how one would do that
in practice though.

~~~
kryptiskt
Here is a blog about assembling 6502 code in Haskell:
[http://www.wall.org/~lewis/2013/10/15/asm-
monad.html](http://www.wall.org/~lewis/2013/10/15/asm-monad.html)

------
drcode
I'm struggling with the same problem: I'm a Lisp programmer who's writing a
commercial game, in my case a Unity engine game, which requires C#.

I've opted for a less elegant, but technically simple strategy: I'm writing
all the build tools/content tools in Clojurescript, and then writing only the
core game engine in raw C#.

Next, I'm using [http://bridge.net](http://bridge.net) to cross-compile the
game engine into javascript, which I can then link to from clojurescript so
that all unit tests and 90% of all QA testing can be done via clojurescript
tooling, without any C# in sight.

This allows me to deploy a commercial game in "native" C# without any
performance penalty, but with as few lines of C# as humanly possible.

~~~
mikepurvis
This seems really complicated, relative to using the Clojure CLR port. Is it
just not mature enough, or were there other advantages to going via JS?

~~~
drcode
Using Clojure CLR would make the build process simple, at the cost of some
complexity and likely a performance penalty in the deployed application.

On the other hand, my strategy makes the final deployed application dead
simple and fast, but leads to a build process that's complex and messy.

It seems objectively true that the latter approach is going to be less risky,
because if the final deployed game doesn't work well, the whole project is
f###ed.

The only way to mitigate this risk and still stay with 100% Lisp is to create
your own Lisp compiler, which is exactly what OP did... but that way lies
insanity :)

------
j_m_b
One of the advantages of lisp is REPL-driven development. I imagine you can't
just edit a fn, eval it and then see the changes immediately. What is the
workflow like when creating a NES game using co2?

~~~
bitwize
I dunno about Co2, but the last time I heard about a project like this --
Naughty Dog's GOAL -- they _absolutely_ could compile GOAL on the fly on the
development PC and send it immediately to run on the PS2 dev kit inside an
already running game. REPL-driven development directly on a game console. It
was awesome.

------
jasperpilgrim
This is impressive. I appreciate you documenting the development of it and
giving an overview of what's going on inside. I wish there were more blog
posts like this. Have you reached out to the Racket community about the game
and co2? Also, would you say this Lisp is geared more toward people who
already know 6502 assembly, and not toward people who just want to write a NES
game in a Lisp?

~~~
djmips
With only looking through the article and being a 6502/NES programmer myself,
you can't escape having to know 6502 and the NES hardware to write a NES game.
This Lisp is cool and it will certainly smooth the process and is a good fit
for an Adventure game and other parts of NES game development where you aren't
counting cycles (like UI).

~~~
jasperpilgrim
Good to know. Assuming it's true that 6502 asm is not too difficult to learn,
co2 looks like it would be fun to work with on a simple game. Really neat
project.

~~~
djmips
6502 is easy to learn. Have some fun here
[https://skilldrick.github.io/easy6502/](https://skilldrick.github.io/easy6502/)

For me the challenge with the NES itself was getting a good tutorial and then
with making a game, getting your art from your mind into the tiles and sprites
and in your project. Your art 'pipeline'. Once that's established it becomes
easier.

------
anon9001
If you like this, you should also check out the work around Retro City
Rampage. RCR is a GTA1 clone for multiple platforms from a few years back, but
the developer also made a real NES ROM of it. Here's a great talk about that
process:
[https://www.youtube.com/watch?v=Hvx4xXhZMrU](https://www.youtube.com/watch?v=Hvx4xXhZMrU)

(I'm not related to the project, but it's one of the few games I've 100%
completed because it was just so good)

~~~
djmips
I don't think they finished the NES version?

~~~
anon9001
Sort of, it's in the game as an emulated ROM:
[https://www.youtube.com/watch?v=ZffFxLyD4Ig](https://www.youtube.com/watch?v=ZffFxLyD4Ig)

~~~
djmips
Prototype version, as in unfinished, too bad. But it's cool it's an Easter
Egg.

------
fouc
Looking at the code examples of the entity system in this article made me
wonder what it'd be like to code a MUD in this language or in lisp generally.

Does anyone know if there are any MUDs out there coded in lisp? I didn't find
any good results in google aside from the MPI lisp-like language built on top
of FurryMUCK.

~~~
320x200
A bit tangential, in relation to MUD-like games and Lisp. The original author
of co2 (that is to say before it was developed further by OP), has worked on a
multi-user interactive fiction with some of the other persons who worked on
this NES game. For that he used mzscheme to run a server side virtual world of
bots/NPC interacting with the players via a browser/javascript client.

You can find some information there:

[https://archive.bleu255.com/nakedonpluto/about/](https://archive.bleu255.com/nakedonpluto/about/)

[https://gitorious.org/naked-on-pluto/game-
server](https://gitorious.org/naked-on-pluto/game-server) (cert expired)

[https://gitorious.org/naked-on-pluto/game-
client](https://gitorious.org/naked-on-pluto/game-client) (cert expired)

------
CoolGuySteve
I’d like to hear more about the compiled stack.

In extremely latency sensitive applications, the mix of stack and instruction
cacheline faults can cause significant overhead.

~~~
zozbot234
No cache lines on a 6502, though!

~~~
CoolGuySteve
I'm talking about modern architectures

------
gautamcgoel
Really cool article. I appreciated the "engineering on the battlefield" vibe.
I'm curious why they first went with Lisp.

------
seisvelas
They made their language using Racket! Great to see Racket style Language
Oriented Programming being used for something so cool

------
edmoffo
Lisp is and was the best programming language. I moved to Java many years ago
and still regret :)

------
soulofmischief
Cool! Thanks for sharing! Just picked up the game, it looks awesome.

------
ngcc_hk
Very impressive and readable. Congratulations!!!

------
ninkendo
I know it's off-topic but I appreciate so much when somebody hosts their own
blog rather than using Medium or some nag-ware hosting service.

I didn't get any pop-up "pardon[ing] the interruption" or asking me to join a
mailing list, or anything! To think this used to be the normal way of doing
things on the web.

~~~
scrollaway
The other side of that coin is that on mobile the article is painful to read
and the layout is horrible.

For what it's worth I hate medium as well. But I would recommend ghost.org if
you want to go with self hosting.

~~~
savolai
Also choosing a good wordpress theme helps a lot. :)

~~~
ihuman
The post is using [0] this theme, which hasn't been updated in over 6 years.

[0]
[https://wordpress.org/themes/duster/](https://wordpress.org/themes/duster/)

