mbomb007 asked us to make a self mutilating program. Its an interesting challenge, but I personally don't like to encourage my programs to be self-mutilating. I like to think that, at the heart of every program is a beautiful butterfly waiting to break out.

As such, for my first ever Code Golf challenge, I challenge Stack Exchange to metamorph a butterfly. Your program should accept its own code as input and output I am a caterpillar! followed by the code for another program in the same language (you may put a divider between the outputs or not... but we're talking butterflies, so prettiness counts!). This second program should output I am a beautiful butterfly!

Metamorphosis: This program should modify itself, which is why it is being passed itself as input. I don't want a boring nested program that is nothing but a print statement I am a caterpillar! followed by printing source code. You have to metamorph the code itself, so the most boring acceptable answer is one which prints I am a caterpillar, then rips a string out of the input (which happens to be code) and prints that. Of course, this is a very tricky little requirement to write, so it should be thought of as a "spirit of the challenge." The formal requirement is going to be set at "If your program is given a random string of the same length as your program, there should be less than a 5% chance of printing I am a butterfly when the second program is run."

Summary:

  • Write a program which, when provided its own code as input, prints I am a caterpillar! followed by a block of source code (with a delimiter between them or not).
  • This second block of source code, when compiled/interpreted as the same language, prints I am a beautiful butterfly!
  • If your program is not fed its own source code as input, and is instead given a random string of characters that does not match its own code, the result must either fail to compile/interpret, or not print I am a butterfly! for at least 95% of random strings (spirit: you are expected to read your own source code from the input, and stitch it together into a butterfly).
    • I'm comfortable with you not proving this, so long as you're holding to the spirit of the metamorphosis idea, modifying your own code, but if you're trying to play loophole games to work around using your inputs, expect to have to prove it.
  • Standard loopholes apply

I'd like these to be judged by their beauty, but that's a decidedly non-quantitative approach, so the usual "number of bytes" route can be used to judge

Bonus: -20% - pick any 3 letter string that doesn't match the first 3 letters of your program. If I run the caterpillar program, but modify the input so that the first 3 character are changed to the specified ones, print I am Batman! instead. Always be Batman. (Same random string rules apply for this... metamorphosis!)

Trivial example (python):

"""
    print "I am a beautiful butterfly!"
    #print "I am Batman!"
"""
import sys
code = sys.stdin.read()
if code.startswith("YYZ"):
   # swap the comments between the print statements
   code = code.replace("#print", "_a").replace("print", "#print").replace("_a", "print")
code = [3:] # remove """ or XYZ
code = code.split('"""')[0]
print "I am a caterpillar!"
print code
  • As a note: I'd love to see ascii art programs where it looks like a caterpillar the first time, and turns into an ascii butterfly the next phase, but that's quite a bit more advanced than the challenge needs to be. – Cort Ammon Oct 7 '15 at 19:58
  • What should we do if a program has multiple files? – TheNumberOne Oct 7 '15 at 23:25
  • @TheNumberOne I'm curious what you have planned there! I don't know if I want to beat down the rules for that right away, without seeing the consequences, but it seems to me that, if you were to accept a multi-part set of files as input (rather than a single file's contents), and you were to output a multi-part set of outputs (rather than a single output), with a half-reasonable deliniator between the files, I think that should be a reasonable solution. If that doesn't work for you, I may need more insight into your proposed solution to better craft a rule. – Cort Ammon Oct 7 '15 at 23:47
  • @TheNumberOne And thank you for the typo catch. That typo was very clearly not a beautiful butterfly! – Cort Ammon Oct 7 '15 at 23:48

Befunge-98, 602 bytes

                                        "^@<"v@@
                                     "'I'"00v>00g::
                                   "@v"0v@@@>g::a">#"
                                 "a">v@@>      0g::'"1>                                 /
                             ":\"'"v@>            'm'"00g:a                       >"@v$"
 "lufituaeb"'"'v00ga"@v\"'":'b\00v@>                :'a\":*84>"00ga"\>@@@@_,#:>"00g:a'<'"
"et"'"'va'v'":'l\00g5k:'""y!">>v@>                    g::'''""ut"'"'>a'<'""fr"'"00g3k:'">
 "ma"00g>'I~48*-~48*-+#@_>:#,_@>                        '"aa"---"aa"!rallipretac"00g:'a\

Tested in PyFunge.

When run with a string not starting with 2 spaces (probability well over 95% when random) outputs nothing. This isn't exactly what the OP is looking for, but fits the specification.

When passed a string starting with 2 spaces (like itself) outputs this:

I am a caterpillar!

---

"!y"       "l"v
v"te"     "rf"<
>"tu"'   "b"\v@
 v"beautiful"<
  >:#,_@@@@>\
 >48*:"a"\:$v@
  "ma"   v@#>
   'I'   <@^

The lower part of that, in turn, outputs:

I am a beautiful butterfly!
  • 2
    Wow. This is amazing. – quartata Oct 8 '15 at 0:12
  • 3
    I knew someone would want to push the rules just like you did; I'm glad something beautiful came out of it =) – Cort Ammon Oct 8 '15 at 3:21
  • Both caterpillar and butterfly look like they are stuck in the Matrix. Beautiful! – Erno de Weerd Oct 8 '15 at 13:07
  • where can I run this? – user1514631 Oct 8 '15 at 13:19
  • 3
    I will never understand how you good folks at Code Golf manage to create such beautiful monstrosities. – Chris Cirefice Oct 9 '15 at 0:08

PHP, 74 Bytes

<?=~¶ßž’ßžß,$s="caterpillar!",strtr($argv[1],[$s=>~šžŠ‹–™Š“ߊ‹‹š™“†Þ]);
  • <?= is equivalent to <?php echo and can take several comma separated values to output
  • ¶ßž’ßžß and šžŠ‹–™Š“ߊ‹‹š™“†Þ are valid constant names in PHP, but because the constants do not exist are treated as string literal. ~ inverts them to "I am a " and "beautiful butterfly!" (saving a byte for one quotation mark each)
  • strtr replaces "caterpillar!" with "a beautiful butterfly!" in the argument
  • 2
    Care to provide an explanation? – Timwi Oct 7 '15 at 21:58
  • @Timwi no problem, explanation added – Fabian Schmengler Oct 7 '15 at 22:04
  • I fully expected someone to encode "beautiful butterfly" with something like ROT13, but the idea of matching it with PHP's string literal technique is, in the words of Kaylee, shiny! – Cort Ammon Oct 7 '15 at 23:52

Pyth, 50 46 bytes

"I am a caterpillar!"+<z8"beautiful butterfly!

Explanation

"I am a caterpillar!"        print "I am a caterpillar!"
 z<8                         first 8 chars of input
+   "beautiful butterfly!    add "beautiful butterfly!" to that and print

The resulting source code is

"I am a beautiful butterfly!

Which basically prints the text.

Perl 6, 60 56 bytes

say "I am a caterpillar!"; s/\S+\!/beautiful butterfly!/

Requires -p to run properly; I have accounted for this in the byte count. Sadly one of the downsides to Perl 6 is that the syntax is much more strict now...

  • Caterpillars are vulnerable during metamorphosis. That's why they like to wrap themselves in c̶o̶c̶o̶o̶n̶s̶ variables: $a=caterpillar;say"I am a $a!";s/$a/beautiful butterfly/ (I'm assuming that Perl 6 allows barewords like Perl 5 with no strict 'subs' and s/// interpolates variables on the LHS.) – ThisSuitIsBlackNot Oct 7 '15 at 22:35
  • Huh, that's funny. I tried that and for some reason when I did wc it gave me the same amount of bytes. But upon typing it out again it gave me less bytes. Strange. – quartata Oct 7 '15 at 23:13
  • Oh wait nevermind I remember why I didn't do it. When run the new code it throws an error because of the space between beautiful and butterfly. – quartata Oct 7 '15 at 23:18
  • Ah, I've never used Perl 6 so can't help you there. I really just wanted an excuse to make a witty remark. ;) say"I am a caterpillar!";s/\S+!/beautiful butterfly!/ is shorter and will certainly work in Perl 6. – ThisSuitIsBlackNot Oct 8 '15 at 0:48
  • 1
    @ThisSuitIsBlackNot It does fit the challenge. The rules were just there to make sure you actually read and modify your code. In the end, the real spirit is trying to let the beautiful butterfly in the heart of the code break free. Beauty, of course, is in the eye of the beholder. We will each find different solutions more or less beautiful than others. As for solutions in PERL, well... let's just say PERL has its own peculiar definition of beautiful, and it suits its purposes just fine ;-) – Cort Ammon Oct 8 '15 at 20:08

Retina, 53 bytes

caterpillar
beautiful butterfly
^
I am a caterpillar!

Prints out:

I am a caterpillar!beautiful butterfly
beautiful butterfly
^
I am a beautiful butterfly!

Notice that there is no separator between I am a caterpillar! and the new program. The new program expects no input.

bash / awk / cksum - 179.2 169.6 168 bytes

awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'

Demo:

$ awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'<<'E'
> awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'
> E
I am a caterpillar!
echo|awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."10"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'
$ echo|awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."10"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'
I am a beautiful butterfly!

# Batman!
$ awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'<<'E'
> xyzawk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'
> E
I am Batman!

# Invalid input
$ awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0}'<<'E'
> awk '/^xyz/{print"I am Batman!";exit}NF{("cksum<<<'"'"'"substr($0,100))|getline r;if(r!~/^6689751/)exit}{printf"I am a %s%."!NF"s!\n",NF?"caterpillar":"beautiful"," butterfly"}NF&&sub(/!NF/,10){print"echo|"$0{'
> E

I hope the 20% applies for any string starting with xyz, otherwise the original count is 224 212 210 bytes (fixed the "I am Batman!" part).

Transformation done: replaces the only occurrence of the literal !NF with 10, so that " butterfly" is also printed using the printf.

Performs a simple cksum on a portion (i.e. the remainder) of the source code, hence its requirement as well.

Caveat: first input must end with '. Not so much a caveat as to suppress wrong input...

No second input is expected.

  • 1
    WHOA. I was waiting for the awk person, and that's it. That's pretty cool. – jrg Oct 8 '15 at 21:19
  • @jrg thanks for the encouragement. :) – h.j.k. Oct 9 '15 at 1:58

Python - 184 bytes -20% for bonus = 147.2

""""""
import sys;c=sys.stdin.read();print"I am a caterpillar!";x=c[3:] if"\'''"!=c[:3] else c
print x+c[:3]
""";print"I am a beautiful butterfly!" """
''';print"I am Batman";'''

To print I am batman, replace the first three double quotes with single quotes in the input.(First line is '''""")

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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