27
\$\begingroup\$

This was inspired by Print a Negative of your Code and Golf a mutual quine.


Consider a rectangle of characters, that meet the following restrictions:

  1. Consists solely of printable ASCII characters
  2. Dimensions both greater than 1
  3. Each row and each column contains at least one space.
  4. Each row and each column contains at least one non-space character.

For example, the following is a valid 6x4 rectangle:

%n 2e 
1  g 3
 &* __
 3  

A negative for this rectangle is defined to be a rectangle of equal dimensions, with all spaces replaced by non-space characters, and all non-space characters replaced by spaces. A negative of the above rectangle could be:

  f  ^
 33 > 
9  $  
^ }|Q'

Any non-space printable ASCII character may be used to replace a space.

Task

Your task is to write a program with rectangular source code, that outputs a valid negative to itself. The negative outputted must also be a valid program, in the same language as the original, and it must output the source of the original.

No trailing whitespace may be added or removed, except for a single trailing newline at the end of either output, which is optional.

Neither program is permitted to read the source code of either; nor may REPL environments be assumed.

Scoring

Your score is the product of the dimensions of your code (i.e. if your source code is in a 12 by 25 rectangle, your score is 12*15=180). Additionally, for each character used in a comment, your score increases by 2 (If you use /* .. */ once in your code, and your code is in a 10 by 10 rectangle, your score would be 10*10+8*2=116).

The lowest score wins.

If there is a tie, the submission with the least number of spaces in the program (either the original or the negative, whichever has fewer spaces) wins.

If there still remains a tie, the earlier answer shall win.

There is a bonus of -52%, if combining the original and the negative together produces a normal quine. For example:

Original   Negative   Combined
 A A       B B        BABA
A A         B B       ABAB
\$\endgroup\$
5
  • \$\begingroup\$ @Optimizer That's the reason I didn't make the bonus mandatory. \$\endgroup\$
    – es1024
    Dec 2, 2014 at 6:30
  • 1
    \$\begingroup\$ I am talking about just the negative mutual quine part ;) \$\endgroup\$
    – Optimizer
    Dec 2, 2014 at 6:31
  • \$\begingroup\$ @MartinBüttner Ah, my bad. I was thinking in weird terms. \$\endgroup\$
    – Optimizer
    Dec 3, 2014 at 12:42
  • 1
    \$\begingroup\$ Can anyone do this in c? +1 to whoever will first! \$\endgroup\$
    – MegaTom
    Dec 5, 2014 at 22:26
  • \$\begingroup\$ is whitespace (the lang) allowed \$\endgroup\$ Nov 23, 2021 at 17:06

7 Answers 7

28
\$\begingroup\$

Python, 97x2 + 2 = 196

Not a great solution to start off, but at least it works (I think).

c='o=1-%d;print("%%97s\\n%%97s"%%("#","c=%%r;exec(c%%%%%%d)\\40"%%(c,o),"#")[o:][:2])';exec(c%1) 
                                                                                                #

Output:

                                                                                                #
c='o=1-%d;print("%%97s\\n%%97s"%%("#","c=%%r;exec(c%%%%%%d)\\40"%%(c,o),"#")[o:][:2])';exec(c%0) 
\$\endgroup\$
2
  • 9
    \$\begingroup\$ +1 for the only submission so far to use a real language \$\endgroup\$ Dec 3, 2014 at 19:13
  • \$\begingroup\$ It doesn't seem to be too far off from the bonus either. \$\endgroup\$
    – mbomb007
    May 8, 2015 at 14:24
27
+100
\$\begingroup\$

CJam, (58 56 54 48 46 x 2) * 48% = 44.16

{`"_~"+{_,94\m2/S*a_+\*                       
                       N/23f/Wf%N*}_`'"#)!*}_~

which prints

                       {`"_~"+{_,94\m2/S*a_+\*
N/23f/Wf%N*}_`'"#)!*}_~                       

The non-space characters in each line remain the same between the two mutual quines.

But now the really sweet part:

{`"_~"+{_,94\m2/S*a_+\*{`"_~"+{_,94\m2/S*a_+\*
N/23f/Wf%N*}_`'"#)!*}_~N/23f/Wf%N*}_`'"#)!*}_~

is a quine! :)

Test it here.

How it works

I recommend you read the explanation on my other submission first, as it explains the basics of quining in CJam in general.

This one is a bit trickier. For the mutual quine, as in the other case, I modify the string representation of the block by adding spaces before or after each line, and swapping a 0 with a 2, so that the resulting program puts the spaces at the opposite end.

Note that the spaces don't affect the mutual quines at all. In the first one, they are in a block, which isn't really used, and in the second they are around the entire code.

To obtain a regular quine when combining both, we need to find a way to avoid doing all that modification. Notice that the structure of the whitespace and code means that by combining both, we insert the entirety of one quine into the other. So if we put the entire modification code in a block, we can run that block depending on its actual contents.

So now I've got this block... for the mutual quines, it only contains the code I actually want to run. For the combined quine, it also contains the entire quine again, in a random position, which doesn't make any sense... but since it's a block, it's not run automatically. So we can determine whether to modify the string based on the contents of that block. That's what _`'"#)! is for. It duplicates the block, converts it to a string, searches for the character " (which, in the mutual quines, only appears outside the block) - the search returns -1 if the character isn't found and a positive integer otherwise -, increments the result and negates it logically. So if a " was found this yields 0 otherwise it yields 1. Now we just do *, which executes the block once, if the result was 1 and not at all otherwise.

Finally, this is how the modifying code works:

_,94\m2/S*a_+\*N/23f/Wf%N*
_,                         "Duplicate the quine string and get its length.";
  94\m                     "Subtract from 94.";
      2/                   "Divide by two.";
        S*                 "Create a string with that many spaces. This will be
                            an empty string for the first mutual quine, and contain
                            23 spaces for the second mutual quine.";
          a_+              "Create an array that contains this string twice.";
             \*            "Join the two copies together with the quine string.";
               N/          "Split into lines.";
                 23f/      "Split each line into halves (23 bytes each).";
                     Wf%   "Reverse the two halves of each line.";
                        N* "Join with a newline.";

Claiming the Bounty, (12 x 10) * 48% = 57.6

Turns out that this code can be split over more lines very easily with some modifications. We add 2 characters, to get 48 in a row, which we can then conveniently divide by 8, so that we have 8 lines with 6 characters of code and 6 spaces. To do that we also need to change a few numbers, and to rearrange an operator or two, so they aren't split over both lines. That gives us a working version with size 12 x 8... one off the requirement. So we just add two lines that don't do anything (push a 1, pop a 1, push a 1, pop a 1...), so get to 12 x 10:

{`"_~"      
      +{129X
$,m2/S      
      *a_+\*
N/6f/1      
      ;1;1;1
;1;1;1      
      ;Wf%N*
}_`'"#      
      )!*}_~

As the previous one this produces

      {`"_~"
+{129X      
      $,m2/S
*a_+\*      
      N/6f/1
;1;1;1      
      ;1;1;1
;Wf%N*      
      }_`'"#
)!*}_~      

(Side note: there is no need to keep alternating left and right on the intermediate lines, only the position of the first and last line are important. Left and right can be chosen arbitrarily for all other lines.)

And through pure coincidence, the full quine also still works:

{`"_~"{`"_~"
+{129X+{129X
$,m2/S$,m2/S
*a_+\**a_+\*
N/6f/1N/6f/1
;1;1;1;1;1;1
;1;1;1;1;1;1
;Wf%N*;Wf%N*
}_`'"#}_`'"#      
)!*}_~)!*}_~

(I say coincidence, because the part that takes care of not executing the inner code now gets weirdly interspersed with the other quine, but it still happens to work out fine.)

That being said, I could have just added 44 lines of 1; to my original submission to fulfil the bounty requirement, but 12 x 10 looks a lot neater. ;)

Edit: Haha, when I said "pure coincidence" I couldn't have been more spot on. I looked into how the final quine now actually works, and it's absolutely ridiculous. There are three nested blocks (4 actually, but the innermost is irrelevant). The only important part of the innermost of those 3 blocks is that it contains a " (and not the one that it did in the original submission, but the very '" that is used at the end to check for this same character). So the basic structure of the quine is:

{`"_~"{`"_~"+{___'"___}_`'"#)!*}_~)!*}_~

Let's dissect that:

{`"_~"                               }_~ "The standard CJam quine.";
      {`"_~"+                  }_~       "Another CJam quine. Provided it doesn't do 
                                          anything in the rest of that block, this 
                                          will leave this inner block as a string on 
                                          the stack.";
                                  )      "Slice the last character off the string.";
                                   !     "Negate... this yields 0.";
                                    *    "Repeat the string zero times.";

So this does indeed do some funny magic, but because the inner block leaves a single string on the stack, )!* happens to turn that into an empty string. The only condition is that the stuff in the inner block after + doesn't do anything else to the stack, so let's look at that:

             {___'"___}                  "Push a block which happens to contain 
                                          quotes.";
                       _`'"#)!*          "This is from the original code and just 
                                          removes the block if it does contain 
                                          quotes.";
\$\endgroup\$
4
  • 4
    \$\begingroup\$ TLDR; upvote ;) \$\endgroup\$
    – Optimizer
    Dec 2, 2014 at 17:40
  • \$\begingroup\$ Shouldn't it be Y/2 in the combined quine? \$\endgroup\$
    – schnaader
    Dec 3, 2014 at 8:48
  • \$\begingroup\$ "And through pure coincidence" nah ;) \$\endgroup\$
    – Timtech
    Dec 5, 2014 at 23:52
  • \$\begingroup\$ @Timtech See my edit. Pure coincidence was not an understatement. ^^ \$\endgroup\$ Dec 5, 2014 at 23:57
17
\$\begingroup\$

CJam, (51 49 47 46 45 42 x 2) * 48% = 40.32

{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~ 
                                         R

Running the above code gives this output:

                                         R
{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~ 

running which, prints back the original source.

The source and the output are simply swapped lines.

Now comes the magic.

Overlapping the source and the output results into the following code:

{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~R
{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~R

which is a perfect quine!

Try them online here


How it works

All the printing logic is in the first line itself which handles all three cases explained later.

{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~
{                                     }_~   "Copy this code block and execute the copy";
 ]                                          "Wrap everything before it in array";
  )                                         "Pop the last element out of it";
   "_~"+                                    "Append string '_~' to the copied code block";
        S41*                                "Create a string of 41 spaces";
            'R+                             "Append character R to it";
               @,                           "Rotate the array to top and get its length";
                 [{   }{   }{     }]=~      "Get the corresponding element from this"
                                            "array and execute it";

The array in the last line above is the array which has code blocks corresponding to all three cases.

Case 1

{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~ 
                                         R

In this case, the length of remaining stack was 0 as when the block was executed, it only had the copy of the block itself, which was initially popped out in the third step above. So we take the index 0 out of the last array and execute it:

 {N@S}          "Note that at this point, the stack is something like:"
                "[[<code block that was copied> '_ '~ ] <41 spaces and R string>]";
  N             "Add newline to stack";
   @            "Rotate the code block to top of stack";
    S           "Put a trailing space which negates the original R";

In this case, the second line is a no-op as far as printing the output is concerned.

Case 2

                                         R
{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~ 

In this case, the stack already contained an empty string, so when the copied code block was executed, it had 2 elements - an empty string and the code block itself. So we take the index 1 out of the last array and execute it:

{SN@}            "Note at this point, the stack is same as in case 1";
 SN              "Push space and newline to stack";
   @             "Rotate last three elements to bring the 41 spaces and R string to top";

Case 3

{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~R
{])"_~"+S41*'R+@,[{N@S}{SN@}{W=N]_}]=~}_~R

In this case, the stack has 6 elements. So after popping the last code block, remaining array length is 5. We take the index 5 out of the array and execute it. (Note that in a array of 3 elements, index 5 is index 5%3 = 2)

{W=N]_}          "Note at this point, the stack is same as in case 1";
 W=              "Take the last character out of the 41 spaces and R string, i.e. R";
   N]            "Add a new line to stack and wrap the stack in an array";
     _           "Copy the array to get back the source of Case 3 itself";
\$\endgroup\$
10
\$\begingroup\$

CJam, 42 37 33 x 2 = 66

{`As_W%er"_~"+S 33*F'Lt1{\}*N\}_~
               L                 

which prints

               L                 
{`As_W%er"_~"+S 33*F'Lt0{\}*N\}_~

(The lines are swapped, and a 1 turns into a 0.)

Test it here.

How it works

First, you should understand the basic CJam quine:

{"_~"}_~

The braces simply define a block of code, like a function, that isn't immediately executed. If an unexecuted block remains on the stack, it's source code (including braces) is printed. _ duplicates the block, and ~ executes the second copy. The block itself simply pushes the string containing _~. So this code, leaves the stack in the following state:

Stack: [{"_~"} "_~"]

The block and the string are simply printed back-to-back at the end of the program, which makes this a quine.

The beauty of this is that we can do whatever we want in the block, and it remains a quine, because each piece of code will automatically be printed in the block contents. We can also modify the block, by obtaining it's string representation with ` (which is just a string of the block with braces).

Now let's look at this solution. Notice that either part of the mutual quine contains of the quine-like block with _~, and an L. The L pushes an empty string onto the stack, which doesn't contribute to the output. So here is what the block does:

`                             "Convert block to its string representation.";
 As                           "Push 10 and convert to string.";
   _W%                        "Duplicate and reverse, to get another string 01.";
      er                      "Swap 0s and 1s in the block string.";
        "_~"+                 "Append _~.";
             S 33*            "Push a string with 33 spaces.";
                  F'Lt        "Set the character at index 15 to L.";
                      1{ }*   "Repeat this block once.";
                        \     "Swap the code string and the space string.";
                           N\ "Push a newline and move it between the two lines.";

So this will do the quine part, but exchange a 1 for a 0, and it will also prepend another line with an L, where the code above has a space. The catch is that the order of those two lines is determined by the swapping inside { }*. And because the outer part of the mutual quine has the 0 in front of it replaced by a 1, it never executes this swap, and hence produces the original order again.

\$\endgroup\$
6
\$\begingroup\$

CJam, 27 × 2 = 54

{ ` " _ ~ " + N - ) 2 * ' '
 > @ t s G B + / N * } _ ~ 

Output:

 { ` " _ ~ " + N - ) 2 * ' 
' > @ t s G B + / N * } _ ~

'A'B> compares the characters A and B. ' '\n > returns 1 because 32>10 and ' \n' > returns 0 because the two spaces are equal.

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

CJam, 30 29 x 2 = 58

{"_~"SN]_,4=S28*'R+\{N@}*}_~ 
                            R

Outputs:

                            R
{"_~"SN]_,4=S28*'R+\{N@}*}_~ 

which outputs the original source.

This is based on the same principal as my other solution.

Try it online here

\$\endgroup\$
3
+100
\$\begingroup\$

Klein, 2*96 = 192

 \                                                                                           1
< (!.:!.?!|84*:999*+2+$<::::::]]]]]]]77*55+<)!.:!.?!>(84*2+@*77]]]]]]]::::::<$*77:*48+55+2*48 <"

Try it online!

< 84*2+55+84*:77*$<::::::]]]]]]]77*@+2*48(>!?.!:.!)<+55*77]]]]]]]::::::<$+2+*999:*48|!?.!:.!( <"
 1                                                                                           1

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Do you think this is possible in Lost? \$\endgroup\$
    – emanresu A
    Dec 26, 2021 at 0:00
  • \$\begingroup\$ @emanresuA I think it is. It would be pretty hard though. \$\endgroup\$
    – Wheat Wizard
    Dec 26, 2021 at 0:47

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.