Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. Revealing the details of how OpenAI agents hacked Hugging Face (swarmtraces.org)
    160comments
  2. Ollaya – Ollama for open-source, Jev-style decision models (ollaya.dev)
    102comments
  3. Show HN: Jev Plays Pokémon Red (jev-pokemon.vercel.app)
    71comments
  4. Plan mode is dead (aymannadeem.com)
    139comments
  5. What even is an OS now? (sockpuppet.org)
    177comments
  6. Jury finds Facebook liable for deceiving users in Cambridge Analytica case (cbsnews.com)
    6comments
  7. Platform-independent SIMD in Go (go.dev)
    136comments
  8. Postgres SELECT DISTINCT Does Not Scale (dbos.dev)
    3comments
  9. Git-bug: Distributed, offline-first bug tracker embedded in Git (github.com/git-bug)
    101comments
  10. One Piece of Flock Camera Data Put This Innocent Woman in Jail for 13 Days (jezebel.com)
    19comments
  11. Excel now supports multiple values in a single cell (techcommunity.microsoft.com)
    88comments
  12. Gravity seems holographic. What does that mean for reality? (quantamagazine.org)
    137comments
  13. Remembering Johannes Doerfert (llvm.org)
    2comments
  14. Show HN: Hacker Atlas - A map of what Hacker News talks about (hackeratlas.com)
    6comments
  15. I wrote a ray tracer in Brainfuck (epestr.com)
    12comments
  16. First Principles Thinking (sunilsadasivan.com)
    100comments
  17. Lab on a Contact Lens Can Measure Stress Through Serotonin (ieee.org)
    3comments
  18. U.S. appeals court upholds designation of Anthropic as supply chain risk (cnbc.com)
    715comments
  19. Fourier Analysis: Drawing Llamas with Circles (adekau.github.io)
    —discuss
  20. Show HN: A game about fake news and memes (unspin.app)
    6comments
  21. TiddlyInstall: A universal, reusable, install system (robertsdotpm.github.io)
    5comments
  22. How video games inspire great UX (2019) (jenson.org)
    16comments
  23. Why didn't anybody tell me about Redis hash slots? (verygoodsoftwarenotvirus.dev)
    5comments
  24. How we learned to stop worrying and love campus surveillance (fnl.mit.edu)
    80comments
  25. Show HN: Ekselio – Loveable for finance workflows (local first) (gptbeyond.com)
    2comments
  26. An airport cooled by natural ventilation (theguardian.com)
    30comments
  27. Show HN: Make math automatic with Mathy (gmays.com)
    21comments
  28. What happens when you analyze your favorite college football team like the CIA? (cultivatelabs.com)
    25comments
  29. Microsoft abandons personal AI chatbot race with Copilot reboot (bloomberg.com)
    85comments
  30. Alan Kay: Shannon gave us a way of dealing with noisy channels [video] (youtube.com)
    24comments

I wrote a ray tracer in Brainfuck

42 pointsby 17h agoepestr.com
12 comments
15h agoHN ↗

Calling this "written in brainfuck" is like calling anything in C "written in machine code"

1h agoHN ↗

I suppose writing the compiler which produces the machine code interesting. Similiarly the blog is about the abstractions and techniques and less so about writing with hand.

15h agoHN ↗

Isn't this just a ray tracer in python/c that spits out brainfuck? By this logic gcc writes all my programs in assembly lol

4h agoHN ↗

Well the proper analogy would be that you write your programs in assembly. I think the more impressive thing here isn't the ray tracer, but the C (or was it C++?) to brainf** transpiler. That would be equivalent to you writing both C code and the C compiler. Pretty impressive, but depending on the complexity of the program not as impressive as writing whatever it is in assembly directly. A raytracer would be PAIN to write directly in brainf** - I think I'd want to use fixed precision everywhere rather than emulated floating point. (on second glance, it does look like the author of the article is also using fixed precision arithmetic, but confusing the label for the layout of the number with the type of number representation itself?)

3h agoHN ↗

Looks like I misunderstood what it meant to be a floating point, and this does match the description of a fixed-point representation.

Pretty impressive, but depending on the complexity of the program not as impressive as writing whatever it is in assembly directly

I'd make the case assembly is easier here, given the DSL isn't much different in terms of it's experessiveness, and jumping around is easier in assembly too. Registers change the whole thing.

3h agoHN ↗

Pretty much, though the interesting bit is clearly the abstractions and work involved. Writing 22MB of code doesn't sound very maintainable :)

4h agoHN ↗

brainfuck is unpleasant to write directly - e.g. the language doesn't have variables, so you need to manually do the bookkeeping of which memory offset is storing what 'variable'. & if you need to refactor your program slightly, in a way that changes the memory layout, maybe you need to manually rework the absolute & relative offsets. So I can appreciate why the author didn't roll up their sleeves to directly write BF - that's neither a productive nor interesting exercise.

Interesting to see how the author decomposed the problem:

- C raytracer https://github.com/mTvare6/rayfuck/blob/master/ray.c

~~ LLM refactor of the C code ~~>

- SSA-style C raytracer code https://github.com/mTvare6/rayfuck/blob/master/ray_ssa.c

~~ c2dsl.py helper script (compiler) ~~>

- DSL raytracer https://github.com/mTvare6/rayfuck/blob/master/ray.dsl

~~ dsl2bf.py helper script (another compiler) ~~>

BF raytracer https://github.com/mTvare6/rayfuck/blob/master/ray.bf (~22 mb of unreadable nonsense)

The dsl2bf compiler has a bunch of examples of implementing slightly higher level abstractions atop BF primitives. E.g. "go" to move the pointer to a different offset, destructive & non-destructive copies, all the way up to things like division -- BF only natively offers unary addition/subtraction.

If we have a read of the code of the final compiler, dsl2bf.py, the abstractions used in that code are relatively simple: global variables, local variables, lists, dicts, for loops, function definitions & function calls. It is feasible to implement a simple compiler like dsl2bf in BF itself, with sufficient head scratching. Again, quite unpleasant to try it directly in BF, but a next step could be to implement the dsl2bf compiler in the DSL itself - extending it if necessary, then compiling it with itself to produce a dsl2bf compiler implemented in BF.

3h agoHN ↗

That does sound like a fun step, I'd already begun experimenting with some optimizations after having received suggestions in reddit to add fork/join primitives. Adding a compiler with these added performance gains sounds reasonable and something which will run quickly. dicts certainly involve some thought there.

I hadn't considered self-hosting the compiler, but having put it into works, I probably will.

This was the render the speed up version gave: https://paste.c-net.org/SpikingCarbs

2h agoHN ↗

dicts certainly involve some thought there

One way to start could be to ignore performance of the data structure.

The first main job dicts are being used for is the `mem` dict mapping a key (variable name) to some value record.

A data structure that supports Store(K, V) & V = Get(K) could be something like an stack allocated array of (Key, Value) pairs, that you search through using linear search to implement Store & Get. It wouldn't be very fast, but you probably don't have too many items in a typical DSL program. You'd need to implement some kind of stack or so on - or perhaps you could get away with reserving some fixed capacity.

2h agoHN ↗

Well the problem is that the DSL uses strings, so any representation which keeps variable names as strings still needs storage and comparison, which currently only the fixed type does. Though c2dsl could instead use a unique integer for every string for variables.

The first value of each instruction would then always be one of a fixed set of opcodes, variables their IDs, and numbers left as-is (and we've invented machine code :)). Then (K, V) is always fixed-size and laid out predictably in memory, so the linear-search approach sounds reasonable.

2h agoHN ↗

another approach could be to support strings, of length exactly 1. would 256 unique strings be enough to name all the variables (& functions?) in an interesting program?

1h agoHN ↗

Yup.

rg var ray.dsl | wc -l

142

rg func ray.dsl | wc -l

6

+28 for opcodes, bringing it to 176. So it works for this interesting program, the raytracer, but the compiler likely requires way more. Maybe not the 4 cells I've been using, but 2^16 = 65k would be enough buckets but unique names.