Introduction:
A typical cartoonish cactus usually looks like this:
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
aorz, 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 code-golf, 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
-
2\$\begingroup\$ Are the words guaranteed to be just lowercase letters? If so may submissions choose to use upppercase instead? \$\endgroup\$noodle person– noodle person2024年03月18日 12:19:05 +00:00Commented Mar 18, 2024 at 12:19
-
\$\begingroup\$ Is there a maximum length of an input word (to help sizing the bounding box)? \$\endgroup\$Dom Hastings– Dom Hastings2024年03月18日 12:19:44 +00:00Commented Mar 18, 2024 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\$Kevin Cruijssen– Kevin Cruijssen2024年03月18日 22:44:41 +00:00Commented Mar 18, 2024 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\$Kevin Cruijssen– Kevin Cruijssen2024年03月18日 22:47:24 +00:00Commented Mar 18, 2024 at 22:47
-
3\$\begingroup\$ Upside-down L shaped branches? In what kind of alphabet are those upside-down L's?! :) \$\endgroup\$noodle person– noodle person2024年03月18日 23:25:46 +00:00Commented Mar 18, 2024 at 23:25
17 Answers 17
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.
-
1\$\begingroup\$ Clever to index into the spaces string from 65 to the character’s ordinal. \$\endgroup\$noodle person– noodle person2024年03月20日 15:32:11 +00:00Commented Mar 20, 2024 at 15:32
K (ngn/k), 53 bytes
Takes a list of 2 strings and returns a character matrix.
{|+(|/#'x)$x,:|y}.{(""[!97!*x],/:|1 2_x),,`c97ドル+!26}'
-
\$\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– ovs2024年03月19日 09:10:02 +00:00Commented Mar 19, 2024 at 9:10
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)
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
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
functiondue 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))}
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))}
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
-
\$\begingroup\$ I get an error:
Error in y - !y : non-numeric argument to binary operatorato.pxeger.com/…. The problem seems to be with operator precendence of?and!. \$\endgroup\$pajonk– pajonk2024年03月19日 06:56:21 +00:00Commented Mar 19, 2024 at 6:56 -
4\$\begingroup\$ Also, linking to an online repl (like the one I linked) in your answer, would be nice :) \$\endgroup\$pajonk– pajonk2024年03月19日 07:00:35 +00:00Commented Mar 19, 2024 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\$Glory2Ukraine– Glory2Ukraine2024年03月19日 08:33:29 +00:00Commented Mar 19, 2024 at 8:33 -
3\$\begingroup\$ It is possible, just
!y-ydoes the-first, and then the!according to the operator precedence. \$\endgroup\$pajonk– pajonk2024年03月19日 09:46:35 +00:00Commented Mar 19, 2024 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– pajonk2024年03月19日 09:47:06 +00:00Commented Mar 19, 2024 at 9:47
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
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$
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 $\.
Vyxal, 146 bitsv2 , 18.25 bytes
RƛṫøA‹$ṫ"$꘍kzJ;(Ṙẇf§
Bitstring:
01100011010100001110000111101010000100100111011100100011100110011010010111100111000011110101010100011001011010111000101101001001001101011011110010
20 bytes unencoded. Thanks to @emanresu for the golfing suggestion which I somehow didn't notice for 7 months.
First code golf in a while. Feels good to be back doing the golf.
Explained (old)
ƛḣ$ø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.
-
\$\begingroup\$ 18.25 (20 unencoded) \$\endgroup\$emanresu A– emanresu A2024年03月27日 01:06:38 +00:00Commented Mar 27, 2024 at 1:06
-
\$\begingroup\$ hello you have been golfed \$\endgroup\$emanresu A– emanresu A2024年10月27日 03:35:20 +00:00Commented Oct 27, 2024 at 3:35
Charcoal, 25 bytes
↑E2βF2«‖SθJι±⌕β§θ0...θ2↑✂θ2
Try it online! Link is to verbose version of code. Explanation:
↑E2β
Output two copies of the alphabet vertically.
F2«
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ι±⌕β§θ0
Jump to its starting letter.
...θ2
Output the first two letters of the word.
↑✂θ2
Output the rest of the word upwards.
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
-
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– ovs2024年03月19日 09:13:33 +00:00Commented Mar 19, 2024 at 9:13 -
1\$\begingroup\$
(⊂''⍴⍨a⍳⊃⍵),¨→(a⍳⊃⍵)↓⍣¯1¨\$\endgroup\$att– att2024年03月19日 18:39:57 +00:00Commented Mar 19, 2024 at 18:39
Uiua, (削除) 40 (削除ここまで) (削除) 38 (削除ここまで) 36 bytes
⇌⍉⬚@ (⊂⇌∩(⊂+@a⇡26≡⊂:⊟°⊂:¤↯:@ -@a°⊂))
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!
-
\$\begingroup\$
⇌⍉⬚@ (⊂⇌∩(⊂+@a⇡26≡⊂:⊟°⊂:¤↯:@ -@a°⊂)), 36 bytes \$\endgroup\$Joao-3– Joao-32024年03月19日 17:45:05 +00:00Commented Mar 19, 2024 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\$noodle person– noodle person2024年03月19日 17:58:26 +00:00Commented Mar 19, 2024 at 17:58
-
\$\begingroup\$ That code on the code block is outdated though \$\endgroup\$Joao-3– Joao-32024年03月19日 18:02:06 +00:00Commented Mar 19, 2024 at 18:02
-
\$\begingroup\$ @Joao-3 good catch, fixed \$\endgroup\$noodle person– noodle person2024年03月19日 18:04:33 +00:00Commented Mar 19, 2024 at 18:04
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)]
- 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)]
- 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.
```
-
\$\begingroup\$ 167 --> 164 bytes: tio.run/##bYzNisIwFEb38xThgpAbo2gFNQWfpGaR/… \$\endgroup\$squareroot12621– squareroot126212024年10月28日 11:32:45 +00:00Commented Oct 28, 2024 at 11:32
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=' '
Vyxal, 28 bytes
vhøA‹ð*?vḢƛḣ$W;÷Ṙ"+n2εwYfvṘ§
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.
J, 62 bytes
0|.@|:(,~|.)&((u:97+i.26)&([,](,"1(,@{.,:}.)@}.)~' '#~(i.{.)))
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.
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]
Jelly, (削除) 25 (削除ここまで) 23 bytes
ḢO_976x;Ɱ,Ḣ$Øaṭ1Ṛƭ)Ẏz6Ṛ
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_976x;Ɱ,Ḣ$Øaṭ1Ṛƭ)Ẏz6Ṛ - Link: pair of lists of characters, Words
) - for each {Word in Words}:
Ḣ - pop the first character
O_97 - ordinal {of that} minus 97 -> height
6x - 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:
1 - do nothing (when processing the first Word)
Ṛ - reverse (when processing the second Word)
Ẏ - tighten
z6 - transpose with space character as filler
Ṛ - reverse
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)
-
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– Xenox2024年03月19日 21:46:08 +00:00Commented Mar 19, 2024 at 21:46
05AB1E, 21 bytes
εćUć‚AXkúAa}`R«€SζJ»R
Inputs as a pair in reversed order.
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
Aa # 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û1н©¡ ̈®ý1ð'aAûIн©¡ ̈®ýIJ22A1нk-31gÍ0Y322®-32gÍ)ć•ĀçR5•SRΛ