25
\$\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\$
  • \$\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 '19 at 16:33
  • 2
    \$\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\$ – Ad Hoc Garf Hunter Dec 14 '19 at 16:35
  • \$\begingroup\$ @game0ver I'm not sure what you mean by variable here. Could you clarify the question. \$\endgroup\$ – Ad Hoc Garf Hunter Dec 14 '19 at 16:35
  • \$\begingroup\$ @game0ver I am still unsure of what you mean. What is a here, is the referencing a specific example? \$\endgroup\$ – Ad Hoc Garf Hunter Dec 14 '19 at 16:41
  • \$\begingroup\$ @game0ver I still do not known what is meant by u. \$\endgroup\$ – Ad Hoc Garf Hunter Dec 14 '19 at 16:45

17 Answers 17

19
\$\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
| improve this answer | |
\$\endgroup\$
12
\$\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.

| improve this answer | |
\$\endgroup\$
11
\$\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 .

| improve this answer | |
\$\endgroup\$
7
\$\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 chalenging.

Explanation

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

With first byte removed:

Ḋ | Remove first byte
| improve this answer | |
\$\endgroup\$
6
\$\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.
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @JoKing Whoops, I missed that! Updating now. \$\endgroup\$ – Madison Silver Dec 20 '19 at 1:22
  • \$\begingroup\$ Forgot to remove it when I updated the program. Should be fixed now, unless there's something else I missed... \$\endgroup\$ – Madison Silver Dec 20 '19 at 1:28
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.
| improve this answer | |
\$\endgroup\$
4
\$\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
| improve this answer | |
\$\endgroup\$
  • 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 '19 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 '19 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 '19 at 9:38
  • \$\begingroup\$ Technically the 05AB1E codepage is a subtle extension of extended ASCII. \$\endgroup\$ – user85052 Dec 18 '19 at 10:56
4
\$\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.

| improve this answer | |
\$\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.

| improve this answer | |
\$\endgroup\$
3
\$\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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Even better: ^_^ \$\endgroup\$ – connectyourcharger Dec 16 '19 at 17:13
  • \$\begingroup\$ @connectyourcharger You know, one of my eyes are sore... \$\endgroup\$ – user85052 Dec 16 '19 at 23:16
  • \$\begingroup\$ @connectyourcharger ugh. Now I can't not see it as a face. :P \$\endgroup\$ – Lyxal Dec 18 '19 at 0:43
3
\$\begingroup\$

05AB1E, score 1, 2 bytes

Try it online!

First byte is removable.

| improve this answer | |
\$\endgroup\$
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).

| improve this answer | |
\$\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!

| improve this answer | |
\$\endgroup\$
2
\$\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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @JoKing Thanks! \$\endgroup\$ – Robin Ryder Dec 18 '19 at 18:06
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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Strange that s/.^// interprets ^ as non-special whereas s/^// doesn't \$\endgroup\$ – user41805 Dec 18 '19 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'))

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ For the first one, 1+33 saves a byte, as you can remove the 1 to leave +33. \$\endgroup\$ – Neil Dec 20 '19 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!

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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