27
\$\begingroup\$

Write the smallest program that maps strings injectively to outputs and maps itself to 2020.

To be clear, your program \$p\$ must have the following properties:

  1. every possible input string \$s\$ has a well-defined output \$p(s)\$,
  2. for every pair of strings \$s\$ and \$t\$ with \$s\neq t\$, it holds that \$p(s)\neq p(t)\$, and
  3. \$p(p)=2020\$.

Be sure to explain why your submission satisfies properties 1 and 2. For property 3, the output can be a string or any type of number.

Edit 1: Programs need to be proper quine variants. Reading the source code is not allowed.

Edit 2: Note that as a consequence of property 2, it holds that \$p(s)\neq p(p)\$ for every \$s\neq p\$.

\$\endgroup\$
  • \$\begingroup\$ every possible input string Can we support only ASCII? \$\endgroup\$ – Luis Mendo Jan 4 at 18:15
  • 1
    \$\begingroup\$ @LuisMendo - yes, provided ASCII is the alphabet of the language that your program is written in. \$\endgroup\$ – Dustin G. Mixon Jan 4 at 18:16
  • 7
    \$\begingroup\$ Do programs need to be proper quine variants or is reading the source code allowed? \$\endgroup\$ – FlipTack Jan 4 at 19:06
  • 1
    \$\begingroup\$ @FlipTack - Thanks for the clarifying question. No reading the source code. I edited the post to reflect this. \$\endgroup\$ – Dustin G. Mixon Jan 4 at 19:37
  • 1
    \$\begingroup\$ @RobinRyder - A function is acceptable. \$\endgroup\$ – Dustin G. Mixon Jan 4 at 19:41

10 Answers 10

48
\$\begingroup\$

awk, 4 bytes

The structure of an awk program is pattern { action }. If pattern evaluates to true, { action } is performed. If { action } is omitted, the default is to output the current input record.

Code:

2020

As 2020 always evaluates to true, the program always prints it's input, therefore satisfying properties 1. and 2. When the input is the program itself it satisfies property 3. \$p(p)=2020\$ — even \$p(p)=p\$.

Some test cases:

$ echo 2020 | awk '2020'
2020
$ echo 0 | awk '2020'
0
$ echo "" | awk '2020'

$ echo foo | awk '2020'
foo

Would've been more glorious back in the good old days:

$ echo 1 | awk '1'
1
\$\endgroup\$
  • 10
    \$\begingroup\$ polyglot with perl5 -p \$\endgroup\$ – Nahuel Fouilleul Jan 6 at 9:22
  • 1
    \$\begingroup\$ Nice James, thank you for sharing the same :) \$\endgroup\$ – RavinderSingh13 Jan 7 at 6:41
  • 2
    \$\begingroup\$ Also polyglot with Perl 6 -p. \$\endgroup\$ – nwellnhof Jan 7 at 12:59
12
\$\begingroup\$

JavaScript (ES6), 23 bytes

Returns either the input string with a leading \$0\$, or \$2020\$ if the input is the program.

f=s=>s=='f='+f?2020:0+s

Try it online!


JavaScript (Node.js), 76 bytes

Generates a unique BigInt by using each byte of the input string, then applies a XOR to the result in such a way that \$f(f)=2020\$.

f=s=>(g=s=>Buffer(s).every(b=>t=t<<8n|BigInt(b),t=1n)&&t)(s)^g('f='+f)^2020n

Try it online!

\$\endgroup\$
  • \$\begingroup\$ The first one does not match criteria 2, as it will output the same result for different input strings \$\endgroup\$ – Skyler Jan 6 at 20:09
  • 2
    \$\begingroup\$ @Skyler Please note that the input is a string and so is 0+s. If a and b are 2 distinct strings, so are 0+a and 0+b. \$\endgroup\$ – Arnauld Jan 6 at 20:11
  • \$\begingroup\$ I think this doesn't satisfy the "do not read the source code" condition, right? \$\endgroup\$ – Tomáš Zato - Reinstate Monica Jan 7 at 9:55
  • 1
    \$\begingroup\$ @TomášZato-ReinstateMonica Last time I checked, I think Dennis' answer about that was the most upvoted, but it seems like we still don't have a clear concensus. (Also, this requirement did not exist at the time I answered the challenge.) \$\endgroup\$ – Arnauld Jan 7 at 10:29
  • \$\begingroup\$ You can check the revision change on codegolf.stackexchange.com/revisions/197679/2 which was at 2020-01-04 19:36:35Z while this answer was posted on 2020-01-04 17:08:36Z - almost 2 hours and a half after this answer was posted. On that edit, the tag "quine" as added as well. \$\endgroup\$ – Ismael Miguel Jan 7 at 12:08
7
\$\begingroup\$

Python 3.8 (pre-release), 81 60 59 57 56 bytes

-21 Thanks to Jo King

Outputs 2020 if the input matches the program, otherwise the input concatenated to itself 5 time (eg. abc becomes abcabcabcabcabc)

exec(a:='print(5*[i:=input(),404][i=="exec(a:=%r)"%a])')

Try it online!


Python 3.8 (pre-release), 77 67 65 bytes

-10 Thanks to Jo King

Outputs 2020 if the input matches the program, otherwise the input concatenated to itself 5 time (eg. abc becomes abcabcabcabcabc)

lambda s:5*[s,404][s==(a:='lambda s:5*[s,404][s==(a:=%r)%%a]')%a]

Try it online!

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

Ruby -n, 45 bytes

Based on one of the classic Ruby quines, _="_=%p;puts _%%_";puts _%_. Prints 2020 if the input is the source, otherwise prints the Ruby representation of the input (encapsulated in quotes, various characters like " and \ are escaped, etc.)

_="_=%p;p$_==_%%_ ?2020:$_";p$_==_%_ ?2020:$_

Try it online!

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

Jelly, 16 bytes

“Ṿ;⁾v`³⁽¥ŒṾ⁼?”v`

Try it online!

A full program that takes a string as its input. It outputs an unevaluated Jelly version of the input unless provided with itself, in which case it outputs 2020.

Thanks to @JonathanAllan for pointing out a flaw in my original version!

Explanation

 “Ṿ;⁾v`³⁽¥ŒṾ⁼?”v` | Evaluate as Jelly code the following, using itself as the argument:
  Ṿ               | - Unevaluate (effectively wraps string back into “”
   ;⁾v`           | - Append "v`"
       ³    ⁼?    | - If equal to the program’s argument:
        ⁽¥Œ       | - Then: 2020 (compressed integer)
           Ṿ      | - Else: Unevaluated version of the program’s original argument
\$\endgroup\$
  • \$\begingroup\$ Hmm, not sure it's valid without bracketing or something - TIO EDIT - how about this? \$\endgroup\$ – Jonathan Allan Jan 5 at 0:42
  • \$\begingroup\$ @JonathanAllan I don’t follow. Although it will follow standard Jelly implicit printing rules, the output should still be unique for any given input. The question doesn’t seem to put any further criteria on what the output consists of. Thanks for your suggestion; while it works, I’m still not sure why I can’t just continue to use O. \$\endgroup\$ – Nick Kennedy Jan 5 at 0:46
  • \$\begingroup\$ There is an s (ߤ) for which p(s) = p(p) (2020) \$\endgroup\$ – Jonathan Allan Jan 5 at 0:49
  • 1
    \$\begingroup\$ Oh I see. I now also follow your comment to the question. For now, I’ll update to your version if that’s ok. Thanks! \$\endgroup\$ – Nick Kennedy Jan 5 at 0:50
  • 1
    \$\begingroup\$ Was just about to suggest it! \$\endgroup\$ – Jonathan Allan Jan 5 at 0:55
2
\$\begingroup\$

Raku, 47 bytes

<say "<$_>~~.EVAL"eq($!=get)??2020!!@$!>~~.EVAL

Try it online!

Outputs 2020 if the input matches the program, otherwise the input surrounded in brackets.

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

05AB1E, 28 bytes

"34çìD«QiŽ7ìëû"34çìD«QiŽ7ìëû

Try it online or verify a few more test cases.

Explanation:

"34çìD«QiŽ7ìëû"            # Push this string
               34ç         # Push 34, and convert it to a character: '"'
                  ì        # Prepend it in front of the string
                   D«      # Append a copy of the string to itself
                     Qi    # If it's equal to the (implicit) input:
                       Ž7ì #  Push compressed integer 2020
                      ë    # Else:
                       û   #  Palindromize the (implicit) input
                           # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž7ì is 2020.

\$\endgroup\$
  • \$\begingroup\$ Might work ... only problem is an empty string? \$\endgroup\$ – Expired Data Jan 6 at 15:17
  • 1
    \$\begingroup\$ @ExpiredData The м should be K, otherwise any input containing only characters of the input (i.e. DD) would also result in 2020. But apart from that the empty string is indeed a problem I'm not sure how to overcome. :( \$\endgroup\$ – Kevin Cruijssen Jan 6 at 16:37
  • 2
    \$\begingroup\$ @ExpiredData the empty string is far from the only problem. Appending the code to any string doesn't change the output (example). It seems highly unlikely you can make something injective with either м or K, since those fundamentally lose information. \$\endgroup\$ – Grimmy Jan 7 at 12:49
  • \$\begingroup\$ Yeah @Grimmy thanks great point \$\endgroup\$ – Expired Data Jan 7 at 14:32
2
\$\begingroup\$

C (gcc), 190 196 194 192 180 176 bytes

Thanks to Jo King for pointing out a bug.

Trailing newline seems accepted in some other answers, so will use that to fix a bug pointed out by NieDzejkob. (Also -12 bytes thanks to the same.)

-4 bytes thanks to @ceilingcat.

Assumes little-endian, ASCII, sizeof(int) >= 4, all the good stuff.

Outputs the input string preceded by a dollar sign, unless given its own source code, in which case it outputs 2020.

*s="*s=%c%s%1$c,u[99]={'0202'};f(int*t){puts(bcmp(u+2,t,sprintf(u+2,s,34,s))?putchar(36),t:u);}",u[99]={'0202'};f(int*t){puts(bcmp(u+2,t,sprintf(u+2,s,34,s))?putchar(36),t:u);}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ which is a different output than the empty string \$\endgroup\$ – a'_' Jan 6 at 8:53
  • 1
    \$\begingroup\$ The requirement is that no two distinct inputs should have the same output. \$\endgroup\$ – justhalf Jan 6 at 10:50
  • \$\begingroup\$ @JoKing Good point! (Hopefully) Corrected now. \$\endgroup\$ – gastropner Jan 6 at 10:56
  • \$\begingroup\$ @NieDzejkob The number will vary between implementations no doubt. Cheers! \$\endgroup\$ – gastropner Jan 6 at 17:44
  • \$\begingroup\$ @gastropner Now 2020 corresponds to the input of the old program... \$\endgroup\$ – NieDzejkob Jan 6 at 18:10
0
\$\begingroup\$

J, 56 bytes

".a=.}:0 :0
echo@>2020[^:(]-:'".a=.}:0 :0',LF,a&[)1!:1[3

Try it online!

A full program. Unless provided with itself prints each character on a separate line.

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

Java 10, 128 bytes

s->{var t="s->{var t=%c%s%1$c;t=t.format(t,34,t);return t.equals(s)?2020:0+s;}";t=t.format(t,34,t);return t.equals(s)?2020:0+s;}

Try it online.

Explanation:

part of the explanation:

  • var t contains the unformatted source code
  • %s is used to input this String into itself with t.format(...)
  • %c, %1$c, and the 34 are used to format the double quotes
  • t.format(t,34,t) puts it all together

Challenge part of the explanation:

  • t.equals(s) checks if the input-String is equal to the source code
  • ?2020: if it is, return 2020 as result
  • :0+s: if not, return the input-String with a prepended 0 as result instead
\$\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.