Y2K... in 2019?

Ruby, 158 154 146 128 122 100 bytes

Inspired by this answer.

eval s=%{$><<(D>198?'BREAKING NEWS: WORLD ENDS':'eval s=%%{%s}<<D=%d'%[s[0..-2],D<2?100:D+1])#}<<D=1

EDIT: I was able to remove (s.split(35.chr)[0]+35.chr).inspect and replace it with s[0..-2] (range of every value except the last) and the %{ ... } string syntax I used before. Saved 22 bytes!

Old version:

EDIT: Saved a pair of parens (and corresponding pair in the data section) by realizing that "BREAKING NEWS: WORLD ENDS" is a perfectly valid format string, and ruby ignores any extraneos parameters.

END{$><<(q=S>198?"BREAKING NEWS: WORLD ENDS":%{END{$><<(q=S>198?"BREAKING NEWS: WORLD ENDS":%%{%s})%%[q,S<2?0:S-99]}

When starting this I realized that since the number has to go at the very end of the program, and ruby doesn't allow using variables before they are declared, I would have to make code run after the digits somehow. I could've done something like def a(s) ... end;a 1 which would become ...end;a 100, however using ruby's lesser-known END syntax uses fewer bytes. However, the block inside END is in a different scope, so S must be a global variable or constant.


  • END{ ... };S=1: Run block of code just before program terminates; Set constant S to 1 (or 100 - 199 in future iterations)
  • $><<( ... ): $> is a shortcut in ruby for stdout, and << on an IO writes to the IO. The parens are required, otherwise it becomes ($><<S)>198...
  • S>198?"BREAKING NEWS: WORLD ENDS":(q=...)%[q,S<2?0:S-99]: If I were to break this out into slightly more reasonable code it would be:

    if S > 198
      q = ...
      number_to_append = if S < 2
        S - 100 + 1
      q % [q, number_to_append]

    The % operator applied to a string is effectively printf, with the LHS being the format string and the RHS being the arguments.

  • %{ ... (q=%%{%s}) ... S=1%02d}: ruby has an interesting syntax for strings that also allows for pairs of curly brackets to appear within the string without any escaping as long as they are balanced. This is very helpful, as otherwise a similar quine would have to escape the string to put it into itself as a string literal. The two substitutions in the format string are %s for a regular string and %02d for a number right-padded to a size of 2 with the character 0.

My thoughts on shortening further:

  • It'd be nice to be able to use s instead of $s, but defining s s=$s; or making a function def a(s) ... both use more bytes than they save, and I can't think of any other way to do it. EDIT: Constants are global and can be one character!
  • It'd be nice if S was always less then 100, so that it could be compared using 2-digit numbers instead of 3-digit numbers. However, if I use S=0 at the end, the next two digits are interpreted as octal, and 8 and 9 are invalid and all is bunk. S= simply isn't valid, and I don't know any other way to make a value valid both before and after appending two digits. Of note, 0 (and every other integer) is truthy in ruby.

Any thoughts on how to make this shorter, please let me know!

Try it online!

Perl 6, 122 114 106 bytes

-8 bytes thanks to Shelvacu

END {<print $!-199??"END \{<$_>~~.EVAL};\$!="~($!-1&&$!-99)+100!!"BREAKING NEWS: WORLD ENDS">~~.EVAL};$!=1

Try it online!

Takes the standard quine format and adds the breaking news string as well as a new function call with the appended number. This uses END to execute the function when the program ends.

Go, 382 366 354 340 305 298 272 bytes

Won't win but I had fun with the challenge.

package main
func main(){if n<199{s+="\x60,"
print(s[:135],s,100+(n/100)*(n%100+1))}else{print("BREAKING NEWS: WORLD ENDS")}}
var s,n=`package main
func main(){if n<199{s+="\x60,"
print(s[:135],s,100+(n/100)*(n%100+1))}else{print("BREAKING NEWS: WORLD ENDS")}}
var s,n=`,1

Try it on the Go Playground!

Based on a quine. If the variable n is less than 199, then it adds to the string variable n a grave accent (\x60), Go's character for multiline strings, followed by a comma ,. It continues by printing the first 147 characters of s (to prevent printing the , because that only occurs at the end) then prints s as a whole, and finally prints 100 if n == 1 and n+1 otherwise. The result is that successive runs change the variable n at the end of the program to 100, 101, etc. If the variable n is 199 or more, then it prints breaking news.