4
\$\begingroup\$

The task

Given an ascii string, output a program in my esolang MAWP that outputs the inputted string when run.

Useful functions in MAWP

Numbers from 0-9: Pushes the number to stack
M                 Takes the top two numbers off stack and pushes the sum to stack
A                 Takes the top two numbers off stack and pushes the difference to stack (xyA = y-x)
W                 Takes the top two numbers off stack and pushes the multiplied result to stack
P                 Takes the top two numbers off stack and pushes the floored divided result to stack (xyP = yx)
;                 Takes top number off stack and prints it as an ascii char

Test cases

Input: Hello, World!

Possible output: 89W;689MWA;269WW;269WW;1278WWA;159WA;48W;699WM;1278WWA;67W89WM;269WW;455WW;148WM;

Input: codegolf

Possible output: 929MW;278WWA;455WW;1689MWA;1849MWA;1278WWA;269WW;689MW;

Rules

  1. There can be multiple solutions for each symbol, but the length must be minimal: for example, 04M5W5W; is unacceptable while 45W5W; is fine.
  2. The stack starts with a 1 one it.
  3. You may leave something on the stack
  4. Your output may not print out other characters other than the string, and all of the character s must be given in the og order.
  5. This is code-golf, so lowest byte score wins!

ASCII table for reference

ascii table

\$\endgroup\$
  • 3
    \$\begingroup\$ All these comments make me think that modelling the challenge after your specific esolang introduced a lot of finicky details from the solver's point of view... \$\endgroup\$ – xnor May 12 at 10:30
  • 2
    \$\begingroup\$ @mypronounismonicareinstate 79 can still be done with just multiply and addition: 98W7M. \$\endgroup\$ – Kevin Cruijssen May 12 at 10:54
  • 2
    \$\begingroup\$ @Λ̸̸ its not shorter than, for example, 94W1M3W; so no. Other than that, it does output o \$\endgroup\$ – Dion May 12 at 12:01
  • 2
    \$\begingroup\$ Does xyA return x-y, y-x or |x-y|? Does xyP return x//y or y//x? \$\endgroup\$ – Arnauld May 12 at 12:03
  • 3
    \$\begingroup\$ I misread the challenge when I voted to close it as a duplicate. I won't hammer it open because 4 other people voted to close for different reasons. It is unfortunate that my vote is the only one the site seems to care about. \$\endgroup\$ – Wheat Wizard May 12 at 14:27
4
\$\begingroup\$

JavaScript (Node.js),  276 266  263 bytes

Saved 3 bytes thanks to @KevinCruijssen

i=>[v=[],O='',[...2**29+'4'].map(F=x=>F[v[x]=+x]=x)].map(s=_=>v.map(x=>v.map(y=>[x+y,x*y,y-x].map((z,o)=>(!F[z]&&V.push(z))|(S=~~s[x]-~s[y])<s[z]|S==s[z]&F[x]<2?F[s[z]=S,z]=F[x]+F[y]+'MWA'[o]:0)),V=[])&&v.push(...V))&Buffer(i).map(n=>O+=F[n]+';')||O.replace(1,'')

Try it online!

MAWP interpreter

Here is a simple MAWP interpreter I wrote to check the results.

function MAWP(code) {
  let stack = [ 1 ], out = "";

  function assertStkSz(n) { if(stack.length < n) throw "stack error"; }

  [...code].forEach(c => {
    switch(c) {
      case 'M': assertStkSz(2); stack.push(stack.pop() + stack.pop()); break;
      case 'A': assertStkSz(2); stack.push(stack.pop() - stack.pop()); break;
      case 'W': assertStkSz(2); stack.push(stack.pop() * stack.pop()); break;
      case 'P': assertStkSz(2); stack.push(stack.pop() / stack.pop() | 0); break;
      case ';': assertStkSz(1); out += String.fromCharCode(stack.pop()); break;
      default : stack.push(+c); break;
    }
  })
  return out;
}

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ |(S==s[z]&&F[x]<2) can be with one &, can it not? Or ||S==s[z]&F[x]<2 to also get rid of the parenthesis for -2. \$\endgroup\$ – Kevin Cruijssen May 12 at 13:15
  • \$\begingroup\$ @KevinCruijssen Actually, just |S==s[z]&F[x]<2 is perfectly fine. Thank you. :) \$\endgroup\$ – Arnauld May 12 at 13:40
2
\$\begingroup\$

05AB1E, 151 150 bytes

žQÇεÑÅs¸˜2∍DT‹N59‹iPi©'WªëP®P-®„WMJëài`9-Dgi…9MWJ©NUë®NX-'M««]JR•4ñ4₄¬[Ý•5äŽ6þbT„WM‡5äøJ•XDŒ•27вǝεDg46N44‹è‹i©NUëW≠i®NX-ì'A«]"19M29MW"16ǝIÇƵPαè';ý1õ.;

Not too happy with the byte-count, but it could be worse..

Try it online or verify all ASCII characters.

Explanation:

I first tried to do the mapping of each printable ASCII character (integers in the range \$[32,126]\$) manually. With this, I've used the following strategy:

1) I've first determined all integers that can be formed by multiplying two single-digit integers:

  (32) → 48W
# (35) → 57W
$ (36) → 66W
( (40) → 58W
* (42) → 67W
- (45) → 59W
0 (48) → 68W
1 (49) → 77W
6 (54) → 69W
8 (56) → 78W
? (63) → 79W
@ (64) → 88W
H (72) → 89W
Q (81) → 99W

We can add or subtract a single digit from each of these numbers to form all integers in the range \$[32,90]\$:

! (33) → [48W1M] / 257WA
" (34) → 48W2M / [157WA]
% (37) → [66W1M] / 358WA
& (38) → 66W2M / 258WA
' (39) → 66W3M / [158WA]
) (41) → 58W1M / 167WA
+ (43) → [67W1M] / 259WA
, (44) → 67W2M / [159WA]
. (46) → [59W1M] / 268WA
/ (47) → 59W2M / [168WA]
2 (50) → [77W1M] / 469WA
3 (51) → 77W2M / 369WA
4 (52) → 77W3M / 269WA
5 (53) → 77W4M / [169WA]
7 (55) → 69W1M / 178WA
9 (57) → [78W1M] / 679WA
: (58) → 78W2M / 579WA
; (59) → 78W3M / 479WA
< (60) → 78W4M / 379WA
= (61) → 78W5M / 279WA
> (62) → 78W6M / [179WA]
A (65) → [88W1M] / 789WA
B (66) → 88W2M / 689WA
C (67) → 88W3M / 589WA
D (68) → 88W4M / 489WA
E (69) → 88W5M / 389WA
F (70) → 88W6M / 289WA
G (71) → 88W7M / [189WA]
I (73) → [89W1M] / 799WA
J (74) → 89W2M / 799WA
K (75) → 89W3M / 699WA
L (76) → 89W4M / 599WA
M (77) → 89W5M / 499WA
N (78) → 89W6M / 399WA
O (79) → 89W7M / 299WA
P (80) → 89W8M / [199WA]
R (82) → 99W1M
S (83) → 99W2M
T (84) → 99W3M
U (85) → 99W4M
V (86) → 99W5M
W (87) → 99W6M
X (88) → 99W7M
Y (89) → 99W8M
Z (90) → 99W9M

3) When there are two options, we want to prioritize the ones containing a digit 1 (since those is already initially on the stack, and we could potentially remove later on). When one of the two numbers contains a 1 I've put it in square-blocks in the list above. If both or neither contain a 1 it's irrelevant which one we choose.

4) Now that everything below 91 is covered, we are left with the integers in the range \$[91,126]\$.
I first determined all integers which could be formed by one single-digit integer multiplied by a two-digit integer in the range \$[10,18]\$, since 18 being 9+9 is the highest we could create:

[ (91) → 794MW
` (96) → 697MW
b (98) → 795MW
c (99) → 992MW
f (102) → 698MW
h (104) → 894MW
i (105) → 796MW
l (108) → 699MW
p (112) → 797MW
u (117) → 994MW
w (119) → 798MW
~ (126) → 799MW

5) And there are also some additional integers which can be formed by using three single digits outside of the ones above, which are edge cases in my program:

d (100) → 455WW
x (120) → 869MW
y (121) → 358WW
} (125) → 555WW

6) After that, we can use a similar strategy as we did in steps 2 and 3:

\ (92) → [794MW1M] / 4268WWA
] (93) → 794MW2M / 3268WWA
^ (94) → 794MW3M / 2268WWA
_ (95) → 794MW4M / [1268WWA]
a (97) → 697MW1M / 1795MWA
e (101) → 455WW1M / 1698MWA
g (103) → 698MW1M / 1894MWA
j (106) → [796MW1M] / 2699MWA
k (107) → 796MW2M / [1699MWA]
m (109) → [699MW1M] / 3797MWA
n (110) → 699MW2M / 2797MWA    *
o (111) → 699MW3M / [1797MWA]
q (113) → [797MW1M] / 4994MWA
r (114) → 797MW2M / 3994MWA
s (115) → 797MW3M / 2994MWA
t (116) → 797MW4M / [1994MWA]
v (118) → 994MW1M / 1798MWA
z (122) → [358WW1M] / 3555WWA
{ (123) → 358WW2M / 2555WWA
| (124) → 358WW3M / [1555WWA]

The one with * behind it is the only edge case after all these steps, since 19M29MW can be used that contains a 1, so is potentially shorter than both 699MW2M and 2797MWA.


As for the actual code to implement these steps and encode the input:

žQ                           # Push all printable ASCII characters
  Ç                          # Convert it to an integer list in the range [32,127]
   ε                         # Map each integer to:
    Ñ                        #  Get the divisors of the current integer
     Ås                      #  Get the middle (if it's a square) or middle two integers
       ¸˜2∍                  #  If it's a square, duplicate that integer
                             #  (so we only have pairs of integers now)
    D                        #  Duplicate the pair
     T‹                      #  Check for both whether they're a single digit (<10):
       y91‹i                 #  If the integer we're mapping over is below 91:
            Pi               #   If both values in the pair are a single digit:
              ©              #    Store the pair in variable `®` (without popping)
               'Wª          '#    And append a "W" to the list
             ë               #   Else:
              P              #    Pop and take the product of the duplicated pair
               ®P            #    Take the product of pair `®` as well
                 -           #    Subtract them from one another
              ®              #    Push pair `®`
              „WM            #    Push string "WM"
                 J           #    Join the pair together, and then all three together
           ë                 #  Else (the integer we're mapping over is above 90):
            ài               #   If either of the two integers is a single digit:
              `              #    Push both separated to the stack
               9-            #    Subtract 9 from the larger 2-digit integer
                 Dgi         #    If it's now a single digit:
                    …9MW     #     Push string "9MW"
                        J    #     And join all three together
                         ©   #     Store this in variable `®` (without popping)
                          NU #     And store the map-index in variable `X`
                   ë         #    Else:
                    ®        #     Push the string from variable `®`
                     N       #     Push the current map-index
                      X-     #     Subtract the saved map-index of `X`
                        'M  '#     Push an "M"
                          «« #     Join the three together
   ]                         # Close all if-statements and map
    J                        # Join each inner list together to a single string

We now have the following list:

["48W","148WM","248WM","57W","66W","166WM","266WM","366WM","58W","158WM","67W","167WM","267WM","59W","159WM","259WM","68W","77W","177WM","277WM","377WM","477WM","69W","169WM","78W","178WM","278WM","378WM","478WM","578WM","678WM","79W","88W","188WM","288WM","388WM","488WM","588WM","688WM","788WM","89W","189WM","289WM","389WM","489WM","589WM","689WM","789WM","889WM","99W","199WM","299WM","399WM","499WM","599WM","699WM","799WM","899WM","999WM","749MW","749MW1M","749MW2M","749MW3M","749MW4M","839MW","839MW1M","759MW","929MW","1010","929MW2M","689MW","689MW1M","849MW","769MW","769MW1M","769MW2M","939MW","939MW1M","1011","939MW3M","859MW","859MW1M","859MW2M","859MW3M","859MW4M","949MW","949MW1M","789MW","1012","1111","789MW3M","789MW4M","789MW5M","789MW6M","959MW"]

As you can see, it contains some errors like "1010","1011","1012","1111" for the edge cases [100,110,120,121] respectively as discussed earlier, which could be "455WW","869MW","358WW","555WW" instead; "789MW6M" for 125, which could be "555WW" instead; and "789MW3M" for 122, which could be "358WW1M" instead. So we fix those edge cases manually (except for "1011" since we already fix that edge case at the very end anyway):

R                            # Reverse the list
 •4ñ4₄¬[Ý•                   # Push compressed integer 1358555358869455
          5ä                 # Split it into 5 equal-size parts: [1358,555,358,869,455]
 Ž6þ                         # Push compressed integer 1783
    b                        # Convert it to binary: 11011110111
     T„WM‡                   # Transliterate "10" to "WM": "WWMWWWWMWWW"
          5ä                 # Also split it into 5 equal-size parts:
                             #  ["WWM","WW","WW","MW","WW"]
 ø                           # Pair the two lists together
  J                          # And join each inner pair together:
                             #  ["1358WWM","555WW","358WW","869MW","455WW"]
•XDŒ•                        # Push compressed integer 2149280
     27в                     # Convert it to base-27 as list: [4,1,5,6,26]
ǝ                            # Insert the strings at those indices in the reversed list

Then we'll change every case with ...2M or higher to x...A:

ε                            # Map each string to:
 Dg                          #  Get the length (without popping by duplicating first)
     N44‹                    #  Check if the map-index is below 44
                             #  (1 if truthy; 0 if falsey)
   46    è                   #  Use it to index into 46 (6 if truthy; 4 if falsey)
          ‹i                 #  If the length is smaller than that:
            ©                #   Store the current string in variable `®`
             NU              #   And the map-index in variable `X`
           ë                 #  Else:
            W                #   Get the smallest digit (without popping)
             ≠i              #   If it's NOT 1:
               ®             #    Push the string of variable `®`
                NX-          #    Push the map-index and subtract `X`
                   ì         #    Prepend this digit in front of the string
                    'A«     '#    And append an "A"
]                            # Close the if-statements and map

We now have the following (still reversed!) list:

["959MW","555WW","1555WWA","2555WWA","1358WWM","358WW","869MW","789MW","949MW1M","949MW","1949MWA","2949MWA","3949MWA","859MW1M","859MW","1859MWA","1011","939MW1M","939MW","1939MWA","769MW1M","769MW","849MW","689MW1M","689MW","1689MWA","455WW","929MW","759MW","839MW1M","839MW","1839MWA","2839MWA","3839MWA","749MW1M","749MW","999WM","899WM","799WM","699WM","599WM","499WM","399WM","299WM","199WM","99W","199WA","299WA","399WA","499WA","599WA","699WA","799WA","189WM","89W","189WA","289WA","389WA","489WA","589WA","689WA","188WM","88W","79W","179WA","279WA","379WA","479WA","579WA","178WM","78W","169WM","69W","169WA","269WA","369WA","177WM","77W","68W","168WA","159WM","59W","159WA","167WM","67W","158WM","58W","158WA","258WA","166WM","66W","57W","157WA","148WM","48W"]

Fix the final test case as discussed earlier:

"19M29MW"                    # Push string "19M29MW"
         16ǝ                 # And insert it at index 16

And then convert the input using this finished (still reversed) list:

I                           # Push the input-string
 Ç                          # Convert each character to its codepoint integer
  ƵP                        # Push compressed integer 126
    α                       # Take its absolute difference with each codepoint integer
     è                      # Index those into the list we created
      ';ý                  '# Join them together with a ";" delimiter
         1õ.;               # And remove the very first "1"
                            # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •4ñ4₄¬[Ý• is 1358555358869455; Ž6þ is 1783; •XDŒ• is 2149280; •XDŒ•27в is [4,1,5,6,26]; and ƵP is 126.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ underrated answer \$\endgroup\$ – Razetime Aug 9 at 15:03
  • 1
    \$\begingroup\$ @RaghuRanganathan Thank you. :) \$\endgroup\$ – Kevin Cruijssen Aug 9 at 15:26

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.