31
\$\begingroup\$

Challenge

Make two programs, A and B, which are both cat programs in the same language. When concatenated, AB (also in the same language) should be a quine.

For example, suppose hello and world are both cat programs in language XYZ. If helloworld is a quine in said language, then your solution is valid.

For those of you unfamiliar with cats and quines, a cat program is one that prints exactly what was given to it via stdin and a quine is a program that prints its own source code.

Scoring and Rules

  • The total byte count of the concatenated AB program is your score. As this is code golf, the lowest score wins.
  • Standard loopholes are forbidden
  • Input must be taken from stdin and output must go to stdout.
  • The cat programs do not need to take arguments; they only need to copy stdin to stdout.
  • The quine should work when the program is given no input, but does not have to work correctly (but may) for other inputs.
  • The quine does not need to terminate, provided it prints exactly its source code once, nothing more.
  • The quine needs to be at least one byte long.
  • A and B can be the same program.
  • BA does not need to be a quine or even a valid program.
\$\endgroup\$
  • \$\begingroup\$ I don't think you should have the A and B can be same program rule \$\endgroup\$ – Muhammad Salman Jun 1 '18 at 16:42
  • 1
    \$\begingroup\$ @MuhammadSalman My original idea was to have a cat program be doubled to turn into a quine. I just wanted to open the door to easier solutions because I wasn't entirely sure it was possible. Looks like I was wrong on both counts, but I'm fine with that. \$\endgroup\$ – Beefster Jun 1 '18 at 16:46
  • 3
    \$\begingroup\$ You should probably add that AB must be non-empty, since lots of languages have a 0-byte cat allowing for a 0-byte quine. \$\endgroup\$ – DJMcMayhem Jun 1 '18 at 16:50
  • 9
    \$\begingroup\$ @DJMcMayhem a 0-byte quine wouldn't be a valid quine though. \$\endgroup\$ – Stephen Leppik Jun 1 '18 at 16:52
  • 4
    \$\begingroup\$ What is a cat program? \$\endgroup\$ – Pedro A Jun 1 '18 at 22:21

14 Answers 14

31
\$\begingroup\$

V, 2 + 2 == 4 bytes

2i2i

Try the quine!

Try the cat!

A is 2i

B is also 2i

How does it work?

First off, some explanations of how V works. One notable thing that makes this answer possible is that in V, the empty program is a cat program. This isn't a special case, it's inherent to how V operates. On startup, all input is loaded into a "buffer", each command modifies the buffer in someway, and then when the program is done, the buffer is implicitly printed. This means that any string of NOPs is also a cat program.

The i command means enter insert mode, which means every character following an i will be added into the buffer. With a number preceding it, that text will be duplicated n times.

This means that for the cat program, nothing will be added to the buffer, and it will be printed as it was read. In other words:

        " (Implicitly) Load all input
2       " 2 times,
 i      " Insert the following text into the buffer...
        " (nothing)
        " (Implicitly) Print the buffer

But for the quine, there is text after the i:

2       " 2 times,
 i      " Insert the following text into the buffer...
  2i    "   "2i"
        " (Implicitly) Print the buffer

Cheeky non-answer

V, 0 bytes

Try it online!

A is the empty program.

B is also the empty program.

:P

\$\endgroup\$
  • 20
    \$\begingroup\$ Every other language: Oy, we've hit a dead end!. V: *posts standard quine*. \$\endgroup\$ – Erik the Outgolfer Jun 1 '18 at 20:15
13
\$\begingroup\$

Ruby, 71 bytes

2;puts (<<2*2+?2)[/.+2/m]||$<.read
2;puts (<<2*2+?2)[/.+2/m]||$<.read
2

Can be broken up into cats as follows:

2;puts (<<2*2+?2)[/.+2/m]||$<.read
2

and

;puts (<<2*2+?2)[/.+2/m]||$<.read
2

The two cats are identical except for the leading 2, which is a no-op in all three programs. The <<2 is a herestring, meaning that everything starting on the next line until a terminating 2 on its own line is a string, which we concatenate to itself (*2) and append a trailing 2. In the cats the herestring is well-formed but empty, so the regular expression won't match it and we'll fall through to the $<.read expression and output STDOUT. Once we concat the cats, though, the string won't terminate until the third line, so the regex matches and we short-circuit and output the quine.

\$\endgroup\$
11
\$\begingroup\$

Pyth, 29 bytes (5 + 24) 27 bytes (5 + 22)

pz=T0?TzjN*2]"pz=T0?TzjN*2]     # Quine
pz=T0                           # Cat A
     ?TzjN*2]"pz=T0?TzjN*2]     # Cat B

That was fun.
Try the quine here
Try the first cat here
Try the second cat here

Explanations

Cat A
pz=T0
pz       Print the input.
  =T0    (Irrelevant for cat)

Cat B
?TzjN*2]"pz=T0?TzjN*2]
?Tz                      If T (10) is truthy, output the input.
   jN*2]"pz=T0?TzjN*2]   (Irrelevant for cat)

Quine
pz=T0?TzjN*2]"pz=T0?TzjN*2]
pz                            Print the (empty) input (without a newline).
  =T0                         Set T to 0.
     ?Tz                      If T (0) is truthy, output the input.
             "pz=T0?TzjN*2]   Otherwise, get this string...
          *2]                 ... take two copies...
        jN                    ... and join them with a quote.
\$\endgroup\$
11
\$\begingroup\$

C# (Visual C# Compiler), 551 bytes

A: 95 bytes

class A{public static int i=2;static void Main(string[]args){System.Console.Write(args[0]);}}//

Try it online!

B: 438 + 18 bytes

class A{public static int i=0;}
class B{static void Main(string[]args){if(A.i<1){System.Console.Write(args[0]);return;}var a=@"class A{{public static int i=2;static void Main(string[]args){{System.Console.Write(args[0]);}}}}//class A{{public static int i=0;}}
class B{{static void Main(string[]args){{if(A.i<1){{System.Console.Write(args[0]);return;}}var a=@{0}{1}{0};System.Console.Write(a,'{0}',a);}}}}";System.Console.Write(a,'"',a);}}

Try it online!

A+B: 533 + 18 bytes

class A{public static int i=2;static void Main(string[]args){System.Console.Write(args[0]);}}//class A{public static int i=0;}
class B{static void Main(string[]args){if(A.i<1){System.Console.Write(args[0]);return;}var a=@"class A{{public static int i=2;static void Main(string[]args){{System.Console.Write(args[0]);}}}}//class A{{public static int i=0;}}
class B{{static void Main(string[]args){{if(A.i<1){{System.Console.Write(args[0]);return;}}var a=@{0}{1}{0};System.Console.Write(a,'{0}',a);}}}}";System.Console.Write(a,'"',a);}}

Try it online!

A and B take input as a command-line argument. A+B ignores any input. 18 bytes on B and A+B are added for the /p:StartupObject=B option sent to MSBuild. It's only strictly necessary on A+B, but it seemed like cheating to not also have it in B. This way, the compiler flags for A+B are the compiler flags for A (none) plus the compiler flags for B.

Explanation

Program A is straightforward. Class A contains an (unused) static variable i initialized to 2, and prints its first argument when run. The // at the end is important for the A+B code, but does nothing in A itself.

Program B is weird in isolation, but essentially the same. It creates a Class A containing a static variable i initialized to 0, and then runs the Main method of Class B, which does the same as Program A because A.i is less than 1, and returns before any of the weird stuff. The newlines aren't necessary here, but are important for A+B.

When combined, the // from Program A comments out the Class A declaration from Program B, but because of the newline Class B is fine, allowing A.i to refer to the 2 value from Program A instead. The Compiler Flag makes the Program run B.Main() since A.Main() also exists. The result is that Program A+B does not output its argument, but instead goes to the following segment of B.Main(), which is basically just the standard C# quine.

\$\endgroup\$
  • 1
    \$\begingroup\$ "the cat programs...need to copy stdin to stdout" \$\endgroup\$ – Jakob Jun 2 '18 at 1:59
9
\$\begingroup\$

Haskell, 116 + 20 = 187 175 174 136 bytes

A bunch of bytes saved since Ørjan Johansen showed me interact

Cat 1

g=";main|idmain<-(++\"g=\"++show g++g)=interact idmain|1>0=interact id";main|idmain<-(++"g="++show g++g)=interact id

Try it online!

Cat 2

main|1>0=interact id

Try it online!

Quine

g=";main|idmain<-(++\"g=\"++show g++g)=interact idmain|1>0=interact id";main|idmain<-(++"g="++show g++g)=interact idmain|1>0=interact id

Try it online!


The basic principle at work here is that when we add the second cat to the first we change the name of the function we are interacting with from a to idmain. Since interact id is a cat we want idmain to me a function that returns a quine. The obvious solution would be to use const, however since we can assume the input is empty (++) works as well. From here we find the source code via pretty standard means, we have a variable g that encodes the source and we use a special wrapper to print it in string form and code form. There is a slight exception that we need to put our encoder at the front because we already need to end with interact id. This means an extra g= is not encoded and has to be handled manually. Our next cat is pretty standard except we need to make it valid code when tacked on to the end of the other cat so we need both cats to be instances of pattern guards.

Alternative Strategy, 43 + 105 = 186 148

Cat 1

g="";main|idmain<-(++g++show g)=interact id

Try it online!

Cat 2

main|1>0=interact id where g="g=\"\";main|idmain<-(++g++show g)=interact idmain|1>0=interact id where g="

Try it online!

Quine

g="";main|idmain<-(++g++show g)=interact idmain|1>0=interact id where g="g=\"\";main|idmain<-(++g++show g)=interact idmain|1>0=interact id where g="

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You can shorten that quite a bit by replacing getContents + putStr with interact id. Try it online! (The quine no longer works with non-empty input, which allows using a (++ ...) section for the idmain.) \$\endgroup\$ – Ørjan Johansen Jun 2 '18 at 0:47
  • \$\begingroup\$ @ØrjanJohansen Thanks! I didn't know about interact, I guess that's because I rarely do IO stuff with Haskell. I've editted the post. \$\endgroup\$ – TRITICIMAGVS Jun 2 '18 at 1:16
8
\$\begingroup\$

Python 3, 286 bytes

My first Python golf and my first quine! Not very elegant, but it works.

Program A (238 bytes)

from atexit import*;s="from atexit import*;s=%r;register(lambda:print(end='b'in globals()and s%%s or open(0).read()));b=0\nif's'not in vars():print(end=open(0).read())";register(lambda:print(end='b'in globals()and s%s or open(0).read()));

(no trailing newline)

Program B (48 bytes)

b=0
if's'not in vars():print(end=open(0).read())

(no trailing newline)

Try It Online

Acknowledgments

  • -24 bytes thanks to Jo King
  • -82 bytes thanks to Jo King
\$\endgroup\$
  • \$\begingroup\$ You can do end=open... and use %r instead of %s to not have to do the newline and quotes \$\endgroup\$ – Jo King Jun 2 '18 at 1:28
  • \$\begingroup\$ Cool, I switched to %r. Not sure what you mean about the newline though. \$\endgroup\$ – Jakob Jun 2 '18 at 6:02
  • 1
    \$\begingroup\$ Instead of %s to format a newline in, you can just do the literal \n. You can also use ; to split statements instead of \n (except the if needs to be on its own line). % can be escaped in the string by doing %%. The only argument needed to format the string is the string itself, everything else can be striped \$\endgroup\$ – Jo King Jun 2 '18 at 7:49
  • 1
    \$\begingroup\$ Program B (and the text for it) can use locals() to save 2 bytes. \$\endgroup\$ – Jonathan Allan Jun 2 '18 at 14:49
6
\$\begingroup\$

C++ (clang), 313 + 102 = 415 bytes

Program A (ends in a newline):

#include<cstdio>
#define Q(x,y)#x,B=#y;x
int c;auto I="#include<cstdio>",A=Q(int main(){if(c)printf("%s\n#define Q(x,y)#x\",\"#y;x\nint c;auto I=\"%s\",A=Q(%s,)\n#ifdef Q\nint n=++c;\n#else\n%s\n%s\n#endif",I,I,A,I,B);else while((c=getchar())>=0)putchar(c);},int c;int main(){while((c=getchar())>=0)putchar(c);})

Program B (does not end in newline):

#ifdef Q
int n=++c;
#else
#include<cstdio>
int c;int main(){while((c=getchar())>=0)putchar(c);}
#endif

Not terribly sneaky, and as usual C++ isn't that great for quining. I won't be surprised if there are ways to shave bytes here and there off the same idea. The one little catch is changing the behavior of something after it's been defined, and a dynamic variable initializer with side effect does the trick. (Can this even be done in C without compiler extensions?)

Try it online: A, B, AB

(The only portability concern I'm aware of is that the program assumes <cstdio> puts names both in the global namespace and in std.)

\$\endgroup\$
5
\$\begingroup\$

Befunge-98 (FBBI), 8 + 15 = 23 bytes

A + B: (only works for no input)

+9*5~,#@#@~,9j>:#,_:@#"

Try it online!

A:

+9*5~,#@

Try it online!

B:

#@~,9j>:#,_:@#"

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I was wondering if someone would manage a befunge answer. It's too bad this one isn't 2D :-/ \$\endgroup\$ – Beefster Jun 1 '18 at 22:44
  • \$\begingroup\$ @Beefster yeah. The problem is it’s pretty hard to do a 2d Quine. Maybe I’ll work on something though \$\endgroup\$ – MildlyMilquetoast Jun 1 '18 at 22:45
5
\$\begingroup\$

Python 3, 100 + 37 = 137 bytes

Program A:

s='s=%r;print(end=open(0).read())#print(end=open(0).read())\nprint(s%%s)';print(end=open(0).read())#

Try it online!

Program B:

print(end=open(0).read())
print(s%s)

Try it online!

Make Quine AB

s='s=%r;print(end=open(0).read())#print(end=open(0).read())\nprint(s%%s)';print(end=open(0).read())#print(end=open(0).read())
print(s%s)

Try it online!

Only works when input is empty, otherwise it prepends the input to the output.

\$\endgroup\$
  • \$\begingroup\$ The double quotes should be single ones. \$\endgroup\$ – Jonathan Allan Jun 2 '18 at 14:57
  • \$\begingroup\$ Crashing is allowed? \$\endgroup\$ – Jakob Jun 2 '18 at 23:13
  • \$\begingroup\$ @Jakob The question doesn't say that crashing is not allowed, and typically output to STDERR is ignored \$\endgroup\$ – Jo King Jun 4 '18 at 5:07
  • \$\begingroup\$ Ok, fair enough. Clever shortcuts! \$\endgroup\$ – Jakob Jun 4 '18 at 6:55
4
\$\begingroup\$

Attache, 15 + 126 = 141 bytes

A:

AllInput[]|Echo

Try it online!

B:

@{If[_,s.="AllInput[]|Echo@{If[_,s.=%s;;Printf[s,Repr!s],AllInput[]|Echo]es}|Call";;Printf[s,Repr!s],AllInput[]|Echo]es}|Call

Try it online!

A + B:

AllInput[]|Echo@{If[_,s.="AllInput[]|Echo@{If[_,s.=%s;;Printf[s,Repr!s],AllInput[]|Echo]es}|Call";;Printf[s,Repr!s],AllInput[]|Echo]es}|Call

Try it online!

Explanation

Each of the cat program encodes AllInput[]|Echo, which is a simple cat program. B is the main quine phase; alone, it is a vectorized function (through unary @) called with no inputs (being called as |Call). Thus, the first conditional If[_,A,B] executes B, which is simply AllInput[]|Echo.

When A + B is executed, unary @ becomes binary @ due to Echo merging with the lambda:

AllInput[]|Echo@{If[_, ...

Now, this means that the lambda is executed before Echo is. Back to the conditional, this function now has all of STDIN as an argument. So, If[_,A,B] executes A, which is the standard quine framework.

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

Stax, 16 + 12 = 28 bytes

Cat 1:

"yi|d|ca34b4lr"y

Run and debug it

"yi|d|ca34b4lr"y Full program, implicit input
"yi|d|ca34b4lr"  Push the string
               y Push raw input
                 Implicit output of top item

Cat 2:

i|d|ca34b4lr

Run and debug it

i|d|ca34b4lr Full program, implicit input
i            Don't parse input (prefix directive)
 |d          Push main stack depth, always zero
   |c        Cancel because top item is falsy, and implicitly print
     a34b4lr Never executed

Quine:

"yi|d|ca34b4lr"yi|d|ca34b4lr

Run and debug it

"yi|d|ca34b4lr"yi|d|ca34b4lr Full program
"yi|d|ca34b4lr"              Push the string
               y             Push input
                i            No-op
                 |d          Push main stack depth, i.e. 2
                   |c        Do nothing because top is truthy
                     a       Get the string to the top
                      34     Push 34 (charcode of ")
                        b    Copy both
                         4l  Listify top 4
                           r Reverse
                             Implicit output
\$\endgroup\$
3
\$\begingroup\$

Cat 1 :

Lua, 41 bytes

a=io.read;while a(0)do io.write(a(1))end;

Try it online!


Cat 2 :

Lua, 70 bytes

if a then io.input(arg[0])end;a=io.read;while a(0)do io.write(a(1))end

Try it online!


Quine :

Lua, 111 bytes

a=io.read;while a(0)do io.write(a(1))end
if a then io.input(arg[0])end;a=io.read;while a(0)do io.write(a(1))end

Try it online!

io.input(arg[0]) in Cat 2 sets the current file as standard input, and as a result, the cat prints the source code

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG \$\endgroup\$ – Muhammad Salman Jun 3 '18 at 15:10
  • \$\begingroup\$ You can save one byte in cat 1 by removing the last semi-colon ? \$\endgroup\$ – Muhammad Salman Jun 3 '18 at 15:45
  • \$\begingroup\$ Unfortunately, reading the current file is a standard loophole. But nice try anyway. \$\endgroup\$ – Beefster Jun 4 '18 at 17:06
2
\$\begingroup\$

><>, 12 +3 = 15 bytes

Program A:

<oi

Try it online!

And Program B:

>i!o|o<}*d3'

Try it online!

Make Program AB:

<oi>i!o|o<}*d3'

Try it online!

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

JavaScript (Node.js), 199 bytes


a=()=>console.log(require('fs').readFileSync(0)+'');a();var a=a||0;b=()=>console.log(require('fs').readFileSync(0)+'');!a?b():c=()=>console.log(`a=${a};a();var a=a||0;b=${b};!a?b():c=${c},c()`),c()

Try it online!

Cat A, 57 bytes


a=()=>console.log(require('fs').readFileSync(0)+'');a();

Try it online!

Cat B, 142 bytes

var a=a||0;b=()=>console.log(require('fs').readFileSync(0)+'');!a?b():c=()=>console.log(`a=${a};a();var a=a||0;b=${b};!a?b():c=${c},c()`),c()

Try it online!

\$\endgroup\$

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.