A Geiger counter is a device that is used to detect radiation.

We will be making a Geiger counter program.

As we all know, when radiation hits a computer program it removes exactly 1 byte at random. So a Geiger counter program is a program that itself does nothing, but when any byte is removed the modified program prints beep, to indicate the presence of radiation.

Answers will be scored in bytes with fewer bytes being better. Answers must be at least 1 byte.

Your program may print beep with trailing a newline or print a single newline for empty output, so long as it does so consistently. Your program may also use a different case for beep such as BEEP, bEEP, or Beep so long as it does so consistently.

  • 12
    \$\begingroup\$ Can we use the BEL control character to output an actual beep? \$\endgroup\$
    – Jo King
    Commented Aug 5, 2018 at 6:47
  • 2
    \$\begingroup\$ @JoKing I toyed with the idea, it is amusing, but I have to say no. It is too substantially different. \$\endgroup\$
    – Wheat Wizard
    Commented Aug 5, 2018 at 6:48
  • 1
    \$\begingroup\$ And much easier as well. (1 byte vs 4 byte) \$\endgroup\$
    Commented Aug 6, 2018 at 13:11
  • 2
    \$\begingroup\$ I want to see a solution in Retina. \$\endgroup\$
    – mbomb007
    Commented Aug 7, 2018 at 20:28
  • 3
    \$\begingroup\$ I'm trying to figure out how to do this in SMBF... but the only way to compare two cells involves changing them. And in SMBF, the cells you need to check are the cells the program is currently running on. So it's like the Heisenberg Uncertainty Principle. So you have to determine if anything changed using only control flow. \$\endgroup\$
    – mbomb007
    Commented Aug 7, 2018 at 21:39

14 Answers 14


Lost, 303 293 263 253 238 228 bytes


Try it online!

Verification script (borrowed from user 202729's answer). Unfortunately this can only test half of the code at a time, but rest assured I've tested the whole program.

Ouch, this was a tough one. I'll quote WW's deleted answer:

Lost is perhaps the most interesting language for this challenge. In Lost the start location and direction of the pointer is entirely random, thus to make deterministic programs you must account for every possible start location and direction. At the same time, by the nature of this challenge you must also account for any single byte being removed.

Unfortunately, his answer didn't take into account removing newlines, which screwed everything up.


(note that a few bytes might be off here and there)

First let's talk about the general structure of the code:

v^^"peeb"<<\/"beepvv"((>>>@@>>%%>>(((((([[[[[[[\       Processing line
>>>>>>>>>>>//>>>>>>>>>>>>>>>>>>>/>>>>>>>>>>>>>>\\      Beep line
>>>>>>>>>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\\     Back-up beep line
>//>>>>>>>>>>>>>>>>>>>>\\>>>>>>>>>>>>>>>>>>>>>>>>\\    Back-up return line
>>>>>>>>>>>>>>>>>>>>>>>>\\>>>>>>\>>>>>>>>>>>>>>>>>\    Return line

Everything but the processing line must be entirely composed of either > or one of \/. Why? Well, as an example, let's remove a newline:


The first line is now way longer than the rest of the block. If a pointer were to spawn on a non->\/ character with vertical movement, then it would get stuck in an infinite loop.

The biggest radiation detector part is the section at the end of each line.


Normally an IP passing through this from the first line would exit out the last line. However, if any character on the line is removed, then that line shifts down one, e.g:


And the IP instead exits out the line that is missing a byte (with the exception of the last line, where it exits out the second to last).

From there, each of the first four lines will redirect to the second line:


Which will then lead into either one of the two beepers.


If any of the bytes in the first beeper have been removed, then it instead goes to the second:


Both beepers then lead back to the first line and the terminating @.

Some other miscellaneous parts:

The (((((([[[[[[[ is used to clear the stack when the pointer starts inside a pair of quotes and ends up pushing the whole first line to stack. It has to be so unfortunately long because the first newline can be removed to make the first line twice the size. Experimenting in generating the beep using arithmetic instead of quotes ended up longer.

The \s and /s scattered across the lines are there to golf bytes in the top line of code by redirecting the pointer to the correct lines. As most of the bottom lines are just filler, only the top line is able to be golfed. If anyone has any ideas for a shorter radiation proof stack clearer then what I've got now, feel free to comment.

  • \$\begingroup\$ Just out of curiosity, how helpful was the partial answer I posted in chat? I saw some similarities in the earlier versions, and I'd like to know if I was on the right track. \$\endgroup\$
    – Wheat Wizard
    Commented Aug 7, 2018 at 5:31
  • 1
    \$\begingroup\$ @WW I had already been working on it by then, but the \/ to separate the beep pushes and the fact that only one of the quotes needed an exit clause helped \$\endgroup\$
    – Jo King
    Commented Aug 7, 2018 at 5:36

Hexagony, 38 bytes


Try it online!

Verification program.


We make use of Hexagony's auto-detection of hexagon side-length here.

If no bytes are removed, the program has side length 4 and looks like this:

Program without any bytes removed

If however, a byte is removed. There are 2 cases.

  1. The removed byte is after the second <.

    The execution flow would be:

    Program with last byte removed

    There are 2 consecutive @ on the 5th line, so even if one of them are removed, the IP will safely hit a @.

  2. The removed byte is at or before the second <.

    Then the second half will stay intact, and the IP is no longer redirected upwards by that <. Image of execution flow:

    Program with the second <code><</code> removed


Klein XXX, 144 136 128 122 114 bytes

This answer completes JoKing's challenge to make a Geiger counter that works in every Klein topology.


Try it online! Verification script

I don't believe it is really possible to make a perfectly satisfactory explanation. There are definitely aspects of this that I'm not aware of. It's just got too much going on. So the explanation below is a bit rough. I just want to get the idea across even if I gloss over a lot of the details.

The obvious next step is to create a version of Lost that can run on different Klein topologies, and create a Geiger counter in Lost that works in every topology. I don't know if really should be encouraging people to spend there time on such a awful and frustrating task, but I would certainly be willing to give a 500 rep bounty to someone who does the above.


The idea for this is to make a program with 2 parts.

The first is the path taken during normal execution. This path doesn't cross any boundaries, so we can avoid having to deal with the topology, and most importantly is very, very fragile. The idea here being that any disturbance to the program breaks the path and sends the ip flying off randomly.

The second part is a robust core. This part is sort of the opposite, it's role is to catch pointers that have gone off the path and direct them to the beeper. It needs to be impervious to radiation and it needs to catch as many stray pointers as possible.

The general strategy here was to build a program like this and just keep fixing the problems.

The Path

The path looks like this:

\   / ?......\
!   .        \\
    @         \.\
!              //
\\           //
 \....?! 1! ./

Some important about this things are

  • We mostly use mirrors (\ and /) rather than hard redirects. They are more fragile, and make it harder to get back on the path.
  • The last character of every line is part of the path. This is required since removing them needs to break the path.
  • It is sort of hexagon shaped. This is because a right angle turn can be simulated by a pole (e.g. the NE corner in 101) in the topology. So if we try to make a right angle turn at the corner there will end up being a topology that doesn't even need the mirror to make the turn.
  • We have ?!/1 at the bottom and ? near the end. This is to make sure that the bottom portion gets executed exactly once. Sometimes the pointer ends up back on the path after getting knocked off. This makes sure that if it hits the bottom portion of the path it doesn't get stuck in a loop there, and if it skips that portion it can't get to the end of the path.
  • It covers basically the entire perimeter of the program. Hypothetically we only really need the left edge of the program but a full circuit is more fragile and we have to get to the other side anyway.

I experimented with both clockwise and anticlockwise paths. Ultimately clockwise should be better since you can make a shorter path. But I could not get it to work and some earlier attempts using this approach just never worked out. I managed to make an anticlockwise path so that's what's here. I might take some time with the lessons learned here to try clockwise again.

The Core

The core is nothing too special. It is based off of the method used by pretty much every 2D Geiger counter we have two lines each which print beep, and we use the length of each to figure out which is damaged, so we can execute the other one. We surround this with ton of >s to force ips where we want them, this is the classic strategy for Lost programs.


Hexagony, 34 29 bytes


Try it online! Verification!


Here is the normal code formatted into a proper hexagon using HexagonyColorer:

No Cancer...

The double // at the beginning ensures that this path is always taken. If any character is removed, the @ is removed from the path, either being shifted one back or being removed itself:


In this case, we've removed a character after the |, which makes it follow this path, printing beep:

First beep

If we instead remove a character from before the | (or the | itself), we follow the other beep printer:

Second beep

We've then accounted for all possibilities and we only beep using the un-irradiated parts of the program.


Self-modifying Brainfuck, 73 63 bytes

<<[[[[<<]]>[[.>>..>>.[,>]]]]   bbeepp+[<<<]>>[[>]>>>.>>..>>.,+]

Try it online! Verification!

The spaces in the middle of the code are actually representing NUL bytes.


The code is split into two sections by 3 NUL bytes in the middle. Both of them basically prints beep if the other section is irradiated (with a couple of exceptions).

First, the <<[[ at the beginning is to ensure that all ]s are matched at any time. [s won't attempt to look for a matching ] if the cell is positive, while ]s do. If any ] jumps back to one of these brackets it usually jumps back straight away because the cell is 0.

The next part, [[<<]]> then checks if the length of section 2 is even. If so, it executes the other half of section 1, which prints beep using the bbeepp at the start of section 2.


It then clears all of section 2 so it doesn't execute.

In section 2, we check if the length of section 1 and the NUL bytes is divisible by 3 with +[<<<]>>.


Similarly, we print beep.


Z80Golf, 53 36 34 bytes

-16 bytes thanks to @Lynn
-2 byte thanks to @Neil

Since this is just Z80 machine code, there is a lot of unprintables in this one, so have a xxd -r-reversible hexdump:

00000000: ddb6 2120 10dd b615 280c 003e 62ff 3e65  ..! ....(..>b.>e
00000010: ffff 3e70 ff76 003e 62ff 3e65 ffff 3e70  ..>p.v.>b.>e..>p
00000020: ff76                                     .v

Try it online! (exhaustive tester in Python)


z80golf is Anarchy Golf's hypothetical Z80 machine, where call $8000 is a putchar, call $8003 is a getchar, halt makes the interpreter exit, your program is placed at $0000, and all other memory is filled with zeroes. Making programs radiation-proof in assembly is pretty hard, but a generically useful technique is using one-byte idempotent instructions. For example,

or c        ; b1    ; a = a | c

is just one byte, and a | c | c == a | c, so it can be made radiation-proof by just repeating the instruction. On the Z80, an 8-bit immediate load is two bytes (where the immediate is in the second byte), so you can load some values into registers reliably too. This is what I originally did at the beginning of the program, so you can analyze the longer variants I archived at the bottom of the answer, but then I realized that there is a simpler way.

The program consists of two independent payloads, where one of them could have been damaged by radiation. I check whether a byte was removed, and whether the removed byte was before the second copy of the payload, by checking the values of some absolute memory addresses.

First, we need to exit if no radiation was observed:

    or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
    jr nz, midbyte     ; 20 10    ; jump to a halt instruction if not zero

If any byte was removed, then all the bytes will shift and $0020 will contain the last 76, so $0021 will be a zero. We can afford radiating the beginning of the program, even though there is virtually no redundancy:

  • If the jump offset $10 is removed, then radiation will correctly be detected, the jump will not be taken, and the offset will not matter. The first byte of the next instruction will be consumed, but since it's designed to be resistant to byte removals, this doesn't matter.
  • If the jump opcode $20 is removed, then the jump offset $10 will decode as djnz $ffe4 (consuming the next instruction byte as the offset -- see above), which is a loop instruction -- decrement B, and jump if the result is not zero. Because ffe4-ffff is filled with zeroes (nops), and the program counter wraps around, this will run the beginning of the program 256 times, and then finally continue. I am amazed this works.
  • Removing the $dd will make the rest of the snippet decode as or (hl) / ld ($1020), hl, and then slide into the next part of the program. The or will not change any important registers, and because HL is zero at this point, the write will also cancel out.
  • Removing the $b6 will make the rest decode as ld ($1020), ix and proceed as above.
  • Removing the $21 will make the decoder eat the $20, triggering the djnz behavior.

Note that using or a, (ix+*) saves two bytes over ld a, (**) / and a / and a thanks to the integrated check for zero.

We now need to decide which of the two copies of the payload to execute:

    or (ix+midbyte)  ; dd b6 15
    jr z, otherimpl  ; 28 0c
    nop              ; 00
    ; first payload
    ld a, 'b'        ; 3e 62
    rst $0038        ; ff
    ld a, 'e'        ; 3e 65
    rst $0038        ; ff
    rst $0038        ; ff
    ld a, 'p'        ; 3e 70
    rst $0038        ; ff
    halt             ; 76
    nop              ; 00
    ld a, 'b'        ; 3e 62
    ; ...            ; ...
    rst $0038        ; ff
    halt             ; 76

The two copies are separated by a nop, since a relative jump is used to choose between them, and radiation could have shifted the program in a way that would make the jump skip the first byte after the destination. Additionally, the nop is encoded as a zero, which makes it easy to detect shifted bytes. Note that it doesn't matter which payload is chosen if the switch itself is corrupted, because then both copies are safe. Let's make sure that it will not jump into uninitialized memory, though:

  • Deleting $dd will make the next two bytes decode as or (hl) / dec d. Clobbers D. No big deal.
  • Deleting $b6 will create an undocumented longer encoding for dec d. Same as above.
  • Deleting $15 will read the $28 instead as the offset, and execution will proceed at the $0c, as below.
  • When $28 disappears, the $0c is decoded as inc c. The payload does not care about c.
  • Deleting $0c - that's what the nop is for. Otherwise, the first byte of the payload would have been read as the jump offset, and the program would jump into uninitialized memory.

The payload itself is pretty simple. I think the small size of the string makes this approach smaller than a loop, and it's easier to make position-independent this way. The e in beep repeats, so I can shave off one ld a. Also, because all memory between $0038 and $8000 is zeroed, I can fall through it and use a shorter rst variant of the call instruction, which only works for $0, $8, $10 and so on, up to $38.

Older approaches

64 bytes

00000000: 2e3f 3f2e 3f3f 7e7e a7a7 201f 1e2b 2b1e  .??.??~~.. ..++.
00000010: 2b2b 6b00 7ea7 2814 003e 62cd 0080 3e65  ++k.~.(..>b...>e
00000020: cd00 80cd 0080 3e70 cd00 8076 003e 62cd  ......>p...v.>b.
00000030: 0080 3e65 cd00 80cd 0080 3e70 cd00 8076  ..>e......>p...v

58 bytes

00000000: 2e39 392e 3939 7e7e a7a7 2019 3a25 00a7  .99.99~~.. .:%..
00000010: 2814 003e 62cd 0080 3e65 cd00 80cd 0080  (..>b...>e......
00000020: 3e70 cd00 8076 003e 62cd 0080 3e65 cd00  >p...v.>b...>e..
00000030: 80cd 0080 3e70 cd00 8076                 ....>p...v

53 bytes

This one has an explanation in the edit history, but it's not too different.

00000000: 3a34 00a7 a720 193a 2000 a728 1400 3e62  :4... .: ..(..>b
00000010: cd00 803e 65cd 0080 cd00 803e 70cd 0080  ...>e......>p...
00000020: 7600 3e62 cd00 803e 65cd 0080 cd00 803e  v.>b...>e......>
00000030: 70cd 0080 76                             p...v

What if: any non-empty output was fine instead of beep

1 byte


halts the program normally, but if radiation removes it, then the memory will be full of zeroes, making $8000 execute an infinite number of times, printing a lot of null bytes.

  • \$\begingroup\$ Since a starts at zero, can you not use or a, (N); instead of ld a, (N); and a;? It looks as if you can save a couple of bytes that way. \$\endgroup\$
    – Neil
    Commented Aug 8, 2018 at 8:35
  • \$\begingroup\$ @Neil Good question! Unfortunately, on the Z80, only load instructions can take addresses like this. \$\endgroup\$
    – Maya
    Commented Aug 8, 2018 at 11:50
  • \$\begingroup\$ Ugh, it's been too long since I did any Z80 programming... maybe I was thinking of or a, (ix + N)? \$\endgroup\$
    – Neil
    Commented Aug 8, 2018 at 15:17
  • \$\begingroup\$ @Neil actually, that exists, and IX starts at zero too... unfortunately, saving a byte in that area makes the bytes shift in such a way that the 20 19 at the beginning becomes 20 18, and removing the 20 creates an unconditional jump backwards, so a nop has to be added after the first jump in the program, reversing the byte save. \$\endgroup\$
    – Maya
    Commented Aug 8, 2018 at 17:55
  • \$\begingroup\$ Ah, that's a shame. Thanks for checking though! \$\endgroup\$
    – Neil
    Commented Aug 8, 2018 at 19:10

><>, 23 bytes


Try it online! Verification.

It's honestly really surprising how short I got this. Ends with an error.

Non-erroring version, 29 bytes


Try it online!


Klein, one of each topology, totaling 291 bytes

After seeing WW's answer using the 001 topology, I decided to see how hard it would be to do a Geiger Counter for each topology. (Spoiler: very hard. It's difficult to figure out where the pointer will go without hand gestures that make me look like I'm figuring out which hand is my left)


(I also thought about writing a program that is a valid Geiger counter on all topologies, but that might have to wait. If anyone else wants to try though, I'm offering a 500 rep bounty)

000 and 010, 21 bytes


Try 000 online! and Try 010 online!

This is ported from my ><> solution. This obviously works in 000, since that's the default topology for most 2D languages, but I was surprised that it also works in 010.

001 and 011, 26 bytes


Try 001 online! and Try 011 online!

This one is copied directly from WW's answer. Thanks!

100, 21 bytes


Try it online!

101, 21 bytes


Try it online!

110, 26 bytes


Try it online!

111, 24 bytes


Try it online!

200, 21 bytes


Try it online!

201, 31 bytes


Try it online!

By far the most annoying.

210, 26 bytes


Try it online!

211, 27 bytes


Try it online!

The only one where I had to handle entering the beeper through the right side.


Klein 0X1, 26 bytes

Works in both 011, and 001.


Try it online!



This program takes advantage of Klein's unique topologies in particular the 001 and 011 topology, which are the Klein bottle and the real projective plane. This explanation will focus on 001, the klein bottle.

Unedited the program follows the execution path:

Orange path

Removing a byte from the program can effect the program in 4 ways (each in a different color):

Program sections

The first thing to note is that << will always deflect the ip to the left of the origin at the start. If one of the <s is deleted the other takes its place. So if any byte is removed from the red section the following execution path will be followed:

Red path

If the blue byte is removed we get the very simple path:

enter image description here

If the newline is removed we get the path:

Green path

The yellow path is a bit more complex. Since the bottom line is one longer than the top line, when the program is squared at the beginning of execution a virtual character is added to the end of the first line to make them the same size. If any byte on the second line is removed the line is shortened and that virtual character is not added. This is important because ! normally jumps over the virtual character, but in its absence it jumps over / instead.

Yellow path

  • 1
    \$\begingroup\$ You could port my ><> solution in 000 for 21 bytes \$\endgroup\$
    – Jo King
    Commented Aug 18, 2018 at 3:07
  • \$\begingroup\$ @JoKing I think that would be better as its own answer. \$\endgroup\$
    – Wheat Wizard
    Commented Aug 18, 2018 at 3:35

Self-modifying Brainfuck, 144 102 bytes

Unprintables are displayed as escape sequence (for example \x01).




Backhand, 25 21 bytes


Try it online! Verification!

This uses Backhand's ability to change the pointer step value to skip an instruction every step and neatly solve the redunancy issue. It then uses the j command to check if the code is irradiated by jumping to the last character (@, halt) if not, and jumping to the second last (H, halt and output stack) if so.


Runic Enchantments, 29 bytes


Try it online!

Essentially the same as the Klein 000 answer or ><> answer (I started with the Klein one). The only change really needed was to turn the < into L and . into  (translation of command symbols), inserting the IP entry points (need 2, otherwise a deletion would result in a non-compiling program) and the insertion of the delay command to get the two IPs to merge (thus printing only one beep), again, needing two. Also required inserting additional NOPs to keep line lengths the same. Klein conveniently also uses @ for "print and terminate."

No ability to utilize the whitespace in the lower left, as any reflectors to change direction inhibits the ability to detect radiation. e.g. (26 bytes, irradiated y):

\<<  @"peeb"L\

Prints no output, due to the bent entry segment causing a re-reflection back to the lower line's terminator.


Befunge-93, 55 bytes

<< >       vv
v  |   _ #-<_

Try it online! Verification!

I'd hoped to get it a little smaller than this, but the length of the beep printer is the bottleneck.


Wumpus, 37 34 32 31 bytes

777*7..@ $o&4"beep"|"@peeb"4&o@

Try it online! Verification!

This solution uses the fact that . jumps to a position modulus the length of the program.

Alternatively for the same amount of bytes

" @o&4"beep"}@

Try it online! Verification!

This one utilises the difference in the direction of the pointer for odd and even line lengths. (I don't really know how the first " actually works when the newline is removed)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.