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]}
S=1%02d})%[q,S<2?0:S-99]}
S=1
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.
Explanation:
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
"BREAKING NEWS: WORLD ENDS"
else
q = ...
number_to_append = if S < 2
0
else
S - 100 + 1
end
q % [q, number_to_append]
end
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!
2Kparanoia: yes97
and producing2Kparanoia: yes98
, so shouldn't (4) readRepeat to step 100, but step 101 will output "BREAKING NEWS: WORLD ENDS"
? (i.e.2Kparanoia: yes99
produces the news) \$\endgroup\$