Live data from Hacker News

Technical Breakdown of a new NES game written in Lisp

dustmop.io

31–40 of 71 posts

Re: Technical Breakdown of a new NES game written in Lisp

#31
post #16

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 to cross-compile the game engine into javascript, which I ca…

That sounds like a great approach. I often wondered how to get Scheme code running in Unity.

Can you fire up a REPL while the game is running? That would be huge.

Many years ago I experimented with the idea of creating games for iOS in Chicken Scheme. Because I'm exceedingly lazy and did not want to bother with cross-compilation – unless it became a serious project – I just told Chicken's compiler to stop at the C code generation step. The Makefile would then copy the generated (and quite unreadable) C code to the XCode project, and then compile the whole thing together with any Objective-C code I had.

With very little setup code, you could embed arbitrarily large Chicken programs. And given Chicken's excellent C interop, the Objective-C code could easily call Scheme functions (the reverse is not as trivial, so I just wrote wrappers for the handful of Objective-C functions I needed – which weren't many in a game).

The only piece missing at the time was that Chicken did not have OpenGL-ES bindings. I solved that by copying code from Gambit Scheme, and using a couple of very trivial macros to make it compatible.

That worked beautifully. I could even start a remote REPL and instantly change running code over the network, no matter if it was running in a real device or the simulator. And I mean instantly: the next rendered frame would already have the changes.

Then I hit my roadblock: I had successfully solved the technical problem, so I lost interest in pursuing the game, which was ostensibly the reason why I had embarked on this detour to begin with. Oh well.

Re: Technical Breakdown of a new NES game written in Lisp

#32

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 (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)

I don't think they finished the NES version?

Re: Technical Breakdown of a new NES game written in Lisp

#33

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?

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).

Re: Technical Breakdown of a new NES game written in Lisp

#34

Earlier quoted context omitted.

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.

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…

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

Re: Technical Breakdown of a new NES game written in Lisp

#35

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…

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...

Hard reasons.

Forth implementations on the 6502 uses a stack and require more RAM than Co2 which uses a compiled stack.

I feel like Co2 would compile to faster code but of course I haven't benchmarked this. The reason I feel this is so is that I way I understand compiled forth is that the 'words' are still threaded so you don't escape the interpreter overhead.

Soft reasons.

Co2 takes away the chore of parsing, in Forth you are the parser. It's simpler but more error prone and harder to read (subjectively).

Forth is postfix notation which for a lot of people is challenging.

Re: Technical Breakdown of a new NES game written in Lisp

#36

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…

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...

Not having to think about a stack all the time.

Re: Technical Breakdown of a new NES game written in Lisp

#37
post #30

Earlier quoted context omitted.

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...

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…

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

Re: Technical Breakdown of a new NES game written in Lisp

#38
post #30

Earlier quoted context omitted.

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…

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

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

* "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...

Re: Technical Breakdown of a new NES game written in Lisp

#40
post #35

Earlier quoted context omitted.

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...

Hard reasons. Forth implementations on the 6502 uses a stack and require more RAM than Co2 which uses a compiled stack. I feel like Co2 would compile to faster code but of course I haven't benchmarked this. The reason I feel this is so is that I way I understand compiled forth is that the 'words' are still threaded so you don't escape the interpreter overhead. Soft reasons. Co2 takes away the chore of parsing, in For…

> Forth implementations on the 6502 uses a stack and require more RAM than Co2 which uses a compiled stack.

I don't know what you mean when you say this. Could you elaborate? Any function call is going to require putting the arguments somewhere.

> The reason I feel this is so is that I way I understand compiled forth is that the 'words' are still threaded so you don't escape the interpreter overhead.

Indirect/direct threading at runtime isn't required; it's up to the compiler. There are plenty of Forth cross-compilers (e.g. MPE's) that compile native code (and call it "subroutine threaded"). They don't have an explicit (inner) interpreter... they just use standard CPU opcodes to call/return.

Post reply on HN