2.}<@>%?<{>$"/\M!8;
Readable:
2 . }
< @ > %
? < { > $
" / \ M
! 8 ;
Try it online!
This can probably be golfed by a byte or two, but that might require some truly ingenious layout, that might be more easily found via brute force (even if it might take rather long to find it).
High level explanation
The program mostly follows this pseudocode:
while (read number is not zero)
{
if (number is even)
print number;
}
Which abuses how Hexagony tries to read a number once STDIN is empty (it returns a zero). Big thanks to Martin for help with coming up with this approach.
Full Explanation
I still haven't fiddled around with Mono to get Timwi's fantastic esoteric IDE running, so I've leant on Martin to provide me with some helpful pretty pictures!
First, a little primer on basic control flow in Hexagony. The first instruction pointer (IP), which is the only one used in this program, starts at the top left of the hexagonal source code, and begins moving towards the right. Whenever the IP leaves the edge of the hexagon, it moves side_length - 1
rows towards the middle of the hexagon. Since this program uses a side length three hexagon, the IP will always be moving two rows when this happens. The only exception is if it moves off of the middle row, where it conditionally moves towards the top or bottom of the hexagon, depending on the value of the current memory edge.
Now a bit about conditionals. The only conditionals in Hexagony for control flow are >
, <
and the middle edge of the hexagon. These all follow a constant rule: if the value on the current memory edge is zero or negative control flow moves left and if is positive the control flows right. The greater than and less than brackets redirect the IP at sixty degree angles, while the edge of the hexagon controls to which row the IP jumps.
Hexagony also has a special memory model, where all data is stored on the edges of an infinite hexagonal grid. This program only uses three edges: one to store a two, one for the currently read number, and one for the number modulo two. It looks something like:
Mod \ / Input
|
2
I'm not going to carefully explain where we are in memory at each point during the explanation of the program, so come back here if you get confused by where we are in memory.
With all of that out of the way, the actual explanation can begin. First, we populate the "2" edge in memory with a 2, then we execute a no-op and move the memory pointer to the right (2.}
).
Next, we begin the main program loop. We read the first number from STDIN and then we hit a conditional (?<
). If there are no numbers left in STDIN, this reads a zero into the current memory edge, so we turn left onto the @
, which ends the program. Otherwise, we bounce off a mirror, move the memory pointer backwards and to the left, wrap around the hexagon to calculate the remainder of dividing the input by 2 and then hit another conditional (/"%>
).
If the remainder was one (i.e. the number was odd), we turn right following the blue path above starting by executing the no-op again, then we wrap around to the bottom of the hexagon, multiply the current edge by 10 and then add eight, bounce off a couple mirrors, do the same multiplication and addition again, getting 188 on the current edge, wrapping back around to the top of the hexagon, executing the no-op again, and finally ending the program (.8/\8.@
). This convoluted result was a happy accident, I originally had written a much simpler bit of logic, but noticed that I could remove it in favour of the no-op, which I thought was more in the spirit of Hexagony.
If the remainder was zero we instead turn left following the red path, above. This causes us to move the memory pointer to the left, and then print the value there (the input value) as a number. The mirror we encounter acts as a no-op because of the direction we are moving ({/!
). Then we hit the edge of the hexagon which acts a conditional with only one outcome, as the input value from before was already tested to be positive, so we always move towards the right (if you imagine yourself facing in the direction of the IP). We then multiple the input by 10 and add two, only to change direction, wrap around and overwite the new value with the ascii value of the capital letter M, 77. Then we hit some mirrors, and exit over the edge of the middle of the hexagon with a trampoline (2<M\>$
). Since 77 is positive, we move right towards the bottom of the hexagon and because of the trampoline skip the first instruction (!
). We then multiply the current memory edge by 10 and add 8, getting 778. We then output this value mod 256 (10) as an ASCII character, which happens to be newline. Finally we exit the hexagon and wrap back around to the first ?
which overrides the 778 with the next input value.