| Bytes | Lang | Time | Link |
|---|---|---|---|
| 056 | JavaScript V8 | 250401T062026Z | Andrew B |
| 000 | Stuck | 241121T105410Z | ioveri |
| 667 | Python 3 | 241120T102730Z | dingledo |
| 099 | R REPL* | 210803T084150Z | Dominic |
| 051 | MSDOS .COM | 221219T145828Z | l4m2 |
| 242 | !@#$%^&*_+ | 220415T044238Z | Twilight |
| 426 | Python 3 | 210715T130919Z | Jakque |
| 009 | Vyxal | 220215T114927Z | Jakque |
| 040 | ><> | 210803T073434Z | Wheat Wi |
| 038 | Klein 0X1 | 201114T175215Z | Wheat Wi |
| 096 | Befunge | 130418T114801Z | ugoren |
| 122 | Lost | 201114T162643Z | Wheat Wi |
| 071 | 8086 machine code MSDOS .COM | 191215T020030Z | gastropn |
| nan | Unary | 191214T170152Z | Kateba |
| 038 | Gol><> | 170717T163321Z | jimmy230 |
| 045 | Befunge98 | 161214T100142Z | Martin E |
| 063 | Befunge93 | 161217T173548Z | James Ho |
| 000 | Perl | 130418T165732Z | user7486 |
| 007 | J | 130417T212207Z | randomra |
| nan | 130417T202423Z | skeevey |
JavaScript (V8), Score 18, 56 bytes
x="Hello, world!";;print(x.length==13?x:"Hello, world!")
My score is 2 better than what I would have achieved with the naive solution:
print`Hello, world!`
The following shows which shows which characters cannot be removed safely:
x="Hello, world!";;print(x.length==13?x:"Hello, world!")
^^^ ^ ^^^^^^^^ ^^^^ ^^
Stuck, score 0, 0 bytes
Yep, an empty program in Stuck will output Hello, World! to stdout. It's completely fault tolerant because there's no byte to delete from. This answer is inspired by this answer.
Python 3, 667 bytes
__exec=xec=eec=exc=exe=__quit=uit=qit=qut=qui=BBBquit=DDDquit=AA=BB=CC=DD=AAA=BBB=CCC=DDD=fr=""##"
_exec=xec=eec=exc=exe=__=exec
quit__class__=__quit=uit=qit=qut=qui=__=quit
quit._class__=__=quit.__lass__=__=quit.__cass__=__=quit.__clss__=__=quit.__clas__=__=quit.__class_=fr=""##"#"
quit._class__=__=quit.__lass__=__=quit.__cass__=__=quit.__clss__=__=quit.__clas__=__=quit.__class_=__=quit.__class__
quit.__class__.__gt__=_=exec
quit.__class__.__gt__=_=exec
AAA=fr="print('Hello, world!'),exit()#"##"
BBB=fr="print('Hello, world!'),exit()#"##"
CCC=fr="print('Hello, world!'),exit()#"##"
DDD=fr="print('Hello, world!'),exit()#"##"
AAA==BBB<quit
CCC==DDD<quit
The question of whether it was possible to produce a radiation-hardened Hello, World! program in Python was raised in the code.golf discord a few days ago. A challenge too tempting to pass up, I worked on it for a few hours before managing to get a score 0 solution.
Explanation
The fact that function calls require () makes producing a score of 0 quite tricky. This is because getting rid of either the left or right parenthesis will almost certainly result in a SyntaxError. Therefore, the only way to achieve this is to find a way to print without using any brackets.
There are actually several ways to do this. One way is to abuse class decorators:
@print
@lambda _: 'Hello, world!'
class C: pass
Another way is to abuse magic headers to switch to a different encoding:
#coding=u7
+AHAAcgBpAG4AdAAoACIASABlAGwAbABvACwAIAB3AG8AcgBsAGQAIQAiACk
However, neither of these will work because certain characters are impossible to remove without triggering a SyntaxError. There is in fact a third way, that is by overriding the magic method(s) of an existing built-in class:
quit.__class__.__lt__=print
quit<'Hello, World!'
Luckily, this third method is much more radiation-resistant than the previous two. To show this, consider some of the possible locations that a character could be removed:
- Removal of
q,u,iort: For this, we can simply assignqui=qit=qut=uit=quitat the beginning. This then raises the question of how to perform the mentioned assignment without having a character removal of that statement result in an error. I'll mention this later, but for now assume that variable assignment is "free". - Removal of the 1st
.: Like before, we can assignquit__class__=quit.__class__. - Removal of some character in
__class__: we can assignquit._class__and all such variations toquit.__class__. - Removal of the 2nd
.: This doesn't produce an error, but causes a useless attribute to be set. We can "fix" this by doingquit.__class__.__lt__=printtwice - radiation can only affect one of the lines, not the other. - And so on...
That leaves how to actually generate the string, "Hello, World!". This is somewhat tricky, given that removing a quote is very likely to cause a syntax error. There is a very clever way of doing this by abusing comments, which is also utilized in @Jakque's answer:
fr=fr=fr="print('Hello, World!')#"##"
With this construction, a syntax error does not occur no matter where we remove a character. Combining this with the quit trick above and introducing a bunch of redundancy for error correction in a certain way, we can generate a snippet that will print Hello, world! no matter which character is removed:
AAA=fr="print('Hello, world!'),exit()#"##"#"
BBB=fr="print('Hello, world!'),exit()#"##"#"
CCC=fr="print('Hello, world!'),exit()#"##"#"
DDD=fr="print('Hello, world!'),exit()#"##"#"
AAA==BBB<quit
CCC==DDD<quit
Note that we now use exec() instead of print() to print Hello, World!. This is primarily so that we can exit() the program as soon as one of the two branches on the bottom passes. This prevents Hello, World! from executing twice.
Finally, I glossed over the part about variable assignment and how we can do something like qui=qit=qut=uit=quit under the influence of radiation. Notice that radiation doesn't affect this statement at all for everything before the last =; any character removal there simply causes a different (but harmless) variable to be assigned. A slight problem occurs if we try to remove anything after the last =. We can fix this by doing qui=qit=qut=uit=... beforehand, but instead of assigning to quit again, we assign to an empty string:
qui=qit=qut=uit=fr=""##"#"
Python 3, score 0, 412 bytes
Thanks to @orthoplex for saving 209 bytes
Thanks to @biz for saving 46 bytes
__exec=xec=eec=exc=exe=uit=qit=qut=qui=FRquit=rf=""##"
quit__class__=uit=qit=qut=qui=frquit=fr=quit._class__=fr=quit.__lass__=fr=quit.__cass__=fr=quit.__clss__=fr=quit.__clas__=fr=quit.__class_=FR=quit
rexec=xec=eec=exc=exe=fr=quit.__class__.__gt__=__=exec
quit.__class__.__gt__=r=exec
rf=f="print('Hello, world!'),quit()#"##"
fr="print('Hello, world!'),quit()#"##"
rf==fr<quit
FR>"print('Hello, world!')#"##"
After posting my solution, some members on the code.golf discord took an interest and brought the program all the way down to 412 bytes! Improvements welcome :)
R REPL*, 204 137 130 99 bytes, score 0
*(or any other R environment in which errors do not halt execution of subsequent commands: entering the program into the R interactive console works fine; alternatively (and as simulated in the TIO link) we can use the command-line option -e 'options(error=function(){})' (which would then define the language as "R -e 'options(error=function(){})'").
a="Hello, world!"##"
b="Hello, world!"##"
T=cat(`if`(exists("a")&&(nchar(a)==13),a,b));
if(T)cat(a)
Explanation:
Lines 1 & 2:
At least one of a or b should contain the text "Hello, world!" even if any character is deleted:
- any deletion inside one quoted string shouldn't affect the other;
- deletion of any of
a="will simply error without assigninga(or the same forb); - deletion of the second
"will assign ```"Hello, world!##"```` to that string without affecting the other; - deletion of any of
##"has no effect; - deletion of the first newline will convert the following line into a comment and prevent assignment of
b, without affectinga; - deletion of the second newline will convert the following line into a comment, without affecting either
aorb(see line 3 below).
Line 3:
Aims to output one of a or b that exists and is the correct, 13-character "Hello, world!" string, or to error.
If it succeeds without erroring, the variable T is re-assigned to NULL (instead of its default value of TRUE).
- deletion of any of
T=,cat(),`if`(,,b),exists("a"), ornchar(a)==will error and fail to re-assignT. - deletion of any of
13will selectbinstead ofato output; however, since this was the single deletion made,bis intact so this is Ok. - deletion of either
;or the third newline has no effect; - if the entire line is commented-out (by deletion of the second newline), it will not re-assign
T.
Line 4:
If T is not NULL, then either an error has occurred (so the deletion was on line 3), or the second newline was deleted (so line 3 was commented-out).
In either case a should be the correct "Hello, world!" string, and nothing has yet been output, so we can safely output a.
Any deletion to this line should cause an error so that it doesn't output anything to stdout.
- deletion of any of
if(T)will error; - if
TisNULL(so no error has yet occurred, and line 3 ran Ok),if(T)will error and this line will not output anything. - if
Tis stillTRUE, then the single deletion already happened on another line, so we shouldn't need to worry about further deletions on this line.
MSDOS .COM, 51 bytes
00000000: eb18 18e8 0e00 4865 6c6c 6f2c 2057 6f72 ......Hello, Wor
00000010: 6c64 2124 b409 5acd 21c3 ebe7 e7b4 09ba ld!$..Z.!.......
00000020: 2401 cd21 c348 656c 6c6f 2c20 576f 726c $..!.Hello, Worl
00000030: 6421 24 d!$
org 100h
jmp .L2 ; SBB [BX+SI],BL if 1B removed
db .L2-$
.L0:call .L1
db "Hello, World!$"
.L1:mov ah, 9
pop dx
int 0x21
ret
db 0x11A-$ dup ? ; Actually none
.L2:jmp .L0 ; OUT E7, AX if 1B removed
db .L0-$
mov ah, 9
mov dx, .L3-1 ; If it goes this way
int 0x21 ; then 1 byte missing
ret
.L3:db "Hello, World!$"
gastropner suggests me do this
Collection of all programs with at most 1 byte removed in base64, confirmed
/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4NX/AgVdACCLvBunjDQGwDuQeO2LBXimvB64zX4rztWL/i5Av150lJoeOSHW05X92oDP65IyBlb67MdiB3tAoqaEfRm3gzRuAXuwZhHgJsxZs0QpbeW6y0O+IUD3a6M3dV4n+YbVbdSu8MWbR9qg76ck36pl5sy9kzvUv9hcAczs00fsjGJS10OdrU6sDxTIOpMk13Z+WxChUK04r19vxvShWbKDb2pZawGxFVJ2Sks0JvZNOJExJQx8l0fa6sSqQtOJR4oWVmOf/lePTc/ZDE3pz2nVPYgxQeLN31fGGeoso1JwWvr3sDyL6v49m2ZR9y0fVwc/nactXKMTJLzKmxSuwq6azF2f6ddf+0OL5fgVgccV5M1P9lQ6WV+sp80RWo1ceO8OJWmvIGM3ZTcl7ZcYqWUxQyvqAp0aL9ZDvXJhnybKXDSKOhzjtLcKM/07aCsVmBe5hZwllSnjiAOwKeH/8KyP/Uxfwl0xO5zyWshxWa0Znji7HAQH9ais1UHVHAP9P9EQF+g0rU5WehexGtrRg74lGF9/hUSepXTZZAZLpMURXJC9zlhkAj7xKsL3Lmm/yNZyETgDiZMB2kD/k3js5jDnmAZjU15KkYHpuNVsjsFcP6ERVipU4b3WRGCjsMgzbTcN1naVFUNOWXLGcvdY2Y5o2Wf2+TMTD275J51Db4aNUX8rIRd3NUwAAAAASNVP9/NyC/kAAaEEgKwDAKrxg/KxxGf7AgAAAAAEWVo=
!@#$%^&*()_+, score 2, 242 bytes
!!!!!!!!!!!!!! ^!!!!!!!!!!!!!ddddddddddddddllllllllllllllrrrrrrrrrrrrrrooooooooooooooWWWWWWWWWWWWWW ,,,,,,,,,,,,,,oooooooooooooolllllllllllllllllllllllllllleeeeeeeeeeeeeeHHHHHHHHHHHHHH(((@%%%%%%%%%%%%%%))üü&& ^dlroW ,olleH((@)
Well, I give up.
I'm on a mobile phone, so I cannot put the null character there. If someone would be so kind to replace the !!_+ in the TIO link, I would appreciate it. The two weaknesses are the ^ between the exclamation marks.
This is not particularly clever, and most of the characters are just padding. Contains two Unicode characters; the challenge specifications said remove one character, not one byte.
The HW is repeated 14 times to be immune to % removal or removal in the HW string. !@#$%^&*()_+ allow unmatched ( but not unmatched ) when parsing, so the left parenthesis is repeated one more time than the right parenthesis.
What if the @ was removed? We can know from the stack size if 13 characters went missing, so we use stack indexing to exit by error if the stack size is too short. Each character is doubled to make sure the test is performed. If the test passed, it means the @ is the removed character, and none of the characters after the test was removed, so you can put a normal Hello, World program there.
I made this one bored afternoon at school with a pencil, but I did not have time to debug and post this until now. Bugs might still be present.
Python 3, score = 6 4, 454 426 bytes
xec=eec=exc=exe=exeexec=rint=pint=prnt=prit=prin=ppprint=hhh=hh=hhh=fr=""""pp(fr[1::2]) rrr________:__"ii______p____;nn____p______ptt__(________p(( __________(ff__________rfrr________[__r[[______1____[11____:______1::__:________:22 __________:66__________-2::________4__]22______]____)]]____)______ ))"""##"""
xec=eec=exc=exe=exec
pp=print
fr=fr=fr=""""HHeelllloo,, wwoorrlldd!!"""##"""
exec(hhh[1::2++2++2++2++2++2++2++00])
The undeletable char are parenthesis for the exec function and the brackets.
How it works:
hhh=hh=hhh=fr=...initialize the main code and stor it inhhhxec=...=ppprint=...initialize all possibe deletion ofexecandprintto avoid a futureNameErrorxec=eec=exc=exe=execensure thatexec(with possible deletions) is well definedfr=fr=fr=""""HHeelllloo,, wwoorrlldd!!"""##"""store infrthe stringHello, world!but doubled to keep the information even with a deletionthe last slice can be equal to either
[1::14],[::14],[1:14]or[1::12]. Both of them slice the main code to have respectivelyprint(fr[1:26:2]),"r";pp(fr[1::2]),pp(fr[1::2])orp :pp( fr[1:: 6-4])
Thanks to @Jo King♦ for pointing me my errors, helping me to solve them and helped me to golf the result
Vyxal, 9 bytes, score 0
kH0kH ∴¡¡
Explanation :
# unaltered
kH # push 'Hello, World!' => [ Hello, World! ]
0 # push 0 => [ Hello, World! , 0 ]
kH # push 'Hello, World!' => [ Hello, World! , 0 , Hello, World! ]
∴ # max(a,b) => [ Hello, World! , Hello, World! ]
¡¡ # sentence case (twice) => [ Hello, World! , Hello, world! ]
# implicit output
# 1st char missing
H # convert to hex => [ 0 ]
0 # Push 0 => [ 0 , 0 ]
kH # push 'Hello, World!' => [ 0 , 0 , Hello, World! ]
∴¡¡ # max and sentence case => [ 0 , Hello, world! ]
# 2nd char missing
k0 # do nothing => [ ]
kH # push 'Hello, World!' => [ Hello, World! ]
∴¡¡ # max and sentence case => [ Hello, world! ]
# 3nd char missing
kH # push 'Hello, World!' => [ Hello, World! ]
kH # push 'Hello, World!' => [ Hello, World! , Hello, World! ]
∴¡¡ # max and sentence case => [ Hello, world! ]
# 4th char missing
kH # push 'Hello, World!' => [ Hello, World! ]
0 # push 0 => [ Hello, World! , 0 ]
H # convert to hex => [ Hello, World! , 0 ]
∴¡¡ # max and sentence case => [ Hello, world! ]
# 5th char missing
kH # push 'Hello, World!' => [ Hello, World! ]
0 # push 0 => [ Hello, World! , 0 ]
k # do nothing => [ Hello, World! , 0 ]
∴¡¡ # max and sentence case => [ Hello, world! ]
# 6th same as unaltered
# 7th char missing
kH # push 'Hello, World!' => [ Hello, World! ]
0 # push 0 => [ Hello, World! , 0 ]
kH # push 'Hello, World!' => [ Hello, World! , 0 , Hello, World! ]
¡¡ # sentence case (twice) => [ Hello, World! , 0 , Hello, world! ]
# 8th or 9th char missing same as unaltered but sentence case only once
Fun fact, the char 0 can be replaced by any of $123456789₀₄₆₇₈Ȯ (and maybe some more) and the program is still a solution
><>, score 0, 40 bytes
||o<"Hello, world!"\
|o<"Hello, world!"\
This is a port of my klein 000 answer. It's a little more costly to output in ><>, but overall this is nicely competitive. This halts by triggering an error, as suggested by JoKing. For my original version that exits properly:
><>, score 0, 54 bytes
||>!;!?o!l<"Hello, world!"\
|>!;!?o!l<"Hello, world!"\
Klein 0X1, score 0, 38 bytes
Works in both 011 (real projective plane) and 001 (Klein bottle)
//
@"!dlrow ,olleH"<
@"!dlrow ,olleH"<
This reflects the ip over the top of the program. The geometry causes the ip to reenter the program on the opposite end of the program. This makes it a lot shorter than the traditional method which requires a full length line to reach the right side of the program.
000, score 0, 38 bytes
<<@"!dlrow ,olleH"/
<@"!dlrow ,olleH"/
1X1 or 20X, score 0, 39 bytes
Works in 101, 111, 200, and 201
..
@"!dlrow ,olleH"<
@"!dlrow ,olleH"<
Due to the longstanding bug that spaces are trimmed off the front of Klein programs two .s are needed to make this work. If it were not for this bug the 37 byte program:
@"!dlrow ,olleH"<
@"!dlrow ,olleH"<
world work in all of these geometries.
The idea here is that we choose a geometry that naturally reaches the location we want and clear its way. Particularly we want geometries that connect the east edge to either the north or south edges with the proper twisting so that the ip leaving the east edge enters on the right side of the program. There are 4 of these.
0X0, score 0, 40 bytes
Works in both 000 (torus) and 010 (Klein bottle)
||@"!dlrow ,olleH"./
..@"!dlrow ,olleH"/
1X1, 20X, 210, or 101, score 0, 43 bytes
Works in 101, 111, 200, 201, 210, and 101
..
@"!dlrow ,olleH"<
@"!dlrow ,olleH"<
A modified version of the above where we move the @s out of the path so that 210 and 101 work. Once again .. is required due to a bug and could be removed for a 2 byte save if the bug were fixed.
XXX, score 0, 54 bytes
Works in every geometry
. \\
@"!dlrow ,olleH"<
@"!dlrow ,olleH"<
Befunge, Score 0, 96 bytes
I think I cracked it - no single character deletion will change the output.
Deleting any character from line 1 changes nothing - it still goes down at the same place.
Lines 2 and 3 are redundant. Normally line 2 is executed, but if you delete a character from it, the < is missed, and line 3 takes charge.
Deleting newlines doesn't break it either (it did break my previous version).
No test program, sorry.
EDIT: simplified a lot.
vv
@,,,,,,,,,,,,,"Hello, world!"<<
@,,,,,,,,,,,,,"Hello, world!"<<
A short explanation of the flow:
- Befunge starts executing from top-left, moving right. Spaces do nothing.
vturns the execution flow downward, so it goes down one line.<turns the execution flow left, so it reads line 2 in reversed order."Hello, world!"pushes the string to the stack. It's pushed in reversed order, because we're executing right to left.,pops a character and prints it. The last character pushed is printed first, which reverses the string once more.@terminates the program.
Lost, Score 0, 122 bytes
>>>>>>>>>>>>>%%/>>>>>>>>>>/
\\
>>>>>>>>>>>>>//>>>>>>>>>>>\\
//
/@+-( "vUvdlrow ,olleH"?<<
///
/@+-("vUvdlrow ,olleH"? <<<
It never stops amazing me that radiation-hardening are possible in Lost.
If you haven't seen Lost before it is a 2-D programming language in which instead of starting execution at a fixed location it chooses a random location and direction and starts there. This makes writing any lost program a bit of a radiation hardening challenge normally, since a program must work from every start location. But now we layer on radiation-hardening too and every program must work from every start location. With 122 bytes, four directions and a 28 by 6 bounding box, this means there are approximately 80,000 different programs that must be work.
This program is built with a mix of standard lost methods and standard radiation hardening methods. To start here is the normal Hello World for lost:
v<<<<<<<<<<>>>>>>>>>>>
>%?"Hello, worldvU"-+@
It is comprised of a "collector" which gathers all the stray instruction pointers and points them to the beginning of the actual program.
v<<<<<<<<<<>>>>>>>>>>>
> v
A more detailed explanation of how this program works can be found here.
Now we want to modify this program to use the duplicate alignment method of radiation hardening. This method works by having two copies of the desired code and entering them from the end of the line.
>>>>>>>>>vv
program <
program <
This way when on of the programs is edited it becomes misaligned and the other one is executed
>>>>>>>>>vv
progam <
program <
To do this with our lost program is pretty simple:
>>>>>>>>>>>>>>>>>>>>>\\
@+-"Uvdlrow ,olleH"?%<
@+-"Uvdlrow ,olleH"?%<
However there are some problems with this. The alignment of the "s is an issue because it causes infinite loops (in the example above there are basically two strings ">" lain out vertically, so if you start on the quotes going in the right direction you just push the > character endlessly). So you need to make sure the quotes don't line up even when a character has been deleted.
>>>>>>>>>>>>>>>>>>>>>>>\\
@+- "Uvdlrow ,olleH"?%<
@+-"Uvdlrow ,olleH"?% <
Also since v is needed to escape the inside of the string it's deletion is potentially a problem. So we need a backup.
>>>>>>>>>>>>>>>>>>>>>>>>>\\
@+-( "vUvdlrow ,olleH"?%<
@+-("vUvdlrow ,olleH"?% <
Now while alignment prevents most pointers from entering the wrong program, if we delete a non-critical character from a program, e.g.
>>>>>>>>>>>>>>>>>>>>>>>>>\\
@+-( "vUvdlrow ,olle"?%<
@+-("vUvdlrow ,olleH"?% <
Then if execution starts on the % it doesn't need to care about the alignment at all and it will just execute the bad program. So we need to move % before the alignment
>>>>>>>>>>>>>>>>>>>>>>%%\\
@+-( "vUvdlrow ,olleH"?<
@+-("vUvdlrow ,olleH"? <
Now another line of collector is needed to fill the gap we made by adding non-redirecting characters to our collector (%s).
>>>>>>>>>>>>>>%%/>>>>>>>/
>>>>>>>>>>>>>>//>>>>>>>>\\
@+-( "vUvdlrow ,olleH"?<
@+-("vUvdlrow ,olleH"? <
(Some small changes are glossed over here mainly just edge casey nonsense)
Now we have to worry about what happens when a newline is deleted. This would normally be ok because the alignment doubling strategy works for these, however for us it opens the door to a lot of potential infinite loops for example in the program:
>>>>>>>>>>>>>>%%/>>>>>>>/
>>>>>>>>>>>>>>//>>>>>>>>\\@+-( "vUvdlrow ,olleH"?<
@+-("vUvdlrow ,olleH"? <
we now have a bunch of columns with no redirecting characters on them, so pointers starting there can just loop up or down endlessly.
The trick we use here is to add (nearly) blank lines so that deleting a newline doesn't smash two big lines together.
>>>>>>>>>>>>>>%%/>>>>>>>/
>>>>>>>>>>>>>>//>>>>>>>>\\
@+-( "vUvdlrow ,olleH"?<
@+-("vUvdlrow ,olleH"? <
So if we delete a newline:
>>>>>>>>>>>>>>%%/>>>>>>>/
>>>>>>>>>>>>>>//>>>>>>>>\\
@+-( "vUvdlrow ,olleH"?<
@+-("vUvdlrow ,olleH"? <
Nothing fundamentally changed about our program. However these lines can't be completely blank as it leaves the door open for infinite loops. In fact they need to have at least two (because one could be deleted) redirecting characters.
>>>>>>>>>>>>>>%%/>>>>>>>/
//
>>>>>>>>>>>>>>//>>>>>>>>\\
//
@+-( "vUvdlrow ,olleH"?<
//
@+-("vUvdlrow ,olleH"? <
Now if we delete the last newline our quotes align again:
>>>>>>>>>>>>>>%%/>>>>>>>/
//
>>>>>>>>>>>>>>//>>>>>>>>\\
//
@+-( "vUvdlrow ,olleH"?<
//@+-("vUvdlrow ,olleH"? <
Which is no good so we use 3 characters on the 3rd filler line:
>>>>>>>>>>>>>>%%/>>>>>>>/
//
>>>>>>>>>>>>>>//>>>>>>>>\\
//
@+-( "vUvdlrow ,olleH"?<
///
@+-("vUvdlrow ,olleH"? <
From here we arrive at the final program with just some minor fiddling. Iteratively fixing and finding mistakes. I've covered everything I think is interesting, but if you are interested in exactly why this or that just leave a commend and I will add it to the explanation.
8086 machine code (MS-DOS .COM), 71 bytes, score = 0
Slight variation on previous answers on the same theme.
In binary form:
00000000 : EB 28 28 E8 00 00 5A 83 C2 09 B4 09 CD 21 C3 48 : .((...Z......!.H
00000010 : 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 24 90 90 90 : ello, World!$...
00000020 : 90 90 90 90 90 90 90 90 90 90 EB D7 D7 E8 00 00 : ................
00000030 : 5A 83 C2 09 B4 09 CD 21 C3 48 65 6C 6C 6F 2C 20 : Z......!.Hello,
00000040 : 57 6F 72 6C 64 21 24 : World!$
In readable form (NASM syntax):
cpu 8086
org 0x100
%macro CODEPART 0
call near .nextline
.nextline:
pop dx
add dx, 0x09
mov ah, 0x09
int 0x21
ret
.msg db "Hello, World!$"
%endmacro
jump1:
jmp jump2
db 0x28
part1:
CODEPART
filler:
times 13 db 0x90
jump2:
jmp part1
db 0xd7
part2:
CODEPART
Rundown
The active part is duplicated so that there is always one untouched by radiation. We select the healthy version by way of jumps. Each jump is a short jump, and so is only two bytes long, where the second byte is the displacement (i.e. distance to jump, with sign determining direction).
We can divide the code into four parts which could be irradiated: jump 1, code 1, jump 2, and code 2. The idea is to make sure a clean code part is always used. If one of the code parts is irradiated, the other must be chosen, but if one of the jumps is irradiated, both code parts will be clean, so it will not matter which one is chosen.
The reason for having two jump parts is to detect irradiation in the first part by jumping over it. If the first code part is irradiated, it means we will arrive one byte off the mark. If we make sure that such a botched landing selects code 2, and a proper landing selects code 1, we're golden.
For both jumps, we duplicate the displacement byte, making each jump part 3 bytes long. This ensures that irradiation in one of the two last bytes will still make the jump valid. Irradiation in the first byte will stop the jump from happening at all, since the last two bytes will form a completely different instruction.
Take the first jump:
EB 28 28 jmp +0x28 / db 0x28
If either of the 0x28 bytes are removed, it will still jump to the same place. If the 0xEB byte is removed, we will instead end up with
28 28 sub [bx + si], ch
which is a benign instruction on MS-DOS (other flavours might disagree), and then we fall through to code 1, which must be clean, since the damage was in jump 1.
If the jump is taken, we land at the second jump:
EB D7 D7 jmp -0x29 / db 0xd7
If this byte sequence is intact, and we land right on the mark, that means that code 1 was clean, and this instruction jumps back to that part. The duplicated displacement byte guarantees this, even if it is one of these displacement bytes that were damaged. If we either land one byte off (because of a damaged code 1 or jump 1) or the 0xEB byte is the damaged one, the two remaining bytes will also here be benign:
D7 D7 xlatb / xlatb
Whichever the case, if we end up executing those two instructions, we know that either jump 1, code 1, or jump 2 were irradiated, which makes a fall-through to code 2 safe.
Testing
The following program takes the COM filename as an argument, and creates all variants of it, along with a file called tester.bat. When run in DOS, this BAT file will run each of the created binaries, redirecting the outputs into one text file per program.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fin, *fout, *fbat;
int fsize;
char *data;
if (!(fin = fopen(argv[1], "rb")))
{
fprintf(stderr, "Could not open input file \"%s\".\n", argv[1]);
exit(1);
}
if (!(fbat = fopen("tester.bat", "w")))
{
fprintf(stderr, "Could not create BAT test file.\n");
exit(2);
}
fseek(fin, 0L, SEEK_END);
fsize = ftell(fin);
fseek(fin, 0L, SEEK_SET);
if (!(data = malloc(fsize)))
{
fprintf(stderr, "Could not allocate memory.\n");
exit(3);
}
fread(data, 1, fsize, fin);
fprintf(fbat, "@echo off\n");
for (int i = 0; i < fsize; i++)
{
char fname[512];
sprintf(fname, "%02d.com", i);
fprintf(fbat, "%s > %02d.txt\n", fname, i);
fout = fopen(fname, "wb");
fwrite(data, 1, i, fout);
fwrite(data + i + 1, 1, fsize - i - 1, fout);
fclose(fout);
}
free(data);
fclose(fin);
fclose(fbat);
}
DOSBox, where I tested this, does not have the fc command, so another BAT file was created to run under Windows. It compares each text file with the first one to make sure they are all identical:
@echo off
for %%x in (*.txt) do (
fc %%x 00.txt > nul
if ERRORLEVEL 1 echo Failed: %%x
)
Ocular inspection of one of the text files is still needed.
Unary, score 0, 74817134662624094502265949627214372599829 bytes
The code is not included due to post length limitations, but it consists of 74817134662624094502265949627214372599829 zeros.
If any of these zeros is removed, the resulting brainfuck program is KSab's hello world program.
Sadly, I didn't get the job because my machine had only 500 GB of hard disk space.
Gol><>, score 0, 38 bytes
<<H"Hello, world!"/
H"Hello, world!" <
The language is released after the challenge.
Befunge-98, score 0, 45 bytes
20020xx""!!ddllrrooww ,,oolllleeHH""cckk,,@@
Although an optimal solution has already been found (and there's no tie breaker), I thought I'd show that this can be simplified considerably with Befunge 98.
Explanation
The 20020xx reliably sets the delta (the steps of the instruction pointer between ticks) to (2,0) so that starting at the first x, only every other command is executed. See this answer for a detailed explanation of why this works. Afterwards, the code is merely:
"!dlrow ,olleH"ck,@
We first push all the relevant character codes onto the stack with "!dlrow ,olleH". Then ck, means print the top of the stack (,), 13 (c plus 1) times (k). @ terminates the program.
Befunge-93, Score 0 (63 bytes)
I know this isn't a code-golf challenge, but I thought it would be interesting to see if the existing Befunge-93 solution could be improved upon in terms of size. I had originally developed this technique for use in the similar Error 404 challenge, but the need for a wrapping payload in that case made the 3 line solution more optimal.
This isn't quite as good as Martin's Befunge-98 answer, but it's still a fairly significant reduction on the winning Befunge-93 solution.
<>> "!dlrow ,olleH">:#,_@ vv
^^@_,#!>#:<"Hello, world!"<<>#
Explanation
There are two versions of the payload. For an unaltered program, the first < causes the program to execute right to left, wrapping around to the end of the line, until it reaches a v directing it down to the second line, and a < directing it left into the left-to-right version of the payload.
An error on the second line causes the final < to be shifted left and replaced with a > directing the flow right instead. The # (bridge) command has nothing to jump over, so the code just continues until it wraps around and reaches a ^ at the start of the line, directing it up to the first line, and then a > directing it right into the right-to-left payload.
Most errors on the first line just cause the final v commands to shift across by one, but that doesn't alter the main flow of the code. Deleting the first < is slightly different, though - in that case the execution path just flows directly into the left-to-right payload on the first line.
The other special case is the removal of the line break. When the code wraps around to the end of the line, in this case it's now the end of the what used to be the second line. When it encounters the # command from the right, this jumps over the > and thus continues directly into the right-to-left payload.
In case there's any doubt, I've also tested with the perl script and it confirmed that "0 failed out of 63".
Perl, Score 0
(147 characters)
Here is my solution, which I managed to get from 4 down to 0:
eval +qq(;\$_="Hello, world!";;*a=print()if length==13or!m/./#)||
+eval +qq(;\$_="Hello, world!";;print()if*a!~/1/||!m/./#)##)||
print"Hello, world!"
It must appear all on one line to work; line breaks are for "readability" only.
It benefits from Perl's pathologically permissive syntax. Some highlights:
- Barewords that are not recognized are treated as strings. So when
evalbecomesevl, that is not an error if a string is permissible at that point. - Unary
+operator, which does nothing other than disambiguate syntax in certain situations. This is useful with the above, becausefunction +argument(where + is unary) becomesstring + argument(addition) when a function name is mangled and becomes a string. - Many ways to declare strings: a double quoted string
qq( )can become a single-quoted stringq(); a string delimited by parenthesesqq(; ... )can become a string delimited by a semicolonqq; ... ;.#inside strings can eliminate balancing issues by converting things to comments.
The length of this can probably be reduced somewhat, though I doubt ugoren's solution can be beaten.
J, 7 points
Selecting every letter with odd position:
_2{.\'HHeellllo,, wwoorrlldd!!'
Hello, world!
HQ9+
This will never fail to produce the intended result when a character is deleted so gets a score of zero.
HH
When do I start?