6
\$\begingroup\$

Design a function or program that, when run normally, outputs the triangular numbers. However, when any single character is deleted, the program/function should not function in the original programming language, but instead produce the triangular numbers in one other programming language.

Scoring

Your score will be the number of characters in your program for which the program is not valid in your second chosen language.

Lowest score wins, tiebreaker is byte count.

Specific Rules

You may infinitely output triangular numbers, produce a list of the first N with a positive integer input N, or produce the Nth triangular number. Each of the programs may have different behavior in this respect.

Your original program may run in the second language, but it can't produce the correct output.

Your programs may also output in different bases/use different indexing/use different output formats, as long as that format would be valid in a challenge.

No more than 20% of your characters, rounded down, may be invalid.

An invalid character is any character that, when removed, creates no program or function that outputs triangular numbers in your second chosen language.

Any time you remove a character from the original code, it should break it.

Separate versions of programming languages ARE permitted to be treated as different languages.

\$\endgroup\$
9
  • \$\begingroup\$ Can you confirm (or not): is it Ok to have some nonzero number of characters that, when deleted, still allow the program to function in the first language (and that these are counted as 'invalid characters')? \$\endgroup\$ Commented May 18, 2022 at 8:13
  • 2
    \$\begingroup\$ Can the initial program work in the second language? Your challenge to my best reading doesn't seem to rule it out (only the other way around), but I think it would be a good rule. Otherwise you just make a radiation hardened program that's also a polyglot. \$\endgroup\$
    – Wheat Wizard
    Commented May 18, 2022 at 9:51
  • \$\begingroup\$ I agree with @WheatWizard that ruling this out would be a good rule. Currently my answer does work in the second language, and I must admit that this made it fairly low effort... \$\endgroup\$ Commented May 18, 2022 at 10:35
  • 2
    \$\begingroup\$ "Your original program may run in the original language, but it can't produce the correct output." I think you mean "...run in the second chosen language"...? \$\endgroup\$ Commented May 18, 2022 at 16:21
  • 1
    \$\begingroup\$ Changed. I think that's about what's left on scoring, but we'll see. \$\endgroup\$
    – Romanp
    Commented May 18, 2022 at 18:26

1 Answer 1

9
\$\begingroup\$

Perl 5 -M5.010 + A Pear Tree, score 0, tiebreak score 96 bytes

$_='{length==86&&6&&say$T0+=++$b9F;redo}{print$tYC+=++$nKy;redo}#{print$tYC+=++$nKy;redo}#';eval

Try it online! (Perl)

Try it online! (A Pear Tree)

A Pear Tree was designed for challenges and challenges. I think, however, this is the first time I've used it on a challenge that falls into both categories.

This was annoyingly time-consuming to verify – my normal verifier programs don't handle infinite loops well, and yet an infinite loop is shorter to write than a "loop up to input" is in Perl, so I ended up having to check all the irradiated programs manually.

The -M5.010 argument to Perl is a version selection argument that's basically standard in golfing at this point (and used to be allowed without penalty even back when we penalised for command-line arguments) – I would add it out of habit even if it didn't do anything (although it's required here).

Explanation

Perl

Most of the program is stored in a string, $_, which is immediately evaluated:

$_='…';eval
$_='…'         initialize variable $_
       eval    evaluate {$_} as a program

($_ is chosen as the variable because it's the default variable that most commands use when an operand is missing, so this helps out the tiebreak score a little.)

The program itself does the following:

{length==86&&6&&say$T0+=++$b9F;redo}{…}#…
{                             ;redo}        infinite loop
                say                           print
                   $T0                          the value of $T0
                      +=                      after adding
                          $b9F                  the value of $b9F to it
                        ++                    after adding 1 to that
              &&                            but only if
 length                                       the length {of $_}
       ==86                                     is 86
           &&                               and
             6                                6 is truthy
                                    {…}     unreachable code
                                       #…   comment

The actual calculation of the triangular numbers is very simple (although confusing because there are two assignments inside the expression) – $T0 holds the triangular number itself, and $b9F its index, and we repeatedly add 1 to $b9F and then add $b9F to $T0 in order to produce the sequence of triangular numbers. Perl variables are initialised with undef, which acts like 0 when you increment it or add numbers to it. (The variable names don't matter to the Perl program, and are as weird as they are due to how A Pear Tree works.)

The unreachable code – part of the A Pear Tree program – is syntactically valid, but never runs because there's an infinite loop immediately before it.

The length==86 check is used to ensure that none of the irradiated versions of the program print the triangular numbers in Perl. Deleting most things outside the long string literal, or its delimiters, produces a syntax error. Deleting characters from eval is not a syntax error, but the resulting program does nothing when run, because the string is never evaluated. Some deletions inside the string produce syntax errors; these are caught by eval (thus no error message is printed), but prevent the string being evaluated. For other deletions inside the string, the length==86 check will prevent anything actually being printed (it will either be intact, or be corrupted into something falsey), so the code still doesn't output the triangular numbers.

The check for 6 being truthy is mostly irrelevant – it was added purely so that I could have two &&s in there, thus preventing the scenario in which a lone && (short-circuiting AND) gets irradiated into & (bitwise AND) and causes the say statement to run uncondtionally. (With the two &&s, if either of them gets corrupted into &, the other still prevents the say statement running because its left-hand side will be falsey.)

A Pear Tree

To write an A Pear Tree program, you need to decide which substrings of the program are going to be checked for corruption by the interpreter – the interpreter will rotate the largest such part to the start before running the program (and error out if there is no such portion). The substrings in question are marked implicitly by changing irrelevant internal details of them in such a way that their CRC32 is 0.

In this program, there are three such sections with a CRC32 of 0 – the entire program, and the two {print$tYC+=++$nKy;redo}# substrings.

In a non-irradiated run of the program, the largest section is the program itself, so it runs unrotated, and is has effectively identical control flow to the Perl. However, say is not a keyword in A Pear Tree (the "print with newline" builtin is called print there, in one of its very minor differences from Perl), so the program hits an error when it tries to execute say (which is caught by the eval and the program exits naturally). It would be possible to exploit other differences between the languages (e.g. $\ is falsey in Perl but truthy in A Pear Tree), but using the existence/nonexistence of say is terser.

If you delete any character from the program, the program as a whole will no longer have a CRC32 of 0, so one of the {print$tYC+=++$nKy;redo}# substrings (whichever one didn't get irradiated, or the first one if they're both intact) is rotated to the start, followed by the rest of the program. However, the # at the end of the substring comments the rest of the program out, so we just end up with a small loop that calculates triangular numbers. This is identical to the triangular number calculation part of the Perl code, except for the variable names and the use of print rather than say. (Incidentally, although A Pear Tree often allows you to omit the $ before a variable name, it doesn't allow this after the ++ operator and wouldn't save bytes after the print, so for once all the $s are present.)

In order to mark the appropriate substrings of the code, I changed the variable names (and other details like the specific truthy constant in the Perl code – obviously, any truthy constant would work for Perl, not just 6, but 6 worked best for A Pear Tree), which is why they're so weird.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.