35
\$\begingroup\$

Introduction:

A typical cartoonish cactus usually looks like this:

enter image description here

One big stem in the middle, with some L-shaped branches sticking out.

We'll use this general shape for this challenge.

Challenge:

Given a pair of words, create an ASCII-art cactus with two upside down alphabets as stem. The first word is the left branch and the second word is the right branch:

E.g. input = ["cartoonish","testing"], will result in the following cactus:

  zz
  yy
  xx g
  ww n
  vv i
  uu t
  ttes
  ss
  rr
  qq
  pp
  oo
  nn
  mm
  ll
  kk
h jj
s ii
i hh
n gg
o ff
o ee
t dd
racc
  bb
  aa

The first letter of the words are part of the stem; then it'll grow out two letters; and continue upwards for the remaining letters.

Challenge rules:

  • The words will have a guaranteed length of \$5 \leq L \leq 99\$
  • The words can start with an a or z, even though the resulting cactus might look pretty ridiculous that way; they can also start with the same letter or even be the same.
  • A word can tower above the stem (e.g. yoghurt).
  • Although leading spaces to have the correct shape are of course mandatory, one or more (additional) leading/trailing spaces or newlines are allowed. As long as the correct cactus is somewhere on the screen, it's fine.
  • All the letters may be uppercase instead of lowercase, as long as its consistent across the entire 'cactus'.
  • Output format is flexible, so can be printed to STDOUT; returned as a string; returned as a character-matrix; etc.

General Rules:

  • This is , so the shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code (e.g. TIO or ATO).
  • Also, adding an explanation for your answer is highly recommended.

Test Cases:

Input: ["cartoonish","testing"]
Output:

  zz
  yy
  xx g
  ww n
  vv i
  uu t
  ttes
  ss
  rr
  qq
  pp
  oo
  nn
  mm
  ll
  kk
h jj
s ii
i hh
n gg
o ff
o ee
t dd
racc
  bb
  aa

Input: ["yoghurt","antidisestablishmentarianism"]
Output:

t
r
u
h zz m
goyy s
  xx i
  ww n
  vv a
  uu i
  tt r
  ss a
  rr t
  qq n
  pp e
  oo m
  nn h
  mm s
  ll i
  kk l
  jj b
  ii a
  hh t
  gg s
  ff e
  ee s
  dd i
  cc d
  bb i
  aant

Input: ["cactus","stems"]
Output:

  zz
  yy
  xx
  ww
  vv
  uu s
  tt m
  sste
  rr
  qq
  pp
  oo
  nn
  mm
  ll
  kk
  jj
  ii
  hh
  gg
s ff
u ee
t dd
cacc
  bb
  aa

Input: ["duplicate","duplicate"]
Output:

  zz
  yy
  xx
  ww
  vv
  uu
  tt
  ss
  rr
  qq
  pp
  oo
  nn
  mm
  ll
  kk
e jj e
t ii t
a hh a
c gg c
i ff i
l ee l
puddup
  cc
  bb
  aa
\$\endgroup\$
6
  • 2
    \$\begingroup\$ Are the words guaranteed to be just lowercase letters? If so may submissions choose to use upppercase instead? \$\endgroup\$ Commented Mar 18 at 12:19
  • \$\begingroup\$ Is there a maximum length of an input word (to help sizing the bounding box)? \$\endgroup\$ Commented Mar 18 at 12:19
  • \$\begingroup\$ @noodleman Yes, uppercase instead of lowercase is allowed, as long as its consistent. I've add it to the rules. \$\endgroup\$ Commented Mar 18 at 22:44
  • 1
    \$\begingroup\$ @DomHastings Yes, you can assume the max length is 99, since some of the longest words are around the 30-40 mark anyway. Although, if you could edit in an answer for arbitrary sized words below your current, I would appreciate it. I'm just curious how much longer it would be, and what kind of alternative approach you'd use. :) \$\endgroup\$ Commented Mar 18 at 22:47
  • 3
    \$\begingroup\$ Upside-down L shaped branches? In what kind of alphabet are those upside-down L's?! :) \$\endgroup\$ Commented Mar 18 at 23:25

17 Answers 17

8
\$\begingroup\$

Python, 130 bytes

lambda a,b:[*zip(*g(a),*g(b)[::-1])][::-1]
s=" "*102
g=lambda a:[(p:=s[65:ord(a[0])])+a[2:]+s,p+a[1]+s,"%c"*26%(*range(65,91),)+s]

A lambda returning a matrix (list of tuples) of characters.

Attempt This Online!

\$\endgroup\$
1
  • \$\begingroup\$ Clever to index into the spaces string from 65 to the character’s ordinal. \$\endgroup\$ Commented Mar 20 at 15:32
7
\$\begingroup\$

K (ngn/k), 53 bytes

Takes a list of 2 strings and returns a character matrix.

{|+(|/#'x)$x,:|y}.{(""[!97!*x],/:|1 2_x),,`c$97+!26}'

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ if we restrict the maximum input word size, and add a bunch of leading newlines, (|/#'x)$x,: -> 125$x, would save a few bytes \$\endgroup\$
    – ovs
    Commented Mar 19 at 9:10
7
\$\begingroup\$

JavaScript (Node.js), 151 bytes

Expects an array of two strings.

f=(a,y=i=[],c=e=Buffer([y>25?32:97+y]),b=a.map((w,k)=>w[0]==c?w[(i[k]=2)-k]+w[1+k]:(x=w[++i[k]])?e=k?" "+x:x+" ":"  "))=>++e?c:f(a,-~y)+`
`+b.join(c+c)

Try it online!

Commented

f = (                  // f is a recursive function taking:
  a,                   //   a[] = input
  y =                  //   y = vertical position
  i = [],              //   i[] = array of positions in words
  c =                  //   c = current middle character
  e = Buffer([         //   e = copy of c
    y > 25 ? 32        //     use a space if y > 25
           : 97 + y    //     otherwise, use 'a' ... 'z'
  ]),                  //
  b = a.map((w, k) =>  // for each word w at index k in a[]:
    w[0] == c ?        //   if the first letter of w is c:
      w[               //     append the 2nd or 3rd letter of w
        (i[k] = 2) - k //     and initialize i[k] to 2
      ] +              //
      w[1 + k]         //     append the other letter (3rd or 2nd)
    :                  //   else:
      (                //     try to increment i[k]
        x = w[++i[k]]  //     save w[i[k]] in x
      ) ?              //     if it's defined:
        e =            //       set e to a non-zero'ish value
          k ? " " + x  //         append a space followed by x
            : x + " "  //         or x followed by a space
      :                //     else:
        "  "           //       append 2 spaces
  )                    // end of map()
) => ++e               // if e is a space (i.e. we have y > 25
?                      // and both words have been fully written):
  c                    //   stop
:                      // else:
  f(a, -~y) +          //   append the result of a recursive call
  `\n` +               //   followed by a new line 
  b.join(c + c)        //   followed by b[] joined with c + c
\$\endgroup\$
7
\$\begingroup\$

R 4.3.2, 287 bytes

Certainly, there's room for optimization...

Edit

THE final version.

  • Bonus: the headspace region is calculated to fit exactly the height of the cactus including the branches

    f=\(x,y){a=rev(letters);s=substr;b=nchar;`!`=\(c)which(a==s(c,1,1));`?`=\(y)((24+b(y)-!y)%/%26)*(b(y)-2-!y);k=max(?x,?y);r=l=m=q=rep(" ",26+k);a=c(rep(" ",k),a);`?`=\(e)s(e,2,2);`/`=\(l,x){for(j in 3:b(x))l[3-j+!x]=s(x,j,j);l};m[!x]=?x;q[!y]=?x;l=l/x;r=r/y;writeLines(paste0(l,m,a,a,q,r))}
    

    Try it online! (backslash replaced with function due to the old R version)

I have tried to replace writeLines with cat("\n"), that removed 2 bytes of the code, but the output is slightly different (an empty line over the cactus):

g=\(x,y){a=rev(letters);s=substr;b=nchar;`!`=\(c)which(a==s(c,1,1));`?`=\(y)((24+b(y)-!y)%/%26)*(b(y)-2-!y);k=max(?x,?y);r=l=m=q=rep(" ",26+k);a=c(rep(" ",k),a);`?`=\(e)s(e,2,2);`/`=\(l,x){for(j in 3:b(x))l[3-j+!x]=s(x,j,j);l};m[!x]=?x;q[!y]=?x;l=l/x;r=r/y;cat(paste0("\n",l,m,a,a,q,r))}

Try this one online

Yet another R, 231 bytes

This is a stripped down version - without the cactus headspace calculation. The height of output window is 99 lines.

\(x,y){a=rev(letters);s=substr;b=nchar;`!`=\(c)which(a==s(c,1,1));r=l=m=q=rep(" ",99);a=c(rep(" ",73),a);`?`=\(e)s(e,2,2);`/`=\(l,x){for(j in 3:b(x))l[3-j+!x]=s(x,j,j);l};m[!x]=?x;q[!y]=?x;l=l/x;r=r/y;cat(paste0("\n",l,m,a,a,q,r))}

Attempt This Online!

Test (the first method):

    > f("yoghurt","antidisestablishmentarianism")
t     
r     
u     
h zz m
goyy s
  xx i
  ww n
  vv a
  uu i
  tt r
  ss a
  rr t
  qq n
  pp e
  oo m
  nn h
  mm s
  ll i
  kk l
  jj b
  ii a
  hh t
  gg s
  ff e
  ee s
  dd i
  cc d
  bb i
  aant
\$\endgroup\$
5
  • \$\begingroup\$ I get an error: Error in y - !y : non-numeric argument to binary operator ato.pxeger.com/…. The problem seems to be with operator precendence of ? and !. \$\endgroup\$
    – pajonk
    Commented Mar 19 at 6:56
  • 4
    \$\begingroup\$ Also, linking to an online repl (like the one I linked) in your answer, would be nice :) \$\endgroup\$
    – pajonk
    Commented Mar 19 at 7:00
  • 4
    \$\begingroup\$ @pajonk I have tinkered the code so much, that it finally broke. Turned out, R does not allow an expression like !y-y, so it has to be reversed to -y+!y. It seems impossible to have two unary operators in the same expression. Thanks for the interest, the code is repared (incidentally it still has the same length). \$\endgroup\$ Commented Mar 19 at 8:33
  • 3
    \$\begingroup\$ It is possible, just !y-y does the - first, and then the ! according to the operator precedence. \$\endgroup\$
    – pajonk
    Commented Mar 19 at 9:46
  • 1
    \$\begingroup\$ Also, this is not a recursive function, so you can omit the f= (and submit an anonymous function). And the second version is fine according to the rules ("one or more (additional) leading/trailing spaces or newlines are allowed") \$\endgroup\$
    – pajonk
    Commented Mar 19 at 9:47
6
\$\begingroup\$

Perl 5 + -pF, 93 bytes

This solution utilises ANSI escape sequences and necessitates a compatible terminal emulator. This solution uses a hard-coded row position of 29, but this can be trivially changed to increase the available space (at the cost of having to scroll to see the cactus) up to 99 without incurring any additional byte-cost. There is another version below that scales as needed.

$_=".[29;".(3+$|--).H.join$"="..[A",a..z;s/$F[0]\K/.[s@{[$|?"..$F[1]..":$F[1]]}@F[2..@F].[u/g

Try it online!

Explanation

For each input string, the input is automatically read, placed in $_ (implicit -n from -p) and split into characters in @F (-F).

$_ is then re-set to "\x1b[29;nH" (where n is either 3 or 4 depending on the alternating value of $|) which positions the cursor on the 29th row and 3rd (or 4th) column, and has the lowercase alphabet - joined on "\x08\x1b[A" which is backspace followed by the ANSI escape sequence for "up one row" (which is also stored in $") - concatenated to it.

s/// works on $_ by default, so the first char of the word ($F[0]) is s///ubstituted (keeping the start letter in place using \K which will insert the value of the substitution after the char) with the ANSI escape sequence for "save cursor position" (\x1b[s), the inline list (@{[...]}) consisting of the next letter of the word ($F[1], conditionally surrounded by double backspaces if $| is truthy) and then the interpolated sub-list of the remaining letters in the word from index 2 (automatically joined with $" which we set earlier to backspace and "up one row", finally followed by the ANSI escape sequence for "restore cursor position" (\x1b[u).

$_ is then implicitly printed (via -p).


Perl 5 + -p040lF -MList::Util+max, 127 bytes

This solution also utilises ANSI escape sequences and necessitates a compatible terminal emulator, but it automatically moves the cursor to the correct position.

$\.=".[25B"." "x--$|.join($"="..[A",a..z)=~s/$F[0]\K/.[s@{[$|?"..$F[1]..":$F[1]]}@F[2..@F].[u/gr;$;=max$;,-125+@F+ord}{$_="."x$

Try it online!

Explanation

The majority of this is the same as the previous solution, except the output is stored in $\ instead of $_ (which is implicitly output after every call to print, which happens automatically at the end of the program due to -p).

For each input word (implicit -n from -p, stored in $_, split into chars in @F via -F) the following happens:

$\ has "\x1b[25B" added which is the ANSI escape sequence for "move the cursor down 25 lines" and, conditionally (depending on the alternating value of --$|), a space (can't use $" here as that could is overwritten in the first loop), concatenated with the result of the alphabet joining and substitution which is the same as the previous version.

Additionally, $; is set to the max of either $; (\x1c by default) or -125+@F+ord (where @F used in scalar context is the length of the list and ord is the ordinal of the first char of the input $_).

Outside of the implicit while loop from -n (-p), $_ is set to one space, followed by $; (using the implicit ; added from -n - while <STDIN> { ... ;}) repetitions of "\x0c" (form feed).

$_ is then output automatically via -p, which also outputs $\.

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

Vyxal, 152 bitsv2, 19 bytes

ƛḣ$øA‹$ḣṘ"$꘍;⁽ṘẆnṘ:"j§

Try it Online!

Bitstring:

00001001101110000001011000000000100110111110110100111111111100110011101111011010101000001111101111001011011001100011000110111101111001011010010011010101

22 bytes unencoded. Can be 17.75 bytes with the L flag.

First code golf in a while. Feels good to be back doing the golf.

Explained

ƛḣ$øA‹$ḣṘ"$꘍;⁽ṘẆnṘ:"j§­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁤⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁣‏⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏‏​⁡⁠⁡‌⁢⁣​‎‏​⁢⁠⁡‌⁢⁤​‎‎⁡⁠⁤⁢‏⁠‎⁡⁠⁤⁣‏⁠‎⁡⁠⁤⁤‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁢⁡⁡‏⁠‎⁡⁠⁢⁡⁢‏⁠‎⁡⁠⁢⁡⁣‏⁠‎⁡⁠⁢⁡⁤‏‏​⁡⁠⁡‌⁣⁢​‎‎⁡⁠⁢⁢⁡‏‏​⁡⁠⁡‌⁣⁣​‎‎⁡⁠⁢⁢⁢‏‏​⁡⁠⁡‌­
ƛ           ;           # ‎⁡To each string S in the input:
 ḣ$                     # ‎⁢  Push S[1:], S[0]
   øA‹                  # ‎⁣  and calculate the 0 based index of S[0] in the alphabet
      $ḣṘ               # ‎⁤  Push S[1:][0], S[1:][1::-1]
         "              # ‎⁢⁡  and pair into a list. The first item is the bit that's coming out of the stem, the second is the spike.
          $꘍            # ‎⁢⁢  and prepend (number of spaces calculated earlier) to each string in that pair
# ‎⁢⁣This generates a list of what'll be in each column. The spaces at the front are how far down the cactus the characters will be.
             ⁽ṘẆ        # ‎⁢⁤Reverse the order of the first item so it's [spike, stem]
                nṘ:"    # ‎⁣⁡["zyx...cba", "zyx...cba"]
                    j   # ‎⁣⁢Join the list of lists of stem and spike on ^. By some miracle, this also flattens the list.
                     §  # ‎⁣⁣Transpose, and join on newlines
💎

Created with the help of Luminespire.

\$\endgroup\$
1
  • \$\begingroup\$ 18.25 (20 unencoded) \$\endgroup\$
    – emanresu A
    Commented Mar 27 at 1:06
4
\$\begingroup\$

Charcoal, 25 bytes

↑E²βF²«‖SθJι±⌕β§θ⁰…θ²↑✂θ²

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

↑E²β

Output two copies of the alphabet vertically.

F²«

Loop over the two inputs.

Reflect the canvas (this is golfier than trying to output the two words in different directions).

Sθ

Input the next word.

Jι±⌕β§θ⁰

Jump to its starting letter.

…θ²

Output the first two letters of the word.

↑✂θ²

Output the rest of the word upwards.

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

APL (Dyalog Unicode), 51 49 44 42 40 bytes SBCS

Assume ⎕io←0, take input as left and right arguments. 44 -> 42 thanks to @ovs, and 42 -> 40 thanks to @att.

⊖⍉∘↑⍤,∘⌽⍥{((a⍳⊃⍵)↓⍣¯1¨⌽0 1 1⊂⍵),⊂a←⎕C⎕A}

How?

The dfn transforms a string into its half of the cactus.

{((a⍳⊃⍵)↓⍣¯1¨⌽0 1 1⊂⍵),⊂a←⎕C⎕A}
                          a←⎕C⎕A  a is abcd...z, half of the middle stem.
              ⌽0 1 1⊂⍵            vertical and horizontal stems that are
         ↓⍣¯1¨                     aligned (using white spaces) with
  (a⍳⊃⍵)                           the first letter of ⍵ in a

With the dfn denoted as f, the answer is ⊖⍉∘↑⍤,∘⌽⍥f which is equivalent to {⊖⍉↑(f⍺),(⌽f⍵)}.

{⊖⍉↑(f⍺),(⌽f⍵)}
    (f⍺) (⌽f⍵)  two halves of the cactus
        ,       stick them together
 ⊖⍉↑            combine the columns

Try it on tryapl.org

\$\endgroup\$
2
  • 1
    \$\begingroup\$ you can save a byte by reshaping the empty string. And if you remove the left-most , the whole thing becomes a 2-train/atop, which achieves the same (You would need to add parentheses around the whole thing for your testing code on tryapl, but those don't count to the function itself) \$\endgroup\$
    – ovs
    Commented Mar 19 at 9:13
  • 1
    \$\begingroup\$ (⊂''⍴⍨a⍳⊃⍵),¨(a⍳⊃⍵)↓⍣¯1¨ \$\endgroup\$
    – att
    Commented Mar 19 at 18:39
4
\$\begingroup\$

Uiua, 40 38 36 bytes

⇌⍉⬚@ (⊂⇌∩(⊂+@a⇡26≡⊂:⊟°⊂:¤↯:@ -@a°⊂))

Try it

38 → 36 bytes thanks to Joao-3 :)

Explanation

⬚@ (…)

Uiua won’t join together arrays of different sizes, so this sets a fill value of a space for the following function:

  • ∩(…)
    

    Call this function on both inputs:

    • ¤↯:@ -@a°⊂
      

      Separate the first character from the rest, get the character's position in the alphabet and make a string of that many spaces, then fix it (wrap it in an array) for later.

    • ⊂+@a⇡26≡⊂:⊟°⊂:
      

      Separate the first character of the rest from the rest, and use them both to make an arm. Then join with the spaces made earlier, get the alphabet and join it to the 2D matrix.

  • ⊂⇌
    

    Reverse the first arm and join it to the second.

⇌⍉

Rotate the array to the correct orientation, and it’s done!

\$\endgroup\$
4
  • \$\begingroup\$ ⇌⍉⬚@ (⊂⇌∩(⊂+@a⇡26≡⊂:⊟°⊂:¤↯:@ -@a°⊂)), 36 bytes \$\endgroup\$
    – Joao-3
    Commented Mar 19 at 17:45
  • \$\begingroup\$ @Joao-3 nice idea, for some reason it hadn’t occurred to me that i could use fill on the whole thing, and just simplify the whole joining process. thanks! \$\endgroup\$ Commented Mar 19 at 17:58
  • \$\begingroup\$ That code on the code block is outdated though \$\endgroup\$
    – Joao-3
    Commented Mar 19 at 18:02
  • \$\begingroup\$ @Joao-3 good catch, fixed \$\endgroup\$ Commented Mar 19 at 18:04
4
\$\begingroup\$

Python, 167 bytes

lambda l,r,o=lambda s:" "*(ord(s[0])-97):[("{:99s}"*6).format(o(l)+l[2:],o(l)+l[1],*["abcdefghijklmnopqrstuvwxyz"]*2,o(r)+r[1],o(r)+r[2:])[98-i::99]for i in range(99)]

Attempt This Online!

  • Returns a list of rows
  • Inputs that would require more than 99 chars won't work, which is allowed
  • Expects 2 words, lowercase ascii (or at least their first char must be), length of 2 or more (it could be 1 byte shorter if I defaulted to uppercase)

Old version (function with print rather than lambda: I wasn't too sure about I/O conventions) with explanation:

Python, 197 194 192 185 178 175 174 bytes

o=lambda s:" "*(ord(s[0])-97)
def f(l,r):[print(("{:99s}"*6).format(o(l)+l[2:],o(l)+l[1],*["abcdefghijklmnopqrstuvwxyz"]*2,o(r)+r[1],o(r)+r[2:])[98-i::99])for i in range(99)]

Attempt This Online!

  • Prints a cactus to STDOUT, vertically padded to 99 chars
  • Inputs that would require more than 99 chars won't work, which is allowed
  • Expects 2 words, lowercase ascii (or at least their first char must be), length of 2 or more.
    • (It could be 1 byte shorter if I defaulted to uppercase)

How?

o=lambda s:" "*(ord(s[0])-97)              # Function that, given an input word,
                                           # returns as many whitespaces as the
                                           # index of the first char in unicode,
                                           # after "a" (ord("a") == 97), i.e.
                                           # how much the branch should be raised
                                           # from the ground.

def f(l,r):
                                           # Cactus built horizontally by rows:

  ( o(l)+l[2:],                            # * padding + letters 3+ of the word
    o(l)+l[1],                             # * padding + second letter
    *["abcdefghijklmnopqrstuvwxyz"]*2,     # * whole alphabet twice (ugly but I
                                           #   can't golf it further as strings)
    o(r)+r[1],                             # * padding + second (right) 
    o(r)+r[2:]  )                          # * padding + letters 3+ (right)
#
# └──────┬──────┘
#        └──────────────┐
#                       ╽
  ("{:99s}"*6).format( ... )               # Concatenation of 6 strings, each
#                                          # right-padded to 99 characters.
# └───────────┬────────────┘
#        ┌────┘
#        ╽
[print( ... [98-i::99])for i in range(99)] # A way of wrapping the string at 99
                                           # and printing it transposed.
```
\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 164 bytes

f=(a,b,p=![i=10],q=0,c=i>35?S:i.toString(++i),s=(p?(a[++p]||S)+S:a[0]==c?a[p=2]+a[1]:S+S)+c+c+(q?S+(b[++q]||S):b[0]==c?b[1]+b[q=2]:S))=>1/s?S:f(a,b,p,q)+`
`+s;S=' '

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Vyxal, 28 bytes

vhøA‹ð*?vḢƛḣ$W;÷Ṙ"+n2εwYfvṘ§

Try it Online!

I'm very rusty, this can probably be done in about 25 bytes.

Explanation:

vhøA‹ð*?vḢƛḣ$W;÷Ṙ"+n2εwYfvṘ§­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢​‎⁠‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏⁠‎⁡⁠⁣⁣‏⁠⁠‎⁡⁠⁤⁣‏‏​⁡⁠⁡‌⁤​‎⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏⁠‎⁡⁠⁤⁢‏⁠‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏⁠‎⁡⁠⁢⁡⁢‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁢⁣​‎‎⁡⁠⁢⁡⁤‏⁠‎⁡⁠⁢⁢⁡‏⁠‎⁡⁠⁢⁢⁢‏⁠‎⁡⁠⁢⁢⁣‏‏​⁡⁠⁡‌⁢⁤​‎‎⁡⁠⁢⁢⁤‏⁠‎⁡⁠⁢⁣⁡‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁢⁣⁢‏⁠‎⁡⁠⁢⁣⁣‏⁠‎⁡⁠⁢⁣⁤‏‏​⁡⁠⁡‌­
vhøA‹                         # ‎⁡For both words, push first item's position in alphabet
     ð*                       # ‎⁢Multiply with " "
       ?vḢƛ   ;               # ‎⁣Map through suffix of each word:
           ḣ$W                # ‎⁤  Extract head and rest, swap and wrap in list
               ÷Ṙ"            # ‎⁢⁡Reverse order of second item
                  +           # ‎⁢⁢Append spaces to each pair
                   n2εw       # ‎⁢⁣Push alphabet twice, wrap in list
                       Yf     # ‎⁢⁤Interleave with formatted words and flatten
                         vṘ§  # ‎⁣⁡Reverse each item, transpose and join by newlines
💎

Created with the help of Luminespire.

\$\endgroup\$
1
  • \$\begingroup\$ Try 22 \$\endgroup\$
    – lyxal
    Commented Mar 20 at 12:43
3
\$\begingroup\$

J, 62 bytes

0|.@|:(,~|.)&((u:97+i.26)&([,](,"1(,@{.,:}.)@}.)~' '#~(i.{.)))

Attempt This Online!

Probably more bytes to shave off here but not seeing them now...

Function that takes the left branch as the right arg and the right branch as the left arg.

Draws each half in canonical, horizontal form with branch underneath:

 abcdefghijklmnopqrstuvwxyz
                   o
                   mebranch

Reverses the right half and prepends it.

Transposes and reverses.

\$\endgroup\$
3
\$\begingroup\$

APL+WIN, 154 or 76 72 bytes

Original. Prompts for first string followed by second. Index origin = 0:

x←⎕⋄y←⎕⋄a←⎕av[17+⍳26]⋄m←((∊⌈/26⌈¨(n←¯2+¨⍴¨s)+i←a⍳↑¨s←x y),6)⍴' '⋄m[(↑i)+⍳↑n;0]←2↓x⋄m[↑i;1]←↑1↓x⋄m[;3]←m[;2]←(↑⍴m)↑a⋄m[∊1↓i;4]←↑1↓y⋄m[(∊1↓i)+⍳∊1↓n;5]←2↓y⋄⊖m

Try it online! Thanks to Dyalog Classic

New approach. Prompts for the two strings as a nested vector:

l←∊26+⌈/⍴¨s←⎕⋄⍉⌽3⊖a⍪((∊2⍴¨-a⍳↑¨⌽s)⌽1⊖⊃l↑¨(1⌷¨s),2↓¨⌽s)⍪a←l↑a←⎕av[17+⍳26]

Try it online! Thanks to Dyalog Classic

\$\endgroup\$
2
\$\begingroup\$

Jelly,  25  23 bytes

ḢO_97⁶x;Ɱ,Ḣ$Øaṭ¹Ṛƭ)Ẏz⁶Ṛ

A monadic Link that accepts a pair of lists of characters and yields a list of lists of characters (lines).

Try it online! (The footer joins the lines with newline characters.)

How?

ḢO_97⁶x;Ɱ,Ḣ$Øaṭ¹Ṛƭ)Ẏz⁶Ṛ - Link: pair of lists of characters, Words
                  )     - for each {Word in Words}:
Ḣ                       -   pop the first character
 O_97                   -   ordinal {of that} minus 97 -> height
     ⁶x                 -   space character repeated {that many times}
           $            -   last two links as a monad - f(BeheadedWord)
          Ḣ             -     pop the first character -> second character of Word
         ,              -     pair {the rest of BeheadedWord} with {that}
        Ɱ               -   map across {these two WordParts} with:
       ;                -     concatenate {WordPart} to {RepeatedSpaces}
            Øaṭ         -   tack on the lower-case alphabet
                 ƭ      -   alternate between:
               ¹        -     do nothing (when processing the first Word)
                Ṛ       -     reverse (when processing the second Word)
                   Ẏ    - tighten
                    z⁶  - transpose with space character as filler
                      Ṛ - reverse
\$\endgroup\$
2
\$\begingroup\$

Matlab, 181 bytes

Try it online! Input for first test case would be F(["cartoonish";"testing"])

I feel like Matlab isn't well suited for working with strings. But it was a great exercise in array indexing.

s=char(cellstr(input("")));C(1:26,3:4)=char([97:122;97:122]');for i=1:2;C(s(i,1)-96,5:6)=s(i,2:3);C(s(i,1)-95:s(i,1)+length(s(i,:))-99,6)=s(i,4:end)';C=flip(C,2);end;flip(flip(C),2)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ thanks, actually found a small mistake still and read up on how to properly write Matlab to take inputs like it's necessary for TIO \$\endgroup\$
    – Xenox
    Commented Mar 19 at 21:46
1
\$\begingroup\$

05AB1E, 21 bytes

εćUć‚AXkúAª}`R«€SζJ»R

Inputs as a pair in reversed order.

Try it online.

Explanation:

ε           # Map over both strings:
 ć          #  Extract head; pop and push remainder-string and first character
  U         #  Pop this first character and store it in variable `X`
   ć        #  Extract head again
    ‚       #  Pair the remainder-string and first char together
     AXk    #  Get the 0-based index of character `X` in the lowercase alphabet
        ú   #  Pad that many leading spaces to both strings in the pair
         Aª #  Append a lowercase alphabet to this pair
}`          # After the map: pop and push both triplets separated to the stack
  R         # Reverse the second/top triplet
   «        # Merge the two triplets together
    €S      # Convert each string to a list of characters
      ζ     # Zip/transpose; swapping rows/columns,
            # with space as filler character for unequal length rows
       J    # Join all inner character lists back together to strings
        »   # Join these strings by newlines
         R  # Reverse the entire multiline string
            # (after which the result is output implicitly)

I originally started with an approach that uses the Canvas builtin to draw everything at once, but this ended up roughly three times as long (57 bytes):

Aû¹н©¡¨®ý¹ð'aAûIн©¡¨®ýIJ₂₂A¹нk-3¹gÍ0Y3₂₂®-3²gÍ)ć•ĀçR5•SRΛ

Try it online.

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