32
\$\begingroup\$

The task here is pretty simple. You should write a program that takes a string as input and outputs it (that is a cat program).

Additionally when the \$n\$th byte of your program is removed (without replacement) the augmented program should take a string as input and remove the \$n\$th character. If the input to your augmented program is less than \$n\$ characters long it should return it as is. For example the python program

x = input()
if "y" == "y":
  print(x)
else:
  print(x[:16] + x[17:])

Try it online!

will remove the \$17\$th character if its \$17\$th byte is removed (the first y).

Scoring

Your answer's score will be the number of bytes for which removal does not cause the program to remove the corresponding byte. With better score being lower.

In our example above the total length is 68 bytes, with one byte (the \$16\$th one) augmenting the program correctly. That leaves a score of 67 bytes.

If the program were modfied to work in two places like so:

x=input()
u="az"
if u!="az":x=x[:13+(u<"c")]+x[14+(u<"c"):]
print(x)

Try it online!

Where removing the \$14\$th and \$15\$th characters (a and z) work properly. The score is 66 bytes or 68 - 2, since the program is 68 bytes long but two of those bytes work properly.

Rules and clarifications

  • There must be at least one byte which can be removed that causes the program to remove the corresponding character in the input. This means a cat program on its own is not a valid submission.

  • Only one byte will be removed at a time. You do not have to worry about what happens when multiple bytes are removed from your program at the same time.

  • You should support strings using printable ascii characters in addition to all characters that appear in your program itself. Input containing anything else is undefined behavior.

\$\endgroup\$
10
  • \$\begingroup\$ May we work on arrays of characters instead of strings? (For languages for which it's not the same thing.) \$\endgroup\$
    – Arnauld
    Dec 14, 2019 at 16:33
  • 4
    \$\begingroup\$ @Arnauld This challenge asks for a complete program, I chose this because I feel that source layout doesn't play very nicely with functions. As a result I am pretty sure that input will have to be taken as a string. \$\endgroup\$
    – Wheat Wizard
    Dec 14, 2019 at 16:35
  • \$\begingroup\$ In your example you set u='az' and depending on those characters the input gets trimmed, so instead of using characters can we use index like 2,3 etc...? \$\endgroup\$
    – game0ver
    Dec 14, 2019 at 16:45
  • \$\begingroup\$ @game0ver Your code can be any sequence of bytes, the process is agnostic to what the code is doing. You could set u=8, but I'm not sure why you would want to, if either the 8 or the u is removed then the program will error. \$\endgroup\$
    – Wheat Wizard
    Dec 14, 2019 at 16:48
  • \$\begingroup\$ Is it OK if the output includes extra non-printable characters (e.g. null bytes)? \$\endgroup\$ Dec 15, 2019 at 20:49

22 Answers 22

24
\$\begingroup\$

Python 2, score:  56 50  48 bytes - 6 = 42

This is more an attempt to allow to remove more than 1 or 2 characters than to achieve the lowest possible score. Given the scoring scheme, allowing one more byte to be removed this way would cost at least one extra byte, leaving the score unchanged at best.

You may remove the 3rd to the 8th character, i.e. any digit of \$545454\$.

n=545454;x=input();print x[:n%11]+x[n%11+n%9/4:]

Try it online!

How?

Removing the \$n\$th digit from \$545454\$ and applying a modulo \$11\$ results in \$n+1\$. Applying a modulo \$9\$ instead allows to figure out whether the number was changed or not.

 pattern |    x   | x mod 9 | x mod 11
---------+--------+---------+----------
  545454 | 545454 |    0    |   (8)
  _45454 |  45454 |    4    |    2
  5_5454 |  55454 |    5    |    3
  54_454 |  54454 |    4    |    4
  545_54 |  54554 |    5    |    5
  5454_4 |  54544 |    4    |    6
  54545_ |  54545 |    5    |    7
\$\endgroup\$
0
20
\$\begingroup\$

><>, 584 bytes, score 0

<|0!o? !@ !: !@ !: !- !1$ !i|!? !: !+ !@ !@ !- !) !* !e !e$ !* !+1+ !@ !( !3 !@ !* !* !d !f !: !+ !* !2 !$ != !g !2 !$ !@ != !g !1 !$ !@ !: !g !0 !: !: !: !: !:<0~!?g1*e e-10 ~!?g0-$0:-*e e0 0</
<|0!o? !@ !: !@ !: !- !1$ !i|!? !: !+ !@ !@ !- !) !* !e !e$ !* !+1+ !@ !( !3 !@ !* !* !d !f !: !+ !* !2 !$ != !g !2 !$ !@ != !g !1 !$ !@ !: !g !0 !: !: !: !: !:<0~!?g1*e e-10 ~!?g0-$0:-*e e0 0</
<|0!o? !@ !: !@ !: !- !1$ !i|!? !: !+ !@ !@ !- !) !* !e !e$ !* !+1+ !@ !( !3 !@ !* !* !d !f !: !+ !* !2 !$ != !g !2 !$ !@ != !g !1 !$ !@ !: !g !0 !: !: !: !: !:<0~!?g1*e e-10 ~!?g0-$0:-*e e0 0</

Try it online! Verification of perfect score (note times out)

The first zero score program. This is achieved by having three copies of the program on separate lines, with only non-irradiated versions being executed. The program checks for outliers (like newlines being removed), then checks each character to see if it is the same for all three lines. If one is different, we determine which line it is and offset the current index by a multiple of 195 (the length of each line). After determining which byte is irradiated (with no byte being -1 and the first byte being 1), we enter the output loop, decrementing the counter each time we output a character. When the counter hits zero, we skip that character, but don't reset the counter so it can be proven that only one byte of input is removed when the program is irradiated, and none when it is not.

The TIO link above has the program itself in the input, so it is easy to fiddle about in yourself. Simply try removing a byte from the program itself and the same byte will be removed from the output.

It shouldn't be too hard to golf, especially the loop in the middle that's just 60% no-ops, though I just want to post it since it is actually working and this isn't actually .

\$\endgroup\$
14
\$\begingroup\$

sed, Perl 5 -p, Perl 6 -p, 6 bytes, score 5

#s/.//

Try it online!

Works as sed, Perl 5 and Perl 6 program. The 1st byte is removable.

\$\endgroup\$
0
10
\$\begingroup\$

Jelly, 2 bytes, score = 1

ḷḊ

Try it online!

A full program that takes a string and prints a string. When the first byte is removed, removes the first byte of the input.

Achieving a lower score would mean finding a solution where removing any byte leads to the corresponding byte being removed from the string, which I think will be challenging.

Explanation

ḷ  | Left argument of input string and:
 Ḋ | - Input string with first byte removed

With first byte removed:

Ḋ | Remove first byte
\$\endgroup\$
7
\$\begingroup\$

Brainfuck, 11 bytes, score = 10

-+[,>],[.,]

Try it online!

Explanation

-+[,>]   This does nothing.
,[.,]    This reads and outputs the user's input until the program ends.

With first byte removed:

+[,>]    Reads the first character of user input, then 'discards' it by moving to a different cell.
,[.,]    This reads and outputs the user's input until the program ends.
\$\endgroup\$
0
5
\$\begingroup\$

R, 93 bytes, score=87

T<-3.5->T;s=utf8ToInt(scan(,""));if(i<-match(2*T,c(0,-5,2,1,70,6,0,5),0))s=s[-i];intToUtf8(s)

Try it online!

Like Arnauld, I tried to get a few deletable bytes rather than optimize the score, and also to use different tricks depending on the byte removed. Characters 2, 3, 4, 5, 6 and 8 can be removed.

In the unaltered version, the code makes two attempts to assign a value to T, using both leftwards <- and rightwards -> assignment. Since T is initialized as 1 (when coerced to integer), it can be assigned 7 different values, depending on the byte removed:

  • T<-3.5->T leads to T=3.5
  • T-3.5->T leads to T=1-3.5=2.5
  • T<3.5->T leads to T=1, since 1<3.5 is true (the same would occur if we removed byte 7 - I searched for a way to have different behaviours when removing bytes 3 and 7 but couldn't manage)
  • T<-.5->T leads to T=.5
  • T<-35->T leads to T=35
  • T<-3.->T leads to T=3.
  • T<-3.5-T leads to T=3.5-1=2.5

The statement with if and match then removes the relevant character. The rest is the usual fluff required whenever R has to handle strings.


It is obviously possible to make the number 3.5 longer (e.g. 43.5) and be allowed to remove the corresponding characters. For the sake of it, here is a different way of getting more removable characters:

R, 120 bytes, score=112

T<-3.5->T;s=utf8ToInt(scan(,""));if(i<-match(T+T,c(0,-5,2,1,70,6,0,5,rep(0,37),3.5,rep(0,47),-7),0))s=s[-i];intToUtf8(s)

Try it online!

In addition to the characters listed above, bytes 46 and 94 can be removed:

  • byte 46: the first T in T+T becomes +T, which matches 3.5
  • byte 94: -7 becomes 7, which then matches T+T=7.
\$\endgroup\$
5
\$\begingroup\$

05AB1E, score 2, 3 bytes

D¦r

Look ma, (sort of) no unicode!

The character to remove is the first one.

Try it online

Explanation:

D  push two copies of the input onto the stack
¦  remove the first character from the string on top of the stack. Alternatively, if D is removed, push the input with its first character removed onto the stack.
r  reverse the stack
implicitly, output the top of the stack
\$\endgroup\$
4
  • 4
    \$\begingroup\$ The language's name is 05AB1E, not O5AB1E. Also, the second character is ¦, not ASCII |, so it's not really "no unicode". \$\endgroup\$
    – Grimmy
    Dec 16, 2019 at 12:42
  • \$\begingroup\$ @Grimmy thanks, I didn't notice. Since broken pipe is in many of the small extended ascii encodings, I think it sorta counts as "no unicode", maybe? \$\endgroup\$
    – acupoftea
    Dec 16, 2019 at 17:25
  • 1
    \$\begingroup\$ Technically every golfing language with a SBCS is "no unicode", since they have their own encodings. \$\endgroup\$
    – Jo King
    Dec 18, 2019 at 9:38
  • \$\begingroup\$ Technically the 05AB1E codepage is a subtle extension of extended ASCII. \$\endgroup\$
    – user85052
    Dec 18, 2019 at 10:56
5
\$\begingroup\$

Haskell, 31 - 1 = 30

Removing the first byte works

ss(x:b)=b
s x=x
main=interact s

Try it online!

Explanation

In its default state this program defines two functions ss which is unused, and s which is the identity. It then declares that interaction is handled by s, making it a cat.

When we remove the first byte ss is renamed to s. Making it a special case of our function s, since this is the first declaration it takes highest precedence. So now s is defined such that if it can remove the first character it does so otherwise it falls back onto our old definition of s1 and becomes the identity. We still interact with s (although now modifed) so the entire program has the behavior of removing the first character if there is one.


1 This is important in the case of the empty string.

\$\endgroup\$
4
\$\begingroup\$

Keg -ir, 3 bytes, score: 2

#_^

Try it online!

Explanation

#_^ # A line comment
    # Copies the input to the output straightforwardly
    # Implicit reversed input
_   # Discard the first character in the string
 ^  # Reverse the stack
\$\endgroup\$
3
  • \$\begingroup\$ Even better: ^_^ \$\endgroup\$
    – moltarze
    Dec 16, 2019 at 17:13
  • \$\begingroup\$ @connectyourcharger You know, one of my eyes are sore... \$\endgroup\$
    – user85052
    Dec 16, 2019 at 23:16
  • \$\begingroup\$ @connectyourcharger ugh. Now I can't not see it as a face. :P \$\endgroup\$
    – lyxal
    Dec 18, 2019 at 0:43
4
\$\begingroup\$

05AB1E, score 1, 2 bytes

Try it online!

First byte is removable.

\$\endgroup\$
4
\$\begingroup\$

[Python 3], 9097 bytes, score 6

eEzfFzeEz=aAzcCzaAz=aAzbBz=bBzaAz=aAzcCz=eEzfFz=fFzaAz=eEzaAz=dDzaAz=exe=exc=xec=xecexec=aAz=aA=az=Az=aAz=fr='"1"#\nimport base64\n\ndef actual_source():\n\treturn open(eval("_"+"_file_"+"_") ).read()\n\ndef decode(s):\n\treturn str(base64.b64decode(s.replace("_", str() ) ), "utf-8" )\n\ndef encode(s):\n\ts=str(base64.b64encode(bytes(s, "utf-8") ),"utf-8")\n\tresult = str().join([cur if prev!=cur else "_"+cur for prev,cur in zip([None]+list(s),s)])\n\treturn result\n\ndef get_template():\n\treturn decode("aW1wb3J0IGJhc2U2NAoKZGVmIGFjdHVhbF9zb3VyY2UoKToKCXJldHVybiBvcGVuKGV2YWwoIl8iKyJfZmlsZV8iKyJfIikgKS5yZWFkKCkKCmRlZiBkZWNvZGUocyk6CglyZXR1cm4gc3RyKGJhc2U2NC5iNjRkZWNvZGUocy5yZXBsYWNlKCJfIiwgc3RyKCkgKSApLCAidXRmLTgiICkKCmRlZiBlbmNvZGUocyk6CglzPXN0cihiYXNlNjQuYjY0ZW5jb2RlKGJ5dGVzKHMsICJ1dGYtOCIpICksInV0Zi04IikKCXJlc3VsdCA9IHN0cigpLmpvaW4oW2N1ciBpZiBwcmV2IT1jdXIgZWxzZSAiXyIrY3VyIGZvciBwcmV2LGN1ciBpbiB6aXAoW05vbmVdK2xpc3QocykscyldKQoJcmV0dXJuIHJlc3VsdAoKZGVmIGdldF90ZW1wbGF0ZSgpOgoJcmV0dXJuIGRlY29kZSgiQjY0X0VOQ09ERURfUEFSVFMiKQoKZGVmIGdldF93cmFwZXIoKToKCXJldHVybiBkZWNvZGUoIldSQVAiKQoKZGVmIGdldF9wYXlsb2FkKCk6Cgl3cmFwZXIsIHRlbXBsYXRlID0gZ2V0X3dyYXBlcigpLCBnZXRfdGVtcGxhdGUoKQoJZW5fdGVtcGxhdGVfNjQgPSBlbmNvZGUodGVtcGxhdGUpCgl3cmFwZXJfNjQgPSBlbmNvZGUod3JhcGVyKQoJcmV0dXJuIHRlbXBsYXRlLnJlcGxhY2UoIkI2NF9FTkMiKyJPREVEX1B_BUlRTIiwgZW5fdGVtcGxhdGVfNjQpLnJlcGxhY2UoIldSIisiQVAiLCB3cmFwZXJfNjQpCgpkZWYgZ2V0X29yaWdpbmFsKCk6CglwYXlsb2FkID0gZ2V0X3BheWxvYWQoKQoJd3JhcGVyID0gZ2V0X3dyYXBlcigpCglyZXR1cm4gd3JhcGVyLnJlcGxhY2UoIjEyMyIsIHJlcHIocGF5bG9hZClbMTotMV0gKQoKZGVmIG1haW4ocyk6Cglmb3IgaSwgKGEsIGIpIGluIGVudW1lcmF0ZSg_gemlwKGdldF9vcmlnaW5hbCgpLCBhY3R1YWxfc291cmNlKCkgKSApOgoJCWlmIGEgIT0gYjoKCQkJcmV0dXJuIHNbOmldICsgc1tpICsgMTpdCglyZXR1cm4gcwoKaWYgbm90IChldmFsKCJfIisiX25hbWVfIisiXyIpICE9ICJfIisiX21haW5fIisiXyIpOgoJcHJpbnQobWFpbihpbnB1dCgpICkgKQ=_=")\n\ndef get_wraper():\n\treturn decode("ZUV6ZkZ6ZUV6PWFBemNDemFBej1hQXpiQno9YkJ6YUF6PWFBemNDej1lRXpmRno9ZkZ6YUF6PWVFemFBej1kRHphQXo9ZXhlPWV4Yz14ZWM9eGVjZXhlYz1hQXo9YUE9YXo9QXo9YUF6PWZyPSciMSIjXG4xMjMnIycjJwoxMjsKYkJ6PWJCPWJ6PUJ6PWJCej1mcj0nIjEiI1xuMTIzJyMnIycKMTI7CmNDej1jQz1jej1Dej1jQ3o9ZnI9JyIxIiNcbjEyMycjJyMnCjEyOwpleGU9ZXhjPXhlYz1leGVjCmREej1kRD1kej1Eej1kRHo9YUF6LGJCeixhQXo7CmVFemZGemVFej1nR3plRXo9YUF6Y0N6PWFBejxjQ3o7CmVFej1lRT1lej1Fej1lRXo9YUF6PGNDejsKZkZ6PWZGPWZ6PUZ6PWZGej1hQXo+Y0N6OwplRXpmRno9ZUV6fGZGejsKZ0d6PWdHPWd6PUd6PWdHej1lRXp8ZkZ6OwpleGVjKGREeltnR3pdKQ=_=")\n\ndef get_payload():\n\twraper, template = get_wraper(), get_template()\n\ten_template_64 = encode(template)\n\twraper_64 = encode(wraper)\n\treturn template.replace("B64_ENC"+"ODED_PARTS", en_template_64).replace("WR"+"AP", wraper_64)\n\ndef get_original():\n\tpayload = get_payload()\n\twraper = get_wraper()\n\treturn wraper.replace("123", repr(payload)[1:-1] )\n\ndef main(s):\n\tfor i, (a, b) in enumerate( zip(get_original(), actual_source() ) ):\n\t\tif a != b:\n\t\t\treturn s[:i] + s[i + 1:]\n\treturn s\n\nif not (eval("_"+"_name_"+"_") != "_"+"_main_"+"_"):\n\tprint(main(input() ) )'#'#'
12;
bBz=bB=bz=Bz=bBz=fr='"1"#\nimport base64\n\ndef actual_source():\n\treturn open(eval("_"+"_file_"+"_") ).read()\n\ndef decode(s):\n\treturn str(base64.b64decode(s.replace("_", str() ) ), "utf-8" )\n\ndef encode(s):\n\ts=str(base64.b64encode(bytes(s, "utf-8") ),"utf-8")\n\tresult = str().join([cur if prev!=cur else "_"+cur for prev,cur in zip([None]+list(s),s)])\n\treturn result\n\ndef get_template():\n\treturn decode("aW1wb3J0IGJhc2U2NAoKZGVmIGFjdHVhbF9zb3VyY2UoKToKCXJldHVybiBvcGVuKGV2YWwoIl8iKyJfZmlsZV8iKyJfIikgKS5yZWFkKCkKCmRlZiBkZWNvZGUocyk6CglyZXR1cm4gc3RyKGJhc2U2NC5iNjRkZWNvZGUocy5yZXBsYWNlKCJfIiwgc3RyKCkgKSApLCAidXRmLTgiICkKCmRlZiBlbmNvZGUocyk6CglzPXN0cihiYXNlNjQuYjY0ZW5jb2RlKGJ5dGVzKHMsICJ1dGYtOCIpICksInV0Zi04IikKCXJlc3VsdCA9IHN0cigpLmpvaW4oW2N1ciBpZiBwcmV2IT1jdXIgZWxzZSAiXyIrY3VyIGZvciBwcmV2LGN1ciBpbiB6aXAoW05vbmVdK2xpc3QocykscyldKQoJcmV0dXJuIHJlc3VsdAoKZGVmIGdldF90ZW1wbGF0ZSgpOgoJcmV0dXJuIGRlY29kZSgiQjY0X0VOQ09ERURfUEFSVFMiKQoKZGVmIGdldF93cmFwZXIoKToKCXJldHVybiBkZWNvZGUoIldSQVAiKQoKZGVmIGdldF9wYXlsb2FkKCk6Cgl3cmFwZXIsIHRlbXBsYXRlID0gZ2V0X3dyYXBlcigpLCBnZXRfdGVtcGxhdGUoKQoJZW5fdGVtcGxhdGVfNjQgPSBlbmNvZGUodGVtcGxhdGUpCgl3cmFwZXJfNjQgPSBlbmNvZGUod3JhcGVyKQoJcmV0dXJuIHRlbXBsYXRlLnJlcGxhY2UoIkI2NF9FTkMiKyJPREVEX1B_BUlRTIiwgZW5fdGVtcGxhdGVfNjQpLnJlcGxhY2UoIldSIisiQVAiLCB3cmFwZXJfNjQpCgpkZWYgZ2V0X29yaWdpbmFsKCk6CglwYXlsb2FkID0gZ2V0X3BheWxvYWQoKQoJd3JhcGVyID0gZ2V0X3dyYXBlcigpCglyZXR1cm4gd3JhcGVyLnJlcGxhY2UoIjEyMyIsIHJlcHIocGF5bG9hZClbMTotMV0gKQoKZGVmIG1haW4ocyk6Cglmb3IgaSwgKGEsIGIpIGluIGVudW1lcmF0ZSg_gemlwKGdldF9vcmlnaW5hbCgpLCBhY3R1YWxfc291cmNlKCkgKSApOgoJCWlmIGEgIT0gYjoKCQkJcmV0dXJuIHNbOmldICsgc1tpICsgMTpdCglyZXR1cm4gcwoKaWYgbm90IChldmFsKCJfIisiX25hbWVfIisiXyIpICE9ICJfIisiX21haW5fIisiXyIpOgoJcHJpbnQobWFpbihpbnB1dCgpICkgKQ=_=")\n\ndef get_wraper():\n\treturn decode("ZUV6ZkZ6ZUV6PWFBemNDemFBej1hQXpiQno9YkJ6YUF6PWFBemNDej1lRXpmRno9ZkZ6YUF6PWVFemFBej1kRHphQXo9ZXhlPWV4Yz14ZWM9eGVjZXhlYz1hQXo9YUE9YXo9QXo9YUF6PWZyPSciMSIjXG4xMjMnIycjJwoxMjsKYkJ6PWJCPWJ6PUJ6PWJCej1mcj0nIjEiI1xuMTIzJyMnIycKMTI7CmNDej1jQz1jej1Dej1jQ3o9ZnI9JyIxIiNcbjEyMycjJyMnCjEyOwpleGU9ZXhjPXhlYz1leGVjCmREej1kRD1kej1Eej1kRHo9YUF6LGJCeixhQXo7CmVFemZGemVFej1nR3plRXo9YUF6Y0N6PWFBejxjQ3o7CmVFej1lRT1lej1Fej1lRXo9YUF6PGNDejsKZkZ6PWZGPWZ6PUZ6PWZGej1hQXo+Y0N6OwplRXpmRno9ZUV6fGZGejsKZ0d6PWdHPWd6PUd6PWdHej1lRXp8ZkZ6OwpleGVjKGREeltnR3pdKQ=_=")\n\ndef get_payload():\n\twraper, template = get_wraper(), get_template()\n\ten_template_64 = encode(template)\n\twraper_64 = encode(wraper)\n\treturn template.replace("B64_ENC"+"ODED_PARTS", en_template_64).replace("WR"+"AP", wraper_64)\n\ndef get_original():\n\tpayload = get_payload()\n\twraper = get_wraper()\n\treturn wraper.replace("123", repr(payload)[1:-1] )\n\ndef main(s):\n\tfor i, (a, b) in enumerate( zip(get_original(), actual_source() ) ):\n\t\tif a != b:\n\t\t\treturn s[:i] + s[i + 1:]\n\treturn s\n\nif not (eval("_"+"_name_"+"_") != "_"+"_main_"+"_"):\n\tprint(main(input() ) )'#'#'
12;
cCz=cC=cz=Cz=cCz=fr='"1"#\nimport base64\n\ndef actual_source():\n\treturn open(eval("_"+"_file_"+"_") ).read()\n\ndef decode(s):\n\treturn str(base64.b64decode(s.replace("_", str() ) ), "utf-8" )\n\ndef encode(s):\n\ts=str(base64.b64encode(bytes(s, "utf-8") ),"utf-8")\n\tresult = str().join([cur if prev!=cur else "_"+cur for prev,cur in zip([None]+list(s),s)])\n\treturn result\n\ndef get_template():\n\treturn decode("aW1wb3J0IGJhc2U2NAoKZGVmIGFjdHVhbF9zb3VyY2UoKToKCXJldHVybiBvcGVuKGV2YWwoIl8iKyJfZmlsZV8iKyJfIikgKS5yZWFkKCkKCmRlZiBkZWNvZGUocyk6CglyZXR1cm4gc3RyKGJhc2U2NC5iNjRkZWNvZGUocy5yZXBsYWNlKCJfIiwgc3RyKCkgKSApLCAidXRmLTgiICkKCmRlZiBlbmNvZGUocyk6CglzPXN0cihiYXNlNjQuYjY0ZW5jb2RlKGJ5dGVzKHMsICJ1dGYtOCIpICksInV0Zi04IikKCXJlc3VsdCA9IHN0cigpLmpvaW4oW2N1ciBpZiBwcmV2IT1jdXIgZWxzZSAiXyIrY3VyIGZvciBwcmV2LGN1ciBpbiB6aXAoW05vbmVdK2xpc3QocykscyldKQoJcmV0dXJuIHJlc3VsdAoKZGVmIGdldF90ZW1wbGF0ZSgpOgoJcmV0dXJuIGRlY29kZSgiQjY0X0VOQ09ERURfUEFSVFMiKQoKZGVmIGdldF93cmFwZXIoKToKCXJldHVybiBkZWNvZGUoIldSQVAiKQoKZGVmIGdldF9wYXlsb2FkKCk6Cgl3cmFwZXIsIHRlbXBsYXRlID0gZ2V0X3dyYXBlcigpLCBnZXRfdGVtcGxhdGUoKQoJZW5fdGVtcGxhdGVfNjQgPSBlbmNvZGUodGVtcGxhdGUpCgl3cmFwZXJfNjQgPSBlbmNvZGUod3JhcGVyKQoJcmV0dXJuIHRlbXBsYXRlLnJlcGxhY2UoIkI2NF9FTkMiKyJPREVEX1B_BUlRTIiwgZW5fdGVtcGxhdGVfNjQpLnJlcGxhY2UoIldSIisiQVAiLCB3cmFwZXJfNjQpCgpkZWYgZ2V0X29yaWdpbmFsKCk6CglwYXlsb2FkID0gZ2V0X3BheWxvYWQoKQoJd3JhcGVyID0gZ2V0X3dyYXBlcigpCglyZXR1cm4gd3JhcGVyLnJlcGxhY2UoIjEyMyIsIHJlcHIocGF5bG9hZClbMTotMV0gKQoKZGVmIG1haW4ocyk6Cglmb3IgaSwgKGEsIGIpIGluIGVudW1lcmF0ZSg_gemlwKGdldF9vcmlnaW5hbCgpLCBhY3R1YWxfc291cmNlKCkgKSApOgoJCWlmIGEgIT0gYjoKCQkJcmV0dXJuIHNbOmldICsgc1tpICsgMTpdCglyZXR1cm4gcwoKaWYgbm90IChldmFsKCJfIisiX25hbWVfIisiXyIpICE9ICJfIisiX21haW5fIisiXyIpOgoJcHJpbnQobWFpbihpbnB1dCgpICkgKQ=_=")\n\ndef get_wraper():\n\treturn decode("ZUV6ZkZ6ZUV6PWFBemNDemFBej1hQXpiQno9YkJ6YUF6PWFBemNDej1lRXpmRno9ZkZ6YUF6PWVFemFBej1kRHphQXo9ZXhlPWV4Yz14ZWM9eGVjZXhlYz1hQXo9YUE9YXo9QXo9YUF6PWZyPSciMSIjXG4xMjMnIycjJwoxMjsKYkJ6PWJCPWJ6PUJ6PWJCej1mcj0nIjEiI1xuMTIzJyMnIycKMTI7CmNDej1jQz1jej1Dej1jQ3o9ZnI9JyIxIiNcbjEyMycjJyMnCjEyOwpleGU9ZXhjPXhlYz1leGVjCmREej1kRD1kej1Eej1kRHo9YUF6LGJCeixhQXo7CmVFemZGemVFej1nR3plRXo9YUF6Y0N6PWFBejxjQ3o7CmVFej1lRT1lej1Fej1lRXo9YUF6PGNDejsKZkZ6PWZGPWZ6PUZ6PWZGej1hQXo+Y0N6OwplRXpmRno9ZUV6fGZGejsKZ0d6PWdHPWd6PUd6PWdHej1lRXp8ZkZ6OwpleGVjKGREeltnR3pdKQ=_=")\n\ndef get_payload():\n\twraper, template = get_wraper(), get_template()\n\ten_template_64 = encode(template)\n\twraper_64 = encode(wraper)\n\treturn template.replace("B64_ENC"+"ODED_PARTS", en_template_64).replace("WR"+"AP", wraper_64)\n\ndef get_original():\n\tpayload = get_payload()\n\twraper = get_wraper()\n\treturn wraper.replace("123", repr(payload)[1:-1] )\n\ndef main(s):\n\tfor i, (a, b) in enumerate( zip(get_original(), actual_source() ) ):\n\t\tif a != b:\n\t\t\treturn s[:i] + s[i + 1:]\n\treturn s\n\nif not (eval("_"+"_name_"+"_") != "_"+"_main_"+"_"):\n\tprint(main(input() ) )'#'#'
12;
exe=exc=xec=exec
dDz=dD=dz=Dz=dDz=aAz,bBz,aAz;
eEzfFzeEz=gGzeEz=aAzcCz=aAz<cCz;
eEz=eE=ez=Ez=eEz=aAz<cCz;
fFz=fF=fz=Fz=fFz=aAz>cCz;
eEzfFz=eEz|fFz;
gGz=gG=gz=Gz=gGz=eEz|fFz;
exec(dDz[gGz])

This program has the general structure

a="payload"
b="payload"
c="payload"
exec([a,b][b==c])

where "payload" is the program we want to execute. The comparison in the exec call makes sure that we run an unmodified copy of the payload. Within the payload, we open the source of __file__ and compare it to the unmodified source (which is determined using a quine). This gives us the information we need to delete the correct character from the output.

The base64 encoded segments are the inputs used when making the quine. They are base64 encoded to avoid needing to escape nested quotes. The program is written so that it has no repeating characters, allowing almost any deletion to be detected.

The 6 characters that can't be deleted are:

  • The parentheses and brackets in the last line (([])), as deleting them will cause a syntax error.
  • The x in both instances of exec, as this produces the variable eec which is not defined.

If I did define eec, I would introduce a pair of duplicated characters, and would not be able to distinguish between those deletions. If the challenge cared about deletions of characters instead of bytes then I could define eᵉc in the appropriate places to reduce the score to 4.

Radiation Resistance tricks

eEzfFzeEz=aAzcCzaAz=... This line defines all the variables that the program could later try to read, to avoid crashing with a NameError.

bBz=bB=bz=Bz=bBz= when I want to be able to read a value, I define it (bBz) twice, and also define the mangled versions of it once each. When the variable is later accessed, at least one of the original definitions was undamaged, and damaging the later access will result in reading one of the shortened versions of the variable. No variable shorter than 2 characters is used as deleting a single variable would cause

bBz=fr='"1"#\n This acts as a no-op when the payload is executed, and results in any radiation to the start of the string merely storing a bad value in bBz.

  • If the single quote is deleted, "1" is assigned, and the rest of the string is commented out.
  • If the last = is deleted, the string becomes a raw format string, but is still valid syntax.
  • Other deletions mangle some variable names, but redundant assignment fixes this.

At the end of the strings '#'#' is used. As written this is the end of one string followed by a comment. If the first ' is removed, it the next #' become part of the string, and the remaining 2 characters become a comment. If the first # is removed, then the program has 2 strings in a row, so they are concatenated. Damage to the last 2 characters is just a change to the comment text.

12; and ; are added to allow the deletion of newlines to join statements without issue.

dDz=aAz,bBz,aAz; This line stores the A and B in a tuple. If either comma is deleted, we still store a tuple of size two. The 3rd tuple element will never be accessed. Deleting the = has no effect, as dDzaAz was initialized to the same value as aAz.

a != c is converted to e = a<c; f = a>c; g = e|f so that characters in the comparison operator can be deleted without crashing the program. Then redundant comparisons are added so that damaging any one of the comparisons produces the right result.

exec(dDz[gGz]) we can execute a known-good payload by indexing into a tuple.

\$\endgroup\$
3
\$\begingroup\$

Python 3, 33 - 1 = 32 bytes

The removable byte is the 23rd one (~).

x=input();print(x[:22-~0]+x[23:])

Try it online!

This sort of evolved out of Arnauld's answer, but only seeks to get one removable character.

Explanation

In python ~ is a "bitwise not", which basically subtracts the value from 1. So ~0 is equivalent to -1. This makes 22-~0 the same as 23. So normally our program takes everything up to the 23rd character and then adds everything after. However when we remove the ~ 22-~0 becomes 22-0 equivalent to 22. This makes us take the first 22 characters and everything after the 23rd, skipping the 23rd character.

\$\endgroup\$
3
\$\begingroup\$

Shakespeare Programming Language, 236 bytes, score 235

-16 bytes thanks to Jo King.

New lines added for readability. Byte 196 can be removed. Exits with error but the output is correct.

,.Ajax,.Page,.
Act I:.Scene I:.
[Exeunt][Enter Ajax and Page]
Ajax:Open mind.
Page:You be the sum ofyou a cat.
     Be you as big as the square ofthe sum ofa big big big big cat a big pig?
     If soLet usScene VI.

Scene VI:.
Ajax:Speak mind.Let usAct I.

Try it online!

Page reads bytes from input and outputs them, one at a time. Ajax is a counter indicating how many bytes have been read. Page's if statement tests Ajax == 196. In the basic version, the if statement is useless: in all cases, we proceed to Scene VI. If byte 196 has been removed, the statement becomes If soLet usScene I. so we skip Scene VI and the corresponding input does not get output.

This uses the fact that SPL doesn't require scenes to use consecutive numbers.

Looking for other strategies, I checked all the words allowed in SPL: the only useful pair of words which are one deletion apart is Helen/Helena, which are both legal characters. I might try to use this to get a solution where two different bytes can be removed.

\$\endgroup\$
0
2
\$\begingroup\$

Charcoal, 6 bytes, score 5

ΦS⁻κ±⁴

Try it online! Explanation:

 S      Input string
Φ       Filtered
   κ    Current index
  ⁻     Subtract
     ⁴  Literal `4`
    ±   Negated

Since adding 4 to the index is always a truthy result, this is a cat program. Removing the ± at index 4 results in the following program:

ΦS⁻κ⁴

Try it online! It deletes the character at index 4 (0-indexed).

\$\endgroup\$
2
\$\begingroup\$

C (gcc), 54 53 bytes, score 52 51

Bytes 27 or 28 (from the first ++c), or both, may be removed.

Explanation:

There is a counter that increments by 2 each iteration (one in the loop condition, one in the body) in the unmodified program, but removing one of the +s turns the first increment into a no-op. As the only way to get an odd number is in the modified program, only it will remove the 27th byte. Both bytes can be removed because +c is the same as c.

c;main(a){for(;a=~getchar(++c);)++c-27&&putchar(~a);}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

GNU Sed 7 bytes, score=6

Full program

b;s/.//

Program with first byte removed

;s/.//

Input is a printable ASCII string, with no newlines.

\$\endgroup\$
1
  • \$\begingroup\$ Strange that s/.^// interprets ^ as non-special whereas s/^// doesn't \$\endgroup\$
    – user41805
    Dec 18, 2019 at 18:23
1
\$\begingroup\$

JavaScript, 52 bytes, score 51

The 37th byte, 1, is removable.

s=prompt()
console.log(s.slice(0,36+01)+s.slice(37))


JavaScript, 56 bytes, score 55

The 24th byte, 1, is removable.

s=prompt()
console.log(01?s:s.replace(/^(.{24})./,'$1'))

\$\endgroup\$
1
  • \$\begingroup\$ For the first one, 1+33 saves a byte, as you can remove the 1 to leave +33. \$\endgroup\$
    – Neil
    Dec 20, 2019 at 15:58
1
\$\begingroup\$

Symbolic Python, 11 bytes, score 10

__=_[_==_:]

Try it online!

The first _ is removable. Basically, the program sets __ to the input without the first character, which doesn't affect the IO variable _, so it outputs what is inputted. If you remove the _. it does set the variable, so the first character is removed. Try it online!

\$\endgroup\$
1
\$\begingroup\$

J, 14 - 1 = 13 bytes

1(]}.~1-1-:[)]

Try it online!

Removing the first byte works.

how

  • 1(...)] A fork with the constant 1 as the left tine and the input as the right ].
  • (]}.~1-1-:[) One minus 1- the value "does the input equal the left fork tine?" 1-:[.
    • This will always be 0 in the unaltered program.
    • It will always be 1 in the program-with-byte1-removed. No string matches the integer 1.
    • This works because removing that first 1 turns the fork into a hook, which is like a fork whose left tine is the original input.
  • ]}.~ Remove from the beginning }.~ of the original input ] that number of characters -- ie, the 1 or 0 calculated in the previous step.
\$\endgroup\$
1
\$\begingroup\$

Vyxal, score 1

,Ḣ

Try it Online!

,  # Print
 Ḣ # Remove first character, ignored

Ḣ  # Remove first character, implicitly printed
\$\endgroup\$
0
\$\begingroup\$

Pyth, 2 bytes - Score: 1

&t

Try it online!

This implicitly expands to: imp_print((tail(Q) and Q))
Removing the '&' let's the tail function print (All but the first element)

\$\endgroup\$
0
\$\begingroup\$

Python 3, score = 27, 262 bytes

x="a,b=sorted(x,key=len);d=[3,123][x!=(a,b)];n=sum(i is j for i,j in zip(a,b) );s=input();print(s[:d+n]+s[d+n+(a!=b):]) ","a,b=sorted(x,key=len);d=[3,123][x!=(a,b)];n=sum(i is j for i,j in zip(a,b) );s=input();print(s[:d+n]+s[d+n+(a!=b):]) "
exec(max(x,key=len))

Try it online!

redundancy is good

\$\endgroup\$

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.