Write a program that sees the New Year in itself

29

3

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\$.

Dustin G. Mixon

Posted 2020-01-04T16:23:09.597

Reputation: 1 833

every possible input string Can we support only ASCII? – Luis Mendo – 2020-01-04T18:15:30.683

1@LuisMendo - yes, provided ASCII is the alphabet of the language that your program is written in. – Dustin G. Mixon – 2020-01-04T18:16:15.550

7Do programs need to be proper quine variants or is reading the source code allowed? – FlipTack – 2020-01-04T19:06:34.563

Is a function acceptable or must we write a full program? – Robin Ryder – 2020-01-04T19:21:44.680

1@FlipTack - Thanks for the clarifying question. No reading the source code. I edited the post to reflect this. – Dustin G. Mixon – 2020-01-04T19:37:58.487

1@RobinRyder - A function is acceptable. – Dustin G. Mixon – 2020-01-04T19:41:02.427

How do any of these requirements imply being a quine? If you wrote a whole program that (for example) reads from stdin, you'd get p(p) by running ./my_program < my_source.c with the user feeding the program a copy of the source (as opposed to any other input), right? Or for a function, just uint32_t map(char *). Except uint32_t can't work- by the pigeonhole principle that would only allow 2^32 possible input strings, not arbitrary length. Or did you mean that if you want your source code as a constant to compare against, you'd need a quine technique to embed it? – Peter Cordes – 2020-01-07T17:38:21.953

Answers

48

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

James Brown

Posted 2020-01-04T16:23:09.597

Reputation: 663

10

polyglot with perl5 -p

– Nahuel Fouilleul – 2020-01-06T09:22:17.910

1Nice James, thank you for sharing the same :) – RavinderSingh13 – 2020-01-07T06:41:57.370

2

Also polyglot with Perl 6 -p.

– nwellnhof – 2020-01-07T12:59:31.780

12

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!

Arnauld

Posted 2020-01-04T16:23:09.597

Reputation: 111 334

The first one does not match criteria 2, as it will output the same result for different input strings – Skyler – 2020-01-06T20:09:58.963

2@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. – Arnauld – 2020-01-06T20:11:19.537

I think this doesn't satisfy the "do not read the source code" condition, right? – Tomáš Zato - Reinstate Monica – 2020-01-07T09:55:06.563

1

@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.)

– Arnauld – 2020-01-07T10:29:45.990

You can check the revision change on https://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.

– Ismael Miguel – 2020-01-07T12:08:44.287

7

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 2, 56 bytes

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

a='i=input();print 5*[i,404][i=="a=%r;exec a"%a]';exec 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!

Mukundan

Posted 2020-01-04T16:23:09.597

Reputation: 1 188

6

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!

Value Ink

Posted 2020-01-04T16:23:09.597

Reputation: 10 608

2

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

Nick Kennedy

Posted 2020-01-04T16:23:09.597

Reputation: 11 829

Hmm, not sure it's valid without bracketing or something - TIO EDIT - how about this?

– Jonathan Allan – 2020-01-05T00:42:02.160

@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. – Nick Kennedy – 2020-01-05T00:46:59.967

There is an s (ߤ) for which p(s) = p(p) (2020) – Jonathan Allan – 2020-01-05T00:49:11.630

1Oh I see. I now also follow your comment to the question. For now, I’ll update to your version if that’s ok. Thanks! – Nick Kennedy – 2020-01-05T00:50:15.843

@JonathanAllan I’ve gone with which should work ok. Any thoughts? – Nick Kennedy – 2020-01-05T00:53:34.913

1Was just about to suggest it! – Jonathan Allan – 2020-01-05T00:55:11.347

@RobinRyder only when provided as an integer. When provided as a string (which is the spec), it yields “2020” which != 2020 – Nick Kennedy – 2020-01-05T08:22:49.657

@NickKennedy Right, I had missed that input was restricted to strings. – Robin Ryder – 2020-01-05T08:29:32.223

2

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.

Jo King

Posted 2020-01-04T16:23:09.597

Reputation: 38 234

2

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!

gastropner

Posted 2020-01-04T16:23:09.597

Reputation: 3 264

which is a different output than the empty string – None – 2020-01-06T08:53:08.303

1The requirement is that no two distinct inputs should have the same output. – justhalf – 2020-01-06T10:50:48.243

@JoKing Good point! (Hopefully) Corrected now. – gastropner – 2020-01-06T10:56:48.713

@NieDzejkob The number will vary between implementations no doubt. Cheers! – gastropner – 2020-01-06T17:44:41.677

@gastropner Now 2020 corresponds to the input of the old program... – NieDzejkob – 2020-01-06T18:10:12.450

172 bytes – NieDzejkob – 2020-01-06T18:12:07.950

@NieDzejkob Hopefully fixed. The 182 bytes one works only if sizeof(int) == sizeof(char*) (or by luck). – gastropner – 2020-01-06T18:14:13.880

@gastropner Ok, then 180 bytes

– NieDzejkob – 2020-01-06T22:54:52.603

@ceilingcat Neato! – gastropner – 2020-01-07T19:43:21.770

2

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.

Kevin Cruijssen

Posted 2020-01-04T16:23:09.597

Reputation: 67 575

Might work ... only problem is an empty string? – Expired Data – 2020-01-06T15:17:48.993

1@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. :( – Kevin Cruijssen – 2020-01-06T16:37:27.907

2

@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.

– Grimmy – 2020-01-07T12:49:31.213

Yeah @Grimmy thanks great point – Expired Data – 2020-01-07T14:32:20.050

0

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.

FrownyFrog

Posted 2020-01-04T16:23:09.597

Reputation: 3 112

0

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

Kevin Cruijssen

Posted 2020-01-04T16:23:09.597

Reputation: 67 575