The Versatile Integer Printer
15 languages, 68 66 65 bytes / 15^3 = 0.019...
Retina, Starry, Prelude, ETA, Axo, Labyrinth, Hexagony, Foo, Brian & Chuck, Gol><>, evil, Whitespace, Fission, ><> and GolfScript.
After a massive rewrite, I managed to fit in four more languages. The code contains the few tabs for Whitespace. Since Stack Exchange converts them to spaces, I've represented them with \t
below:
#I5aeeNTH{\? \t\t + +3;n@"8"ea9
15}7'`--~!@<"31"LSOe.\t
\teaww`
I think I'm done adding languages (although adding only one might save some bytes in what I already have). I wonder if it's golfable though... 65 bytes for 15 languages is quite a jump from 32 bytes for 11 languages, and I've now got at least one useless character in there to make Foo work..
Retina prints 1
Try it online.
Luckily, the first line is a valid regex. However that regex obviously doesn't match the empty input, so the first stage (consisting of the first two lines) doesn't do anything.
The third line is on its own, so it's treated as a Match stage which, by default, counts the number of matches. However, the `
is a separator which tells Retina that the part in front of it is a configuration string (it doesn't happen to know any of the options given there) and the part after it is the regex. So the regex is empty and Retina finds exactly one match.
Starry prints 2
Try it online.
Starry ignores everything except spaces and +*,'`.
. Each command is one of those characters in conjunction with the spaces since the last of those characters. So let's remove all the extraneous code:
+ +'`. `
Seven spaces followed by +
pushes a 2
. One space followed by a +
duplicates it. '
is a conditional jump. It pops the top of the stack, which is truthy (positive), so it jumps to the corresponding label (where labels are indicated by `
and "corresponding" means "with the same number of leading spaces"), which is the first `
. .
without spaces in front of it then prints the top of the stack as a number.
Prelude prints 3
Try it online.
This assumes the Python interpreter which uses numeric output. Let's remove all the no-ops:
# 5 ? + +3 8 9
15 7 -- ! 31
The first voice does a bunch of stuff, but nothing of it matters, because there is no !
to print any of the results. The second voice pushes a 1
, then a 5
, then a 7
. We take the difference of the last two to get -2
, and then subtract that from the 1
to get 3
. !
prints it. The third voice has only no-ops.
ETA prints 4
Try it online.
ETA ignores everything except the characters ETAOINSH
(in any case). So the code as seen by ETA is:
IaeeNTHneaSOeea
I
tries to read input but can't, so it pushes -1
. a
pushes the current line number plus 1, which is 2
. e
is divmod, which replaces those with 0
and 1
(or -1
, I don't actually know, but it doesn't matter). The next e
replaces both of them with 0
.
Now the interesting part. NTHne
is a base-7 number literal. N
and e
are just the delimiters, and the three digits are THN
. That is 54
(where T
is digit 1
, H
is 0
and n
is 5
). a
pushes 2
once more. S
subtracts it, resulting in 52
and O
outputs it as a character (4
). Now e
tries divmod again, but the stack contains two zeroes, so the program terminates with an error (but doesn't pollute STDOUT while doing so).
Axo prints 5
Try it online.
This language was pretty much single-handedly responsible for the rewrite. I couldn't have the }
on the first line because it would block for input in Axo (see revision history for what I'm talking about). For Axo, only this part of the code is relevant:
#I5aeeNTH{\
Luckily, Axo also has implicit 0
s at the bottom of its stack, because #
pops the top of the stack (to check if the next instruction should be skipped or not). The letters are all no-ops. Then 5
pushes a 5
, {
prints it, \
terminates the program. Quite simple, really.
Labyrinth prints 6
Try it online.
I'm truncating the code a bit, because the right half is never reached, and I'm also using t
in place of \t
, so that the columns line up correctly:
#I5aeeNTH{\
15}7'`--~!@
teaww`
Now that letters, spaces and tabs are walls in Labyrinth, so the accessible code actually looks like this:
# 5 {\
15}7'`--~!@
`
The instruction pointer will automatically follow that path. #
pushes the depth of the main stack (0
) and 15
turns it into a 15
. }
moves it off to the auxiliary stack, and we're not going to use it any more. That conveniently makes the top of the stack zero, so that the IP does not turn left onto the 5
. 7
turns the zero into a 7
, '
is a no-op. The `
is unary negation, so we get -7
. Now -
subtracts the -7
from the implicit 0
underneath making it 7
. This time, the IP does turn right to the `
, which is unary negation, so we get 7
again. The IP hits a dead end a turns around. The -
does the same thing as before, so we get 7
once more. As the top of the stack is now positive, the IP turns right. There's another -
which gives -7
again. Then ~
is bitwise NOT, which gives 6
and !
prints it. That's just the right moment to do so, because now the stack is empty again such that the IP won't turn left onto the {
but instead continues straight ahead into the @
which terminates the program.
Hexagony prints 7
Try it online.
The unfolded code looks like this:
# I 5 a e
e N T H { \
? + + 3 ; n @
" 8 " e a 9 1 5
} 7 ' - - ~ ! @ <
" 3 1 " L S O e
. e a w w . .
. . . . . .
. . . . .
Normally, that would be a terrifying Hexagony program, but the characters actually in use are not too many. In fact they are pretty much the same as those used by Labyrinth and I think the way I differentiate between 5
and 6
is quite nice. :)
The top row can basically be ignored. #
would normally switch to a different IP, but the current memory edge is 0
, so it doesn't. The letters just set a fixed memory value, but we're not going to use it. After the end of the first row, control flow continues in the middle row (starting from the }
, going right). The }
moves to another memory edge. 7
sets that edge to 7
. '
moves back to where we came from. -
subtracts the memory edge we've just set to 7
from an unused memory edge (0
), so we get -7
. The next -
does the same thing again, so it's a no-op. So far, quite similar to Labyrinth (apart from the memory layout). But now ~
is not bitwise NOT but unary negation in Hexagony. So this gives 7
instead of 6
. !@
, like in Labyrinth prints the value and terminates the program.
Foo prints 8
Try it online.
As we all know since The Programming Language Quiz printing things is quite trivial in Foo, even if most of the code is a random jumble of characters. None of the characters affect the output except the "8"
which prints 8
. Well, there is the "31"
later on, but Foo terminates with an error at the end of the first line. I'm not exactly sure why that happens, but it requires that 3
(or any other digit) on the top row, which isn't used anywhere else.
Brian & Chuck prints 9
Try it online.
Let's do this thing again where we remove the third line (it's never parsed) and replace all irrelevant characters (i.e. no-ops, or cells that aren't read) with spaces:
{ ? + + 9
} -- < .
Just as a reminder, each line is a Brainfuck-like whose tape is the source code of the other program. Control flow starts on the first line (called Brian).
The {
moves the tape head all the way to the left (where it already is), and ?
hands control flow over to Chuck (the second line). There, }
moves the tape head to the right until it finds a zero cell. That doesn't happen until the end of the program, so the tape head ends up one cell after the 9
. -
decrements that cell, but that's irrelevant. <
moves the tape head onto the 9
and .
prints it. Chuck runs out of program and terminates.
Gol><> prints 10
Tested here.
#
is a mirror, so the IP immediately skips to the end of the first line (and goes left). The 9
can be ignored. a
pushes 10
, e
pushes 14
, "8"
pushes the character code of 8
, @
rotates the top three stack elements (pulling up the 10
), such that n
prints the 10
and ;
terminates the program.
Thanks to Sp3000 for suggesting to use @
instead of !
(which saved a byte).
evil prints 11
Thanks to Sp3000 for sending me some brute-forced command-lists to generate single-digit numbers.
Try it online.
evil ignores everything except lower case letters so the code looks like this:
aeeneaeeaww
Also, n
affects some state we don't care about so let's ignore that as well. Now a
increments the register (which starts at 0
), and e
is evil's magic "weave" operation which permutes the bits in a particular way. aeeeaeea
happens to yield the value 49
which is the character code of 1
. ww
prints it twice.
Whitespace prints 12
Try it online.
Okay, we know Whitespace only reads spaces, tabs and linefeeds, so let write the code as seen by Whitespace with STL
:
SSSSSSTTSSLTLST
That's two commands:
SSSSSSTTSSL
TLST
The first one pushes the number 12
. Specifically, SS
starts a number literal. The next S
is the sign bit (positive). Then everything up to the L
is a binary representation of the number. There's a ton of leading zeroes, which we need for Starry, but they don't affect the number. Then the TTSS
s is 12
in binary. Fun fact: if I added a 16th language, I could save a byte here, because Starry could use the four S
in the binary represtation of 16
. I doubt I will though...
The TLST
just prints the top of the stack as a number. (TL
marks the command as an I/O command, and ST
is printing numbers.)
Fission prints 13
Try it online.
Fission only sees this part of the code:
<"31"L
L
starts control flow with a left-going atom. "
toggles print mode, so that 31
just prints 13
. Then the atom is captured in the wedge of the <
, which terminates the program.
><> prints 14
Tested here.
Distinguishing between ><> and Gol><> isn't as easy as I thought, because Gol><> almost always does the same thing as ><> for commands that exist in both, and commands that only exist in Gol><> cause ><> to crash. However, @
rotates the other way round in ><>, such that it pushes down the 7
instead of pulling up the 10
, and then the 14
gets printed instead of the 10
.
GolfScript prints 15
Try it online.
This one is simplest: #
comments out the first line. Then 15
pushes itself and }
is a "super comment", which ignores the entire rest of the program. So the 15
is printed at the end of the program.
30 languages, 248 bytes, 248/30^3 = 0.009185
#|#?15g,@ kkmNmSaIeoe99+{\#/-;n@0ea
#[9!@>.>.eeaww#-1@*"12" L
#{
###
#`{
25
print(4^2 +7)/2
"""
Jo is here.
$'main'MoO OOM
7
>Jo, 30
>X Jo
f::=~27
::=]##}#(prin 29)
print (7/6*24)###;alert 2#-[>+<-----]>-.|#(write(if(= 1/5 .2)26 3))"""
Edit: Beatnik removed since primality testing in Beatnik might not be possible.
The code has tabs in it (which get mangled by Stack Exchange) and a trailing newline, so here's the xxd
:
00000000: 237c 233f 3135 672c 4020 2020 0920 2020 #|#?15g,@ .
00000010: 206b 6b6d 4e6d 5361 4965 6f65 3939 2b7b kkmNmSaIeoe99+{
00000020: 5c23 2f2d 3b6e 4030 6561 0a23 5b39 2140 \#/-;n@0ea.#[9!@
00000030: 3e2e 3e2e 6565 6177 7723 2d31 402a 2231 >.>.eeaww#-1@*"1
00000040: 3222 094c 0a23 7b20 090a 2323 230a 2360 2".L.#{ ..###.#`
00000050: 7b0a 3235 0a70 7269 6e74 2834 5e32 202b {.25.print(4^2 +
00000060: 3729 2f32 0a0a 0a22 2222 0a4a 6f20 6973 7)/2...""".Jo is
00000070: 2068 6572 652e 0a24 276d 6169 6e27 4d6f here..$'main'Mo
00000080: 4f20 4f4f 4d0a 2037 0a3e 4a6f 2c20 3330 O OOM. 7.>Jo, 30
00000090: 0a3e 5820 4a6f 0a66 3a3a 3d7e 3237 0a3a .>X Jo.f::=~27.:
000000a0: 3a3d 5d23 237d 2328 7072 696e 2032 3929 :=]##}#(prin 29)
000000b0: 0a70 7269 6e74 2028 372f 362a 3234 2923 .print (7/6*24)#
000000c0: 2323 3b61 6c65 7274 2032 232d 5b3e 2b3c ##;alert 2#-[>+<
000000d0: 2d2d 2d2d 2d5d 3e2d 2e7c 2328 7772 6974 -----]>-.|#(writ
000000e0: 6528 6966 283d 2031 2f35 202e 3229 3236 e(if(= 1/5 .2)26
000000f0: 2033 2929 2222 220a 3))""".
Alternatively, you can copy and paste the code from this "Try it online!" link.
This is pretty badly golfed, but I wanted to play off the idea that, once you have enough languages, byte count doesn't matter as much any more. Having said that there are some languages I could still easily add (e.g. Objeck) but are currently too long to be useful. I'm running out of good languages though, so I might stop here for now.
Run all programs with </dev/null 2>/dev/null
(i.e. empty input, surpressed STDERR).
The explanation's quite long, so here's an executive summary:
No. Lang. Non-esolang? 2D esolang? BF/BF-deriv?
--------------------------------------------------------------------------
1 COW ✓
2 CoffeeScript ✓
3 Common Lisp ✓
4 Retina
5 Befunge-93 ✓
6 Python 2 ✓
7 Rail ✓
8 ETA
9 Prelude
10 Gol><> ✓
11 evil
12 Foo ✓
13 Ruby ✓
14 ><> ✓
15 Brian & Chuck ✓
16 Whitespace
17 3var
18 Axo ✓
19 Labyrinth ✓
20 Starry
21 Fission ✓
22 Brainfuck ✓
23 Julia ✓
24 Lily ✓
25 GolfScript
26 Chicken Scheme ✓
27 Thue
28 Perl 6 ✓
29 Picolisp ✓
30 TRANSCRIPT
1. COW
COW is a Brainfuck derivative with additional commands, one of which is numeric output. Anything invalid is ignored, so the executed program is merely
MoO OOM
which increments the cell to 1 then prints it as a number.
2. CoffeeScript (includes interpreter)
CoffeeScript sees:
# comments
###
multiline comment
###;alert 2# comment
which simply alerts 2.
(Yes, it'd probably be better if another language took this slot, but I'm too lazy to reshuffle at this point :P)
3. Common Lisp | ideone
Common Lisp (clisp) sees:
#|
multiline comment
|#(write(if(= 1/5 .2)26 3))"""
1/5
is a rational and not equal to 0.2
, so 3 is printed. The proceeding """
is a syntax error.
Note that print
seems to output a preceding newline and trailing space in Common Lisp. However, luckily, write
works in both Common Lisp and Chicken Scheme.
4. Retina | Try it online!
Restrictions introduced: Every second line starting from the first needs to be a valid regex.
Every pair of lines form a replacement stage, replacing instances of matches of the first line's regex with the second line. In the middle, we have the pair
"""
which replaces the initial empty string with """
. The final empty line, not part of any pair, is treated as a match stage, counting the number of matches of the regex. There are four instances of empty string in """
, namely 1"2"3"4
.
5. Befunge-93 | Interpreter
Befunge is a 2D language, and the relevant instructions are
# # 15g,@
in the first line, and the 5
in the 25
line. #
skips the next instruction, 15g
gets the char at position (1, 5)
in the code (the 5
in the 25
line), ,
outputs the char and @
halts.
6. Python 2 | ideone
Python sees:
# comments
25
print(4^2 +7)/2
"""
multiline string
"""
(4^2+7)/2 = (xor(4,2)+7)/2 = (6+7)/2 = 13/2 = 6
, which gets print
ed.
7. Rail | Try it online!
Rail is a 2D language, and execution start from the $
of the main function, heading southeast. Thus, the relevant portion of code is
$'main'
7
o
J
with the o
and J
coming from lines used by TRANSCRIPT. After outputting 7, the train hits an unrecognised J
instruction, which crashes the program.
8. ETA | Try it online!
Restrictions introduced: Chars before the ETA program should not be in etaoinsh
.
ETA only recognises the letters etaoinsh
and their uppercase versions, meaning the code starts off with
NSaIeoe
n...e
pushes a base 7 number based on what's within the delimiters, which for SaI
is 624
, or 312 in decimal. o
then outputs as char, apparently after modulo 256, giving the char 8
(code point 56). e
then tries to divide with an empty stack, which fails.
9. Prelude | Try it online!
Restrictions introduced: No more than one of ()
in any column, ()
matched reading a column at a time, no infinite loops caused by ()
.
This requires the Python interpreter to have NUMERIC_OUTPUT = True
set.
Prelude is a language where each line is executed separately. A lot of chars get executed, but the important part is the
9!
on the second line, which outputs 9. ()
in Prelude denote a loop, but thanks to the prominence of #
s (which pop from the stack), the tops of the stacks are always 0 by the time a loop is hit, so none of them are run. Prelude's source code restrictions regarding ()
introduced some extraneous spaces though.
10. Gol><> | Interpreter
This part (and ><>) work like Martin's answer. The relevant code is
# ;n@0ea
Gol><> is a 2D language and #
reflects the IP, making it travel leftwards. It wraps around, push 10, 14 and 0 to the stack. @
then rotates the stack, bringing 10 to the top, n
outputs it and ;
halts the program.
11. evil | Try it online!
This part's also similar to Martin's answer.
evil ignores everything except lowercase letters. Ignoring a few more characters, the relevant part is
aeeeaeeaww
where a
increments the variable A
, e
is evil's weave function which shuffles the bits of A
, and w
outputs A
. Hence we output 1
twice, giving 11
.
But what about the rest of the instructions, and especially that w
on the last line? Let's just say that sometimes it's easiest to just mess with the code and pray it still works in everything which, here, it somehow did...
12. Foo | Try it online!
Foo outputs anything between double quotes, so the relevant part is the
"12"
on the second line. However, since we need double quotes later we use a method similar to Martin's answer to make Foo error out, namely the preceding #-1@
. It's unclear why that works in a language which soldiers on in the face of empty stack and division by zero errors, but I'm glad it does.
13. Ruby | ideone
Like Python, Ruby sees:
# comments
25
print(4^2 +7)/2
"""
multiline string
"""
However, it's worth noting that the multiline string is actually three separate strings (""
, "..."
, ""
) concatenated together. The print line outputs (4^2+7) = xor(4,2)+7 = 6+7 = 13
, before erroring out trying to divide nil
by 2.
14. ><> | Try it online!
This part's the same as the Gol><> part, except @
brings the 14 up to the top instead, which gets outputted.
15. Brian & Chuck | Try it online!
Brian & Chuck is a BF derivative with two tapes, where one tape's instruction pointer is the other tape's memory pointer. In the absence of ```
, the first two lines of the source code are used to initialise the tapes.
The relevant chars in the first two lines are:
?15
# >.>.
The ?
in Brian's tape passes control over to Chuck in the cell being pointed to (the #
) is nonzero. Chuck then executes >.>.
, outputting the two chars after the question mark.
16. Whitespace | Interpreter
Using STL
for space, tab and line feed respectively, the start of the program is:
SSSTSSSSL
TL
STL
L
L
The first line pushes 16 (+10000
base 2), the preceding TLST
prints it as a number. The next three newlines halt the program.
Note, however, that this program is interpreter specific. The rest of the code syntax errors in most interpreters, so a more lenient interpreter is required, like the one linked above.
17. 3var | Try it online!
Of the first line, a slew of instructions get executed, but the relevant ones are
kkmmao#/
Due to ETA's restriction, we use k
to decrement the variable B rather than a
to increment it. kk
decrements B to -2 and mm
squares B twice to 16, which is incremented to 17 with a
. This is then outputted with o
.
#
is then used to reset B to 0, and /
causes the program to error out via division by 0.
18. Axo | Try it online!
Restrictions introduced: No instructions before the Axo program which change the direction of the IP
Once again, a slew of instructions get executed in the first line, but the relevant ones are
# # 15 ,@ 9 9 + { \
Axo is a 2D language like Befunge, and #
is similarly a bridge that skips the next instruction, but only if the top of the stack is zero. 15,
push to the stack, but the stack is emptied with @
. 99+
then pushes 18, {
outputs and \
halts.
19. Labyrinth | Try it online!
Labyrinth is another 2D language, and the executed instructions are
#|#
[9!@
#
pushes the length of the stack, which is 0 the first time. |
is bitwise OR, not changing anything since the stack just has 0s at this point, and the second #
now pushes 1 due to the lone zero. We turn right due to the 1, 9
converts this 1 to 1*10+9 = 19
, !
prints it and @
halts.
This program relies on the fact that [
is not currently a recognised instruction, and hence is treated as a wall.
20. Starry | Try it online!
Restrictions introduced: All +
s must have at least one preceding space
If we strip away unrecognised characters, the relevant part of the code is
, +.. +
,
is input, but since we pipe from /dev/null
there is none, pushing 0 to the stack. A +
with n >= 5
preceding spaces pushes n-5
, so the next instruction pushes 2. ..
then outputs these two digits in reverse order.
Next we have a +
with a single preceding space, which duplicates. However, the stack is empty, so we error out.
21. Fission | Try it online!
The only relevant part for Fission is
*"12"L
L
spawns an atom moving leftward, "21"
prints 21 and *
halts.
22. Brainfuck | Try it online!
Introduced restrictions: No .
before the first [
This requires an interpreter which gives 0 on EOF and has 8-bit cells. The relevant code is
,+-[>.>.-+.>,>]-[>+<-----]>-..
The inital -
is to offset the +
, and the first [...]
is not executed since the cell is 0. The following -[>+<-----]>-
sets the cell to the char code of 2
, and ..
outputs it twice.
23. Julia | Try it online!
Julia sees:
# comments
25
print(4^2 +7)/2
What's printed is 4^2+7 = pow(4,2)+7 = 16+7 = 23
, and the program errors out trying to divide nothing
by 2. Note that Julia doesn't seem to mind the fact that the rest of the code would cause a syntax error anyway.
24. Lily | Interpreter
Lily sees:
# comment
#[
multiline comment
]## comment
print (7/6*24)# comment
7/6*24 = 1*24 = 24
is printed.
25. GolfScript | Try it online!
GolfScript sees:
# comments
25
print(
GolfScript is stack-based, so 25 is pushed to the stack, then popped and printed with print
. (
then tries to decrement the implicit empty string on the stack, which fails and errors out the program.
26. Chicken Scheme | ideone
Chicken Scheme has the same #| ... |#
multiline comment syntax as Common Lisp. However, in
(write(if(= 1/5 .2)26 3))
1/5
is a float which is equal to 0.2
, so 26 is outputted instead.
27. Thue | Try it online!
Thue is a language based on string rewriting. The first relevant part is
f::=~27
::=
which defines a substitution f -> 27
then denotes the end of substitutions with ::=
. The lone f
in if
is then replaced with 27
, which is outputted.
28. Perl 6 | ideone
Perl 6 has a new comment syntax, namely #`(some bracket)
which is a multiline comment all the way to the matching bracket. Thus, Perl 6 sees:
# comments
#`{
multiline comment
}# comment
print (7/6*24)# comment
which prints 7/6*24 = 28
.
29. Picolisp | ideone
Picolisp sees:
# comment
#{
multiline comment
}#(prin 29)
which prints 29. The line afterwards then causes a syntax error.
30. TRANSCRIPT | Try it online!
TRANSCRIPT is a thematic esolang modelled after text adventures. Unrecognised lines are ignored (which allows you to add extra story/flavour text amongst the actual code instructions), so the relevant lines are:
Jo is here.
>Jo, 30
>X Jo
The first line declares a string variable Jo
, using a two-letter name since one-letter names seem to fail. The second line sets this string to "30"
, which is outputted by X
("examine") in the third line.
Python 1.x, 2.x and 3.x, 32 bytes / 3^3 = 1.1851...
import sys
print(sys.version[0])
Prints the first number of the version, which is 1
in Python 1.x, 2
in Python 2.x and 3
in Python 3.x.
By the time we get Python 9.x my score will be a glorious 0.04389
!
:~)!