6
\$\begingroup\$

Introduction

Ah, INTERCAL...
As much as I'd like encourage everyone to Try it Online, text output is just painful.
According to the docs it uses the "Turing Text Model". While an... interesting concept, using it is about as much fun as shooting yourself in the foot. And what do we do with a task like this? Automate it.

The Turing Text Model

The characters INTERCAL knows are printed on a circular tape that can only be moved in the positive direction. Printing is done by passing tape head movement commands in an array to the READ OUT statement. Every ASCII character is written on the inside of that tape (The outside has the characters for the input on it, duh). This results in the characters' bytes being on the tape in reverse. Also the tape head moves backwards along the character list, because its positioning is based on the outside of the tape.
The head starts at position 0.

Now the magic starts. I'll be using Truttle1's explanation on how to achieve output.

  1. Set up an array with the output length.
  2. Fill the entries in the array with tape head movement values.
    1. Find the current character's ASCII value in binary
    2. Reverse it and convert back a number n.
    3. Subtract n from the current head postion and modulo by 256 if needed, resulting in a value r
    4. r is the value you need to store in the array
    5. The head is now at position n.
  3. DO READ OUT the array.

PLEASE NOTE

  • Array is pre-initialized with 0, first index is 1
  • INTERCAL uses extended 8-bit ASCII characters, hence the tape length of 256.
  • Between 1/3rd and 1/5th of all lines have to start with PLEASE. Note that in that case you drop the DO for GIVE UP and READ OUT, but not for anything else, as seen in the examples.

Challenge

Given an input string, output a valid INTERCAL program that prints that string and terminates.

Examples

Prints "BUZZ"

DO ,1 <- #4
DO ,1 SUB #1 <- #190
DO ,1 SUB #2 <- #152
PLEASE DO ,1 SUB #3 <- #336
DO READ OUT ,1
PLEASE GIVE UP

Whitespace is optional. The following prints "FIZZ"

DO,1<-#4DO,1SUB#1<-#158DO,1SUB#2<-#208DO,1SUB#3<-#312PLEASEREADOUT,1PLEASEGIVEUP

(Examples shamelessly stolen from Truttle1's FizzBuzz program from the video.)

You can find an ungolfed reference implementation in python 3 here

Rules

  • No standard loopholes
  • This is , shortest code wins.
  • You can expect input >= 1, ASCII characters only.
  • The program may not throw any errors apart from ICL774I RANDOM COMPILER BUG and ICL666I COMPILER HAS INDIGESTION. First one happens at random, second one is C-Intercal running out of memory and circumventing that isn't part of the challenge
\$\endgroup\$
  • 4
    \$\begingroup\$ How is the binary number supposed to be reversed? Your Python implementation preprends a leading 0 before reversing, but I don't think that works for ASCII codes below 64. My guess is that it should be always padded to exactly 8 bits. \$\endgroup\$ – Arnauld Oct 2 at 12:49
  • \$\begingroup\$ From my experience, you are correct \$\endgroup\$ – Unrelated String Oct 3 at 5:26
  • \$\begingroup\$ For various solutions' outputs from very long inputs, the C-INTERCAL on TIO encounters ICL666I COMPILER HAS INDIGESTION, which is to say the compiler runs out of memory. I assume this is permitted? \$\endgroup\$ – Unrelated String Oct 3 at 10:37
  • 1
    \$\begingroup\$ @Arnauld Yes, I should have written "pad to 8" somewhere \$\endgroup\$ – mindoverflow Oct 3 at 18:44
  • 1
    \$\begingroup\$ @UnrelatedString Yes, added that to the rules since C-Intercal running out of memory is not your program's fault. What length was your input? \$\endgroup\$ – mindoverflow Oct 3 at 18:44
8
\$\begingroup\$

Python 3, 157 bytes

t=i=0
p=o='PLEASE'
for c in input():i+=1;k=int(f'{ord(c):08b}'[::-1],2);o+=i%4//3*p+f'DO,1SUB#{i}<-#{t-k&255}';t=k
print(f'DO,1<-#{i}{o}DOREADOUT,1DOGIVEUP')

Try it online!

This prints \$n+3\$ instructions, of which \$\left\lfloor \frac{n+5}{4} \right\rfloor\$ are polite. That ratio just barely fits in the \$[1/5, 1/3]\$ politeness interval for all \$n \geq 1\$.

-1 byte thanks to Neil.

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ If you use &255 instead of %256 then you can use t-k&255 instead of subtracting from t earlier, allowing you to remove the - from the t-=k, saving 1 byte. \$\endgroup\$ – Neil Oct 2 at 20:05
5
\$\begingroup\$

JavaScript (Node.js),  156  148 bytes

s=>`DO,1<-#${Buffer(s).map(c=>o+=`${i++&&~i&3?'':'PLEASE'}DO,1SUB#${i}<-#`+(p-(g=k=>p=k--&&c>>k&1|g(k)*2)(8)&255),i=p=o=""),i+o}DOREADOUT,1DOGIVEUP`

Try it online!

Try the output in INTERCAL!

How?

Bit reversal

We use a recursive function to reverse the bits of the character c.

( g = k =>       // k = bit position counter 
  k-- &&         // decrement k; if it was not 0:
    c >> k & 1   //   bring the k-th bit of c at position 0 and isolate it
    | g(k)       //   bitwise OR with a recursive call,
      * 2        //   whose result is doubled
)(8)             // initial call with k = 8

Politeness

Starting with i = 0, we insert a polite statement whenever the following expression is falsy:

i++ && ~i & 3

This means that we insert a PLEASE for the first processed character, and then every 4 characters starting with the 3rd one.

Neither the leading instruction nor on the two trailing instructions are polite. They are marked as L and TT respectively in the following table.

 length | output structure   | politeness ratio
--------+--------------------+------------------
    1   | LPTT               |   1/ 4 = 0.250
    2   | LP-TT              |   1/ 5 = 0.200 <-- lower bound
    3   | LP-PTT             |   2/ 6 ≈ 0.333 <-- upper bound
    4   | LP-P-TT            |   2/ 7 ≈ 0.286
    5   | LP-P--TT           |   2/ 8 = 0.250
    6   | LP-P---TT          |   2/ 9 ≈ 0.222
    7   | LP-P---PTT         |   3/10 = 0.300
    8   | LP-P---P-TT        |   3/11 ≈ 0.273
    9   | LP-P---P--TT       |   3/12 = 0.250
   10   | LP-P---P---TT      |   3/13 ≈ 0.231
   11   | LP-P---P---PTT     |   4/14 ≈ 0.286
   12   | LP-P---P---P-TT    |   4/15 ≈ 0.267
   13   | LP-P---P---P--TT   |   4/16 = 0.250
   14   | LP-P---P---P---TT  |   4/17 ≈ 0.235
   15   | LP-P---P---P---PTT |   5/18 ≈ 0.278
   ..   | ...                |   1/5 < r < 1/3
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Ah ok, I forgot about JS not having integer division. My bad. Thanks for the explanation. \$\endgroup\$ – Kevin Cruijssen Oct 2 at 16:37
5
\$\begingroup\$

05AB1E, 77 74 54 bytes

Ç₁+₁šb퀨C¥(₁%€‘‚µ,1<-#1€·,1—¨#1<-#ÿ€·‚Ø€Ä,1‘J‘ÿ€·†¿€¾

-20 bytes by porting @UnrelatedString's Jelly answer, so make sure to upvote him!!

Outputs with spaces at #1 DO,1 SUB#, DO READ OUT, and DO GIVE UP.

Try it online or verify a few more test cases.

Try the output in INTERCAL.

Explanation:

Ç               # Convert the (implicit) input-string to a list of codepoint integers
 ₁+             # Add 256 to each value
   ₁š           # Prepend 256 at the front of the list
     b          # Convert each value to a binary string
      í         # Reverse each
       ۬       # Remove the last digit of each
         C      # Convert each from binary back to a base-10 integer
          ¥     # Take the forward differences (deltas) of this list
           (    # Negate each difference
            ₁%  # Take modulo-256 on each
€               # Map over each integer:
 ‘‚µ,1<-#1€·,1—¨#1<-#ÿ€·‚Ø€Ä,1‘
                #  Push dictionary string "PLEASE,1<-#1 DO,1 SUB#1<-#ÿ DO READ OUT",
                #  where the `ÿ` is automatically filled with the integer
   J            # Join this list of strings together
    ‘ÿ€·†¿€¾    # Push string "ÿ DO GIVE UP", where the `y` is filled with the string
                # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why ‘‚µ,1<-#1€·,1—¨#1<-#ÿ€·‚Ø€Ä,1‘ is "PLEASE,1<-#1 DO,1 SUB#1<-#ÿ DO READ OUT" and ‘ÿ€·†¿€¾ is "ÿ DO GIVE UP".

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Charcoal, 90 89 85 bytes

DO,1<-#ILθ⊞υ⁰⭆θ⪫⟦×PLEASE⊖﹪κ³DO,1SUB#⊕κ<-#﹪⁻⊟υΣ⊞Oυ⍘⮌◧⍘℅ι !⁸ !²⁵⁶⟧ω”Z1∨?AE₂-πK↷Y:γüD0←✂

Try it online! Link is to verbose version of code. Explanation:

DO,1<-#ILθ

Print the instruction to set the length of the output.

⊞υ⁰

Start with the head at position 0. The value is actually stored in the predefined empty list as we can modify the list's value later using the Pop and PushOperator functions rather than having to resort to a command.

⭆θ⪫⟦...⟧ω

Loop over the characters and print the concatenation of 5 expressions for each character. (This is slightly golfier as the concatenation automatically stringifies the two numeric values in the list).

×PLEASE⊖﹪κ³

Be polite every third character. There is also a PLEASE at the end, so that the politeness ratio is ¹⁄₄, ¹⁄₅, ²⁄₆, ²⁄₇, ²⁄₈, ³⁄₉, ³⁄₁₀, ³⁄₁₁ ... after which the politeness ratio tends towards ¹⁄₃.

DO,1SUB#⊕κ<-#

Print the 1-indexed index at the start of the instruction to output the character.

﹪⁻⊟υΣ⊞Oυ⍘⮌◧⍘℅ι !⁸ !²⁵⁶

Calculate the reversed binary of the current character, output the difference from the head, and update the head with the new reversed binary, all in one expression. The binary is encoded using space for 0 so that it can easily be padded to 8 bits, plus the use of strings avoids separators that would otherwise be necessary.

”Z1∨?AE₂-πK↷Y:γüD0←✂

Print the compressed trailing instructions to output the string and exit. The string compression means that I don't have to worry about optimising the number of times I output PLEASE any further.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Python 3, 128 bytes

t=0
for c in input():n=int(f'{ord(c):08b}'[::-1],2);print(f'PLEASE,1<-#1DO,1SUB#1<-#{t-n&255}DOREADOUT,1');t=n
print('DOGIVEUP')

Try it online!

Produces similar output to my Jelly solution, but is just as much a modification of Lynn's Python solution.

Originally used Python 3.8's "walrus" operator, but it turned out shorter not to by 2 bytes.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Jelly, 62 59 bytes

OŻ+⁹BUṖ€Ḅ_Ɲ%⁹“!![ẓ,ȮFẈẋ⁹⁾V!ĖÐĊnß6ṛ»;;“Œ°þ[ṪȦṄ»Ʋ€;“©⁴Œ½OлŒu

Try it online!

Uses an array length of 1 and prints repeatedly to save on indexing, and sets the length to one repeatedly to save on politeness logic: length-element-print forms a very convenient unit of 3.

Without string compression:

OŻ+⁹BUṖ€Ḅ_Ɲ%⁹“please,1<-#1do,1sub#1<-#”;;“doreadout,1”Ʋ€;“dogiveup”Œu

Try a result online!

O                                      Codepoints of input.
 Ż                                     Prepend zero,
  +⁹                                   add 256 to each,
    B                                  convert each to binary.
     U                                 Reverse each,
      Ṗ€                               remove last element from each,
        Ḅ                              convert from binary.                                
         _Ɲ                            Subtract all adjacent pairs,
           %⁹                          and modulo 256.
                         Ʋ€            Map:
                  ;                    prepend to the number
             “...»                     "please,1<-#1do,1sub#1<-#",
                   ;                   append to that
                    “...»              "doreadout,1".
                           ;“...»      Append "dogiveup" to the whole result
                                 Œu    and uppercase.
| improve this answer | |
\$\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.