Hacker News new | past | comments | ask | show | jobs | submit login
A first person shooter in 571 lines of GNU Awk (2016) (github.com/themozg)
514 points by nequo on Jan 19, 2023 | hide | past | favorite | 106 comments



If you're interested in feats of low-size games, I offer you kkrieger, a 3D FPS that fits in 96KB.

https://www.youtube.com/watch?v=8fZBUsn5RYg


Timestamp where the gameplay starts: https://www.youtube.com/watch?v=8fZBUsn5RYg&t=97s

I enjoyed the video. However for me it’s not about the game being small, it’s about implementing anything 3d (or any game for that matter) in awk!


AFAIK this was achieved by heavily using DirectX API and features it contains. When running, it uses around 300 MiB of RAM.


The textures and models are procedurally generated at load time!


Do you expect it to ship its own userspace driver, kernel driver and kernel?


Yeah, if it doesn’t boot it doesn’t count. Everything after reset vector counts as game code.


It wasn't my intention to discredit the kkrieger game, it's nonetheless a great accomplishment.


Of course they are using DX or OpenGL - how else are they supposed to display graphics? )


The very submission you're commenting on is a 3d game without DX or openGL.


just write bytes to the framebuffer?


Did you know that the original Doom game was shipped in 1993 with a VM running Windows 10, just for the DirectX driver? It was the only way to do computer graphics at that time /s


wrong parent?


Was it? I wanted to support mgaunard point, hence the "/s".


Details on how it was made…

https://youtu.be/bD1wWY1YD-M


This is wild. One wonders what would happen if the (perhaps misguided) ideals that shaped that project returned to being in vogue.



Huge but somewhat dull games. No Man's Sky is probably the big name that went that way recently. Or, in its own way, Dwarf Fortress.


I'm not sure I'd lump DF in there at all. It may be procedural generated, but there is a mountain of depth to it.


Pun intended? It was just the two programmers writing that for a long time so I guess the mostly-procedurally-generated content makes sense.


Procedural generation for 3D content is something quite common nowadays - see Substance Designer as an example.

AFAIK the people behind kkrieger tried to push their tool for commercial use at some point but it didn't seem to catch on - but that was years ago.


Nice. My little CLI utility that filters and lists my servers in EC2 is 11MB (GO).


Too small for me.. I'd like to containerize this and add at least 10 more MB, do you have a Dockerfile already?


perhaps an AppImage for easy cross-platform support -- that should add an order of magnitude


A snap. Lol


Tbf, 11mb is all it needs. Add in the graphics library and assorted libc utils that Awk is using and it would be similar.


In the linked video, one of the kkrieger devs (kb) comments and addresses some FAQs


What a delightfully insane project. AWK is under-appreciated IMHO. Read the short manual and you'll discover a world of functionality in a highly orthogonal interface. Pattern Match->Manipulate. An incredibly useful workflow for many tasks.


I wish there was like a "libawk" or something like it for programmatic usage. Its really a neat piece of work that is limited on being only a shell program.

At least, as far as I am aware, there is no programmatic interface


I don't know of a "libawk" C library, but my GoAWK interpreter can also be used as a library (Go) library. See reference docs: https://pkg.go.dev/github.com/benhoyt/goawk/interp

A project that's using it that way is Benthos, a "stream processor" written in Go. Awk is one of the "processors", the components that filter and transform data: https://www.benthos.dev/docs/components/processors/awk


I’ve been really impressed by your ability to share your project in entirely relevant threads recently. Hope that doesn’t sound snarky, because I actually mean it. Awesome project. Keep on.


Hehe, thanks. Yeah, I was on the fence about posting it the last time, thinking "Hmmm, am I promoting my own project too much?" But I've tried to only do it in very relevant contexts or when people ask and it would solve that question.


GoAWK's CSV mode is a great addition to AWK. Have you thought about adding a JSON mode, too, to get an AWK-flavored alternative to jq?

Edit: I see that you have: https://github.com/benhoyt/goawk/issues/152


Yeah, my comment there more or less sums up the thought I've put in so far. AWK doesn't really have nested data structures, but a lot of JSON / JSON lines is fairly flat, so it may work. It shouldn't be too hard ... though as I've noted there, there are a few tricky design issues to work though. Hope to come back to this at some point!


The implementation is so beautiful…thanks for sharing it. This will make me better, I promise.


You can write awk scripts directly if you start a file with a "awk -f" shebang or similar!

I am not totally sure if this is what you mean or not, but it's much nicer than embedding the script into a bash source file.



What would be a use case for this?


This is a somewhat different idea but I'd like to be able to feed structured data (in memory objects) to an (user defined) awk-like script without the need to serialize/parse everything. This could be used for packet filtering, conditional breakpoints, file searching, syscall filtering and intercepting, etc. Basically wherever you need a user defined filter more powerful than regex.

The embedder can decide what variables and functions to provide for each invocation of the script. You could get something like Wireshark filters out of the box:

    ip && port==1234 {print size, time}
Graphviz includes a tool "gvpr" which essentially implements this idea for processing graphs but of course, they end up reimplementing a large part of awk.


At this point I’be caved and just coerce through json via python and jam things through jq for most of my data inspection and sleuthing.


Text processing & extraction


Like a middle ground between regex and embedded Lua?


That's Perl.


I'm sure some element of perl is the middle ground of everything.


Gawk added facilities for writing extensions, but I don't see how to use it as a library. Funny I never thought of it, considering how much I like awk, but using awk instead of Lua as an embedded extension language sounds appealing.


I love Lua but I can also see AWK working like a charm here.


Where would you use this? Most languages have good enough string processing to imitate a lot of what AWK does


An elegant tool for forgetting inbetween all my organic needs for it.


They missed an opportunity to call this "Levenshtein 3D"


I, at least, appreciated this joke =)


Literally dead


I am shocked how readable the code is. Was expecting some Perl-like spaghetti.


You could say that the code isn't really awkward to read.


That's what she sed


Mom! They spilled Reddit all over my hackernews!


Go ask your father.


I always avoided awk because I thought it was just a really weird looking alternative to sed. When it's nicely formatted like this it looks like a perfectly sensible C-like language.


I was hoping for some clever abuse of AWK's patterns & regexes but clean code will also do :)


For that, to start with, you'd need to be able to create a feedback loop of awk's output back to itself as input. For it not to interfere with rendering, it needs to be on a separate file descriptor from stdout.

I found this snippet on stackexchange showing how exactly that is possible on Linux.

> echo hello | gawk '!length{exit(0)} {print; print substr($0,2) >"/dev/fd/3"; fflush()}' 3>/dev/fd/0

This "renders" on stdout then feeds itself more input on /dev/fd/3.


Wow


Awk reads quite javascripty. JavaScript's function syntax was copied from awk.


This was linked from "The State of the Awk (2020)" on the front page earlier today: https://news.ycombinator.com/item?id=34438560

See also "AWK As A Major Systems Programming Language — Revisited" also linked from that article: http://www.skeeve.com/awk-sys-prog.html


I don't know if it was the RNG messing with me or something else, but almost all of the monsters ended up congregating in the elevator room when I played. I was basically just standing in the approach hallway blasting them away one after another.


Related:

Show HN: 3D shooter in your terminal using raycasting in Awk - https://news.ycombinator.com/item?id=10896901 - Jan 2016 (55 comments)


Huh. Did not know Awk could be so similar to Javascript. I certainly haven’t seen it written in this way before, as usually I only see it used for simple one-liners.


Awk is a fun, surprisingly powerful language. Even plain mawk can do a lot, but gawk has debugger support, profiling, namespaces, and even network support. (I wouldn't necessarily go out of my way to use most of those features, but it's possible!)

It's honestly worth giving the mawk and gawk manual a skim just to see what all they can do. I want to read through The AWK Programming Language as well.

https://invisible-island.net/mawk/manpage/mawk.html

https://www.gnu.org/software/gawk/manual/gawk.html


JavaScript syntax clearly is derived from awk's: the function keyword, regexp literals, for (x in a), optional semicolons, (associative) arrays, ...

Brendan Eich said as much: "JS’s function keyword did come from AWK" [1].

[1]: https://brendaneich.com/2010/07/a-brief-history-of-javascrip...


Yeah, they're both languages which are quite unlike C in operation, but both (by design) use C-like syntax to be more familiar to existing developers. I think AWK has survived incredibly well for a language that's 46 years old.


Awk is super interesting if you peel away a little. One nice thing about it is that the amount of code it takes to do something seems to scale quite linearly with the complexity of the thing you need to do. Which is exactly why you often see it in one-liners, but it's so much more. Recommend a deeper look at it.


There is so much about Awk that just seems more modern than Perl, which largely replaced Awk in common usage in the mid 1990s. Maybe the similarity to Javascript (which as others have mentioned isn't coincidental) will encourage younger people to take a look at it.


Surprised this hasn't been ported to JS, at first glance it already looks 90% done.


See also https://github.com/freznicek/awesome-awk

Lists projects like "CHIP-8 emulator", "A console videoplayer", "Draw 3D objects" etc


TIL that AWK is basically a fully featured programming language ( ⊙⊙)


Yeah didn’t realize that GitHub labeled it it’s own language either! Neat.


Curious to know if there's language that differentiate between procedure (function with side-effect) and pure function at the syntax level.


Ada does this -- sort of. In the base language procedures can't return anything, and functions must return something. However, either of the two can execute side effects.

The SPARK subset of Ada enforces purity of functions at compile time.

SPARK also allows partial purity, i.e. you can declare that a procedure has side effects, but only in the sense that it uses the wall clock as an input, or only in the sense that it writes to a global variable. You can specify in some detail exactly which side effects are allowed to happen in a procedure.


Nim does this, it has 'proc' and 'func'. They define a `func` as a procedure with no side effects using the macro `{.noSideEffect.}` [1].

[1] https://nim-lang.org/docs/manual.html#procedures-func


Fortran has subroutines and functions. Functions can take multiple arguments and return a single value (however arguments can also be modified). Subroutines can take multiple arguments, which can be inputs, outputs, or both (arguments can be declared inputs or outputs, but it's not required) and don't return a value. And then there's common blocks for sharing variables between subroutines...


And many languages that were influenced by it, from PL/I to CMS-2 (Both of which I used in my first years as a computer programmer)


Common blocks have been outdated for the past >33 years. Modules have been the proper modern safer way of sharing data and procedures since 1990.


That's the whole point of Haskell's separate IO type, and while there are other ways to compose IO values, the usual "do notation" creates a clear visual difference (but not too different) between statements (using <-) and expressions (using =).


Interesting to know. Do you know how the evaluation in IO Monad actually work ?


In theory, Haskell evaluates by graph-reduction, hence its lazy semantics, and then after evaluating a program to an IO value it interprets that, similarly to how e.g. a free monad + interpreter pattern would run. In practice Haskell-98 generally gets lowered into a simple form that can then be executed directly, and the IO monad is represented as effectively the state monad where the state is a marker token that represents the real world. In actual practice real-world Haskell IO with async etc. gets run in various ad-hoc ways that seem to work but aren't necessarily principled.


Among the gcc extensions to C and C++ there are 2 attributes for functions without side effects:

    __attribute__ ((pure))
    __attribute__ ((const))
The 'pure' attribute imposes similar but looser restrictions on a function's definition than the 'const' attribute: 'pure' allows the function to read any non-volatile memory, even if it changes in between successive invocations of the function.


BASIC has SUB (for procedures) vs FUNCTION (for functions).


Yes, Fortran has `pure` and `impure` attributes for functions/subroutines (with and without side-effects). ``` pure recursive function factorial(n) integer, intent(in) :: n ... end ```


I used Borland Turbo Pascal back in the '80s and '90s, and as I recall it had separate keywords and syntax for defining procedures vs. functions.


That was about returning a result or not. The void type made that redundant (in Algol-68).


Hell of a side project. As deranged as it is awesome.


Looking at the code it's not nearly as deranged as I would have expected. It's actually pretty easy to follow.


I came across this not too long ago. I recently picked up awk and went looking for unique / unlikely programs written in the language. This is completely mind blowing.


This is disgusting and I love it



Awk is a kind of first-person shooter, for row and column text files.


Text output, right? Can ChatGPT play it?


This dev must be one of the few in the world that doesn't need Google or man pages when awk is needed :)


The weird thing about awk is that it can be written to look like an ordinary c-inspired scripting language. But it also supports the terse one-liners that we see so often; and the general perception is that it's a language for wizards. The ordinary scripting language is hiding in plain sight.


Cool stuff!

BTW: gawk installation instructions for NetBSD and OpenBSD but not FreeBSD? That's a new one.


Fortunately the gawk(1) package name is the same on FreeBSD :)

    # pkg install gawk


Imagine how many games would be possible today if we leveraged those techniques more often.


This is on the same level of crazyness as the Z-Machine interpreter written in PostScropt.


Welcome to Ken’s Labyrinth


Can this be ported to mac awk ?


In my UNIX learning history I skipped straight from sed to perl and didn't use awk. By the time I had switched to python, awk sounded awfully "old" to me.

I went back recently and read more on it and now I understand: it was an excellent interpreted programming language that gave semiskilled programmers some things C didn't, like associative arrays, all nicely packaged within the UNIX frame of mind. In an alternative universe, perhaps awk, instead of perl and then python, would become the scripting language of choice.


For many of us, it is the scripting language of choice...


Most people naturally stepped from awk+sed+sh to Perl.

At least for scripts longer than 30-40 lines where sh looks clunky with too much var substitution and clunky sed regexen.

Perl is something between sh and C on syntax, but easier and with builting match/replace capabilities.


Python is only slightly younger than awk at this point.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: