14
\$\begingroup\$

Martin Ender's 2D programming language Alice has two different modes depending on what orientation the IP has: orthogonal (Cardinal mode) or diagonal (Ordinal mode). Commands in Alice change their meaning depending on which mode the program is in when they're executed. One especially interesting implementation of this is Alice's Z, or "pack", command. For strings in Ordinal mode, this simply takes two strings a and b and interleaves (also known as "zip") them. For example:

a = "Hello"
b = "World"
Z -> "HWeolrllod"

However, while in Cardinal mode, Z pops two integers \$n\$ and \$m\$ and returns \$\pi(n,m)\$*, the Cantor pairing function. For example, for \$n = 2, m = 3\$, Z returns \$\pi(2, 3) = 18\$. The reasoning behind this is explained in this answer.

For clarity, the Cantor pairing function uses the following formula:

$$\pi(n,m) = \frac12(n+m)(n+m+1)+m$$


You are to write two non-identical programs that implement the two modes of Z. More specifically:

  • The first should take two non-empty strings containing only printable ASCII (0x20 to 0x7e) of the same length* and output these strings zipped/interleaved together
  • The second should take two non-negative integers \$x\$ and \$y\$ and should output \$\pi(x, y)\$ as specified above.

*: This isn't technically how the Z command works, read the Alice docs for more

You may input and output in any accepted method, and you may assume all inputs are reasonable for your language.

Your score is the Levenshtein distance between your two programs multiplied by the sum of the program lengths, aiming for a lower score. You can use this website to calculate Levenshtein distance.

Test Cases

For the first program:

a, b -> Z
"a", "b" -> "ab"
"Hello,", "World!" -> "HWeolrllod,!"
"World!", "Hello," -> "WHoerllldo!,"
"Alice", "     " -> "A l i c e "

The second program:

n, m -> π(n, m)
2, 3 -> 18
5, 5 -> 60
0, 1 -> 2
1, 0 -> 1
100, 75 -> 15475
\$\endgroup\$
7
  • \$\begingroup\$ Sandbox Related \$\endgroup\$ Commented Oct 16, 2020 at 22:58
  • 1
    \$\begingroup\$ Must the two programs be in the same language? \$\endgroup\$ Commented Oct 17, 2020 at 6:37
  • \$\begingroup\$ Is it okay if the interleaved output is a list? Also, is it okay if the inputs are swapped? \$\endgroup\$
    – SunnyMoon
    Commented Oct 17, 2020 at 9:03
  • \$\begingroup\$ @RobinRyder Yes, the two programs must be in the same language \$\endgroup\$ Commented Oct 17, 2020 at 11:52
  • \$\begingroup\$ @SunnyMoon Yep, both of those are fine \$\endgroup\$ Commented Oct 17, 2020 at 11:52

9 Answers 9

11
\$\begingroup\$

Jelly, Score 1 * 8 bytes = 8

String zip:

+Ẇɼ+

Try it online!

Cantor pairing function:

+ẆL+

Try it online!

We use the fact that the Cantor pairing is equal to

$$ {n + m + 1 \choose 2} + m $$

Where the left term just happens to be the number of nonempty contiguous slices of \$m+n\$. This saves two bytes per program over the naive +‘×+H+, and one byte over the (less naive) +‘c2+.

Conveniently, in Jelly + zips strings (I had no idea!).

Explanations:

          Implicit input: strings s1, s2
+         Zip s1, s2.
 Ẇ        All nonempty slices.
  ɼ       Save the result to register (ignore previous 2).
   +      Zip s1, s2.
          Implicit input: numbers n, m
+         Compute m+n.
 Ẇ        All nonempty slices of implicit range m+n.
  L       Length.
   +      Add m.    

Note that there are many ways to get 4 for the pairing function (+R;S, +R+ƒ, etc)

\$\endgroup\$
3
  • \$\begingroup\$ Oh, how neat! If you're non-emptily slicing a string of length k, you're choosing two different indices (the start and end points) out of {0, 1… k} (the k+1 fencepost positions of the string) — so there are choose(k+1, 2) ways to do it. \$\endgroup\$
    – lynn
    Commented Oct 17, 2020 at 13:50
  • \$\begingroup\$ would be a more obvious choice than ɼ to me. \$\endgroup\$ Commented Oct 17, 2020 at 18:56
  • \$\begingroup\$ @JonathanAllan Yes, that probably would have been more elegant! \$\endgroup\$
    – Sisyphus
    Commented Oct 18, 2020 at 1:53
5
\$\begingroup\$

Python 3, 1 * (50 + 50) = 100

-2 bytes thanks to Neil!

First function:

Output is a tuple of characters.

lambda a,b:1and sum(zip(a,b),())or(a+b)*(a-~b)/2+b

Try it online!

Second function:

lambda a,b:0and sum(zip(a,b),())or(a+b)*(a-~b)/2+b

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Would it be unacceptable to use floating-point arithmetic for the Cantor pairing function, or alternatively switch to Python 2, to save a byte? \$\endgroup\$
    – Neil
    Commented Oct 17, 2020 at 10:42
  • 1
    \$\begingroup\$ @Neil yes that works, thanks a lot. \$\endgroup\$
    – ovs
    Commented Oct 17, 2020 at 11:31
5
\$\begingroup\$

Haskell, score 1×(43+43)=86

One program is:

a!b=sum[1..a+b]+b
(a:b)%(c:d)=a:c:b%d;a%b=b

It defines a!b = π(a, b), and an unused “helper function” (%).

The other program is the same, but with a semicolon instead of a newline.

It defines x%y = Z(x, y), and an unused “helper function” (!).

\$\endgroup\$
5
\$\begingroup\$

Husk, score 1 × 12 bytes = 12

First program:

₅
+¹Σ+

Try it online! It takes \$n\$ and \$m\$ as two separate arguments.

Second program:

Ξ
+¹Σ+

Try it online! It takes the two strings in a list.

In the first program, the main function just calls the auxiliary function with its arguments flipped, and in the second program, the auxiliary function is ignored altogether.

\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 1 * 102 bytes = 102

Doing it the @ovs way.

Ordinal mode, 51 bytes

a=>b=>1?b.replace(/./g,(c,i)=>a[i]+c):b-(a+=b)*~a/2

Try it online!

Cardinal mode, 51 bytes

a=>b=>0?b.replace(/./g,(c,i)=>a[i]+c):b-(a+=b)*~a/2

Try it online!


JavaScript (ES6), 13 * 70 bytes = 910

Ordinal mode, 35 bytes

e=>l=>l.replace(/./g,(l,i)=>e[i]+l)

Try it online!

Cardinal mode, 35 bytes

e=>l=>l+(e,l-~e)/2*(((l,i)=>e,e)+l)

Try it online!

e=>l=>l.replace(/./g,(l,i)=>e[i]+l)
       ## # ## # ####        ###    // 13 differences
e=>l=>l+(e,l-~e)/2*(((l,i)=>e,e)+l)

e=>l=>                              // given e and l,
      l+(                           // compute l +
         e,                         // (meaningless filler)
           l-~e)/2*((               // (l + e + 1) / 2 *
                     (l,i)=>e,      // (meaningless filler)
                              e)+l) // (e + l)
\$\endgroup\$
4
\$\begingroup\$

Charcoal, score 200 44 1 * 42 bytes = 42

crossed out 44 is still regular 44

First program:

¿¹⭆§θ⁰⭆θ§λκI⁺Σ…·⁰Σθ⊟θ

Second program:

¿⁰⭆§θ⁰⭆θ§λκI⁺Σ…·⁰Σθ⊟θ

Explanation: Port of @ovs's approach. An if statement at the start is used to select the desired code, thus the distance between the two programs is one byte. Since one program has string output and the other has numeric output it's not possible to share code between the two. See the original answer that scored 10 * 20 19 bytes = 200 190 below for how each branch of the if works:

First program:

⭆§θ⁰⭆θ§λκ

Try it online! Link is to verbose version of code. Takes input as an array of two strings. Explanation:

  θ         Input array
 § ⁰        First element
⭆           Map over characters and join
     θ      Input array
    ⭆       Map over strings and join
       λ    Current string
      §     Indexed by
        κ   Outer index
            Implicitly print

Second program:

I⁺Σ…·⁰Σθ⊟θ

Try it online! Link is to verbose version of code. Takes input as an array of two integers. Explanation:

     ⁰      Literal `0`
       θ    Input array
      Σ     Sum
   …·       Inclusive range
  Σ         Sum
 ⁺          Plus
        ⊟   Last element of
         θ  Input array
I           Cast to string
            Implicitly print
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 6 4dist(2 + 6 4) = 48 24 scored

-24 points thanks to @ovs!

I am sure that the programs can be heavily improved.

Ordinal mode:

Outputs the zipped string as a list of characters.

Also takes in input swapped, so "Hello,", "World!" -> "WHoerllldo!," and "World!", "Hello," -> "HWeolrllod,!".

How?

.ι          # Interleave the two inputs, then output implicitly

Try it online!

Cardinal mode:

+LO+

Takes in input in the right order this time!

How?

+         # Add m and n
 LO       # Summation of all numbers in range [1...m+n]
   +      # Add m (which is still surviving in the stack) to the result and output implicitly

Try it online again!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Since \${1 \over 2} (n+m)(n+m+1)\$ is the sum of the first \$n+m\$ positive integers, +LO+ works as the Cardinal mode. \$\endgroup\$
    – ovs
    Commented Oct 17, 2020 at 11:32
2
\$\begingroup\$

R, 1×(76+76) = 152

Ordinal mode:

function(a,`^`=Reduce,p=paste0)`if`(F,sum(1:sum(a),a[2]),p^p^strsplit(a,""))

Try it online!

Cardinal mode:

function(a,`^`=Reduce,p=paste0)`if`(T,sum(1:sum(a),a[2]),p^p^strsplit(a,""))

Try it online!

Input is as a length-2 vector.

The only difference between the two functions is the 37th character, which flips between F and T. Either the second or the third argument of if is therefore executed. For the ordinal mode (interleaving), I relied on this tip by J.Doe.

\$\endgroup\$
1
\$\begingroup\$

Pyt, 2x(6+6)=24

Ordinal mode:

Đ←+⇹ŕǰ

Requires strings to be passed in as arrays of characters

Try it online!

Đ         implicit input; duplicate string
 ←        get second input
  +       element-wise string addition
   ⇹ŕ     flip the stack and remove the top
     ǰ    join the list of strings into one string; implicit print

Cardinal mode:

Đ←+△+ǰ

Try it online!

Đ           implicit input (m); duplicate top of stack
 ←          get input (n)
  +         add the top two items on the stack (yielding n+m)
   △        get the (n+m)th triangle number
    +       add the top two items on the stack (yielding 1/2*(n+m)*(n+m+1)+m)
     ǰ      join the stack as strings (essentially a no-op here)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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