5
\$\begingroup\$

Challenge

Create a 3D word puzzle where the cube's dimensions match the length of the input word. The uppercase word (A-Z) must be validly placed within the cube in one of the fixed orientations: horizontally, vertically, or diagonally. The program should randomly place the hidden word and fill the rest of the cube with random letters.

Input

WORD

Output

Display the cube (n x n x n) layer by layer, where n is the WORD's length.

Examples

UP

UP

AND

AND

DOWN

DOWN

APPLE

APPLE

ORANGE

ORANGE

CODEGOLF (Can you find it?)

N Y R Z O F K G   Y G B V E T P M   O J F K Y O O K   O Z N Q F A R P   M X E T N O I Y   F H C U O F Z A   G V A V O O F B   B V K U O V L F    
W Y L W U H H K   Z M Z X D R K Q   G D D A B I D F   P Y G U I D L I   J Y D O M D Q W   F H B Q Q N B B   T A C F J Q L K   H R Y R Y B Z Q    
L F C D Z B Z W   L E A J O F F J   Z O X Q G A R C   W N N W Y Z S U   S G E V T A C F   K F E O R O N V   K D G Z N W O P   L I W W J L C U    
K L Z Q M A G C   M R Q E F M O I   O K T K T U A U   S E X A Y K C D   N J D V G E S G   X O F P T S F I   H Z B X E X U T   X R Q G V P Q O    
B H F C J P Y A   P I Z G R X N A   A W Z H A Z H V   Q X T E T B Z A   Q A V I Z H G D   E H N J L G G W   V K A O Q U S G   N K M M X R G Z    
B Q K R Y O R I   O J C Q K C P F   F U D R M U J G   E K B F A A C I   K G P O B M N E   M P M B K X X T   V B V N Z O R P   K N Q N J B M D    
M L R C O U C F   A O H U H R E P   M L E T B F R Y   W J S U C Y A N   M X S W E C C X   C U F U V Q U H   J C Z W Y E J S   Z D C U I R F Z    
C H D I M M C W   F W G N I I Z U   C X W Q M C O N   Y O W K X E Z J   U G Y U W Q V V   C N B T A T E Z   W C X Z E O W Z   N S C J P V X X    

3_D

\$\endgroup\$
11
  • \$\begingroup\$ Nice challenge! Instead of displaying, are we allowed to output a list of lists of lists of strings? Also, does "random" here mean "all possible n×n×n cubes should be generated with the same probability" or "all possible n×n×n cubes should have a nonzero probability of being generated" (more info)? Also, when filling the cube with random letters, must we check if any of the added letters also form a valid solution? \$\endgroup\$
    – enzo
    Commented Feb 3 at 16:54
  • 1
    \$\begingroup\$ As far as random, each cubelet should apply a random function to choose an A-Z letter. For example, python has this code: random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ'). \$\endgroup\$
    – vengy
    Commented Feb 3 at 17:00
  • \$\begingroup\$ Can we choose the location, orientation and rotation to always put a word (for example, always put a word on the first layer, vertically, not reversed)? Or it must be randomly selected too? \$\endgroup\$
    – enzo
    Commented Feb 3 at 17:33
  • 2
    \$\begingroup\$ Random word placement seems more interesting as long as it's placed correctly within the cube, either horizontally, vertically, or diagonally. \$\endgroup\$
    – vengy
    Commented Feb 3 at 17:49
  • 1
    \$\begingroup\$ Correct. No need to check if the word occurs multiple times. \$\endgroup\$
    – vengy
    Commented Feb 20 at 22:59

4 Answers 4

3
\$\begingroup\$

Python 3, 226 213 227 222 219 bytes

from random import*
def f(w):
 W=len(w);G=eval('[[[chr(randint(65,90))'+f"for _ in' '*{W}]"*3);l,a,b=map(randrange,(W,W,15))
 for n in range(W):G[[n,l][b&2>0]][[a,n][b!=4]][[a,n,n,W-n-1][b//4]]=w[::b%2or-1][n]
 return G

Try it online!

  • -13 bytes by replacing randint with randrange
  • +14 bytes by implementing the reverse of a word
  • -5 bytes by creating a b variable to store d, o and i, and by using eval
  • -3 bytes by removing the randrange alias, and inlining the r variable

A function that receives a word \$w\$ and returns a 3x3x3 matrix composed of lists.

To see where the word is, change chr(65+g(26)) to chr(97+g(26)).


How does it work?

The generator stores an instance of the random.randrange function.

The range stores the numbers from 0 to until the length of the word, exclusive.

We initialize the Grid to random uppercase letters (chr(65+g(26))).

We initialize three variables with random values:

  • layer: define the index of the layer the word will be written (UP: layer 1, APPLE: layer 2); this variable is ignored if the word is spread across layers
  • axis: define the index of the axis the word will be written (AND: axis 1, DOWN: axis 0, APPLE: axis 0); this variable is ignored if the word is set diagonally
  • b a 4-bits integer, where
    • if the first bit is 0, the word will be put right-to-left (in reverse); otherwise, left-to-right
    • if the second bit is 0, the word will spread across layers (see AND, DOWN and ORANGE test cases); otherwise, it will be contained in a single layer (see UP and APPLE test cases)
    • if the third and fourth bits are 00, the word will be set horizontally (AND and DOWN test cases); if 01, the word will be set vertically (APPLE test case); if 10, the word will be set diagonally-forward (UP and ORANGE test cases); if 11, the word will be set diagonally-backward (see CODEGOLF test case).

Then, for each character of the word, we update the Grid doing some arithmetic based on l, a and b.

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

Charcoal, 56 bytes

W⁼⌊υ⌈υ«≔⁻E³‽⁺²Lθ²υ≔EθEυ⎇‹μ⁰⎇⊕μ⁻⊖Lθλλμυ»EθEθ⭆θ§⁺θ‽α⌕υ⟦κμξ

Try it online! Link is to verbose version of code. Enter the word in lower case if you want to make it obvious where it ended up. Explanation:

W⁼⌊υ⌈υ«

Repeat until a suitable word placement is found.

≔⁻E³‽⁺²Lθ²υ

For each axis, either select a fixed index from 0 to the length of the word, or -1 to spread the word in the forward direction along that axis, or -2 to spread it in the reverse direction (so for example -2, -2, -2 would result in the word written in reverse along the main diagonal).

≔EθEυ⎇‹μ⁰⎇⊕μ⁻⊖Lθλλμυ

Use the randomly selected indices to generate a list of coordinates of each letter of the word.

»EθEθ⭆θ§⁺θ‽α⌕υ⟦κμξ

Output the cube, but selecting the letter from the word instead of a random letter if the current coordinates are from the selected list.

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

JavaScript, 239 bytes

f=(w,W=[...w],r=n=>n*Math.random()|0,d=[0,1,2].map(_=>r(3)-1),o=d.map(x=>[r(L=w.length),L-1][-x]|0),p=[],g=n=>n--?W.map((_,i)=>g(n,p[n]=i)):W.find((_,j)=>!o.some((x,k)=>x+j*d[k]-p[k]))||String.fromCharCode(65+r(26)))=>/1/.test(d)?g(3):f(w)

Try it online!

Creates a 3D array.

It works by choosing a random 3D direction vector \$d\$, where each axis is -1, 0, or 1. (If it gets all 0s try again.) Based on the direction, it chooses a random origin point \$o\$, for each axis \$n\$:

$$ o_n = \begin{cases} L-1 &\text{if }d_n = -1\\ R(0,L) &\text{if }d_n = 0\\ 0 &\text{if }d_n = 1\\ \end{cases} $$

Where \$L\$ is the length of the input word, and \$R(a,b)\$ is a random integer in \$[a, b)\$.

It doesn't guarantee that the word appears only once.

Ungolfed:

f = (w, // the input word
     W = [...w], // split word into array - this'll be handy later
     r = n => n * Math.random() | 0, // a handy random function
     d = [0,1,2].map(_ => r(3) - 1), // pick a random direction
     o = d.map(x => [r(L=w.length), L-1][-x]|0), // pick a random valid starting point
     p = [], // place to store current point
     g = n => // a recursive function to create the grid - taking n = dimension
       n-- // reduce the dimension and check if zero
         ? W.map((_, i) => g(n, p[n] = i)) // if >0 go deeper, recording in p
         : W.find((_, j)=> !o.some((x, k) => x + j*d[k] - p[k])) // if in word, use its letter
               || String.fromCharCode(65 + r(26)) // else a random letter
) => /1/.test(d) // check if direction is valid (not [0,0,0], ie. contains a "1" in string form)
  ? g(2) // valid - create the grid
  : f(w) // invalid - try again :(
\$\endgroup\$
0
\$\begingroup\$

C (gcc), 655 542 446 437 bytes

-105 bytes, thanks to @ceilingcat

To disable the word hint, change w[i]|32 to w[i]|0.

#define r rand()
f(w,s)char*w;{char*u=calloc(s*s,s);int x,y,z,a,b,c,p,i=s/2,l,m,n;if(r%2)for(;i--;)w[i]^=w[s+~i]^=w[i]^=w[s+~i];do for(x=r%s,y=r%s,z=r%s,a=r%3-1,b=r%3-1,c=r%3-1,p=a|b|c,i=0;i<s&&p;p*=l>=0&m>=0&n>=0&l<s&m<s&n<s)l=x+i*a,m=y+i*b,n=z+i++*c;while(!p);for(i=s;i--;)u[((x+i*a)*s+y+i*b)*s+z+i*c]=w[i]|32;for(;y=++i<s*s*s;)u[i]=u[i]?:65+r%26;for(;y<s;y+=puts(""))for(z=0;z<s;z+=printf(" "))for(x=0;x<s;)putchar(u[x++*s*s+y*s+z]);}

Try it online!

\$\endgroup\$
1

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.