13
\$\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\$
  • \$\begingroup\$ Sandbox Related \$\endgroup\$ – caird coinheringaahing Oct 16 at 22:58
  • 1
    \$\begingroup\$ Must the two programs be in the same language? \$\endgroup\$ – Robin Ryder Oct 17 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 Oct 17 at 9:03
  • \$\begingroup\$ @RobinRyder Yes, the two programs must be in the same language \$\endgroup\$ – caird coinheringaahing Oct 17 at 11:52
  • \$\begingroup\$ @SunnyMoon Yep, both of those are fine \$\endgroup\$ – caird coinheringaahing Oct 17 at 11:52
10
\$\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)

| improve this answer | |
\$\endgroup\$
  • \$\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 Oct 17 at 13:50
  • \$\begingroup\$ would be a more obvious choice than ɼ to me. \$\endgroup\$ – Jonathan Allan Oct 17 at 18:56
  • \$\begingroup\$ @JonathanAllan Yes, that probably would have been more elegant! \$\endgroup\$ – Sisyphus Oct 18 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!

| improve this answer | |
\$\endgroup\$
  • 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 Oct 17 at 10:42
  • 1
    \$\begingroup\$ @Neil yes that works, thanks a lot. \$\endgroup\$ – ovs Oct 17 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” (!).

| improve this answer | |
\$\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.

| improve this answer | |
\$\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)
| improve this answer | |
\$\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
| improve this answer | |
\$\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!

| improve this answer | |
\$\endgroup\$
  • 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 Oct 17 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.

| 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.