Ruby, 272 bytes
Duas novas linhas desnecessárias são adicionadas ao código em ambos os lados da função aninhada g
para melhorar a legibilidade. Estes são excluídos da pontuação. Os caracteres f=
que atribuem a função anônima a uma variável também são excluídos.
O formato de saída é 0
ou 1
por pergunta, em vez do nativo true
e do Ruby false
. Uma nova linha (em vez de um espaço) é usada para separar o booleano e a palavra. Meu entendimento é que essa é uma interpretação aceitável dos requisitos de saída, mas, se não, o impacto na contagem de bytes seria menor.
f=->n,l{c=''
x=[p=6*n,1,-p,-1]
(m=3*p*n).times{|i|c<<(5+i/n%6-i/n/p&6==6?65+rand(26):i%p==p-1?10:46)}
q=m+3*n
puts c
g=->w,i,d{w==''?$r=1:c[i]<?A?g[w,(i+x[d])%q,d^1]:w[0]==c[i]&&4.times{|j|g[w[1..-1],(i+x[j])%q,j^1]}}
l.each{|w|$r=0
m.times{|i|c[i]>?@&&g[w,i,0]}
puts $r,w}}
Resultado
Após cerca de 50 chamadas como esta:
f[4,['PPCG','CODE','GOLF','ANT','CAN','CUBE','WORD','WALK','SPELL']]
Finalmente consegui a seguinte saída com 2 hits. ANT
fica no canto inferior direito, subindo, e AN
é compartilhado por CAN
, com o C
contorno redondo para o canto superior esquerdo.
....KCAAXRHT...........
....ALRZXRKL...........
....NDDLCMCT...........
....ETQZHXQF...........
........FYYUSRZX.......
........CFNPAUVX.......
........ZTJVHZVQ.......
........AUWKGVMC.......
............XWKSDWVZ...
............DPLUVTZF...
............DMFJINRJ...
............ZRXJIAFT...
0
PPCG
0
CODE
0
GOLF
1
ANT
1
CAN
0
CUBE
0
WORD
0
WALK
0
SPELL
Explicação
O desdobramento particular do cubo selecionado foi escolhido em parte por sua facilidade de desenho, mas principalmente por sua facilidade de pesquisa.
Os caracteres que não são do alfabeto (os pontos mais a nova linha no final de cada linha) são uma parte importante do campo em que a formiga pode ser encontrada andando.
A pesquisa é realizada pela função recursiva g
, que está aninhada na função f
. Se a palavra passada for uma sequência vazia, a pesquisa será concluída e $r
definida como 1. Se a formiga estiver em um quadrado de letras correspondente à primeira letra da palavra, a pesquisa continuará nas quatro direções: a função é chamada novamente com a palavra abreviada removendo sua primeira letra. Nesse caso, o parâmetro de direção é ignorado. O movimento é feito chamando recursivamente com o índice de células alterado pelos valores em x.
O resultado da adição é obtido pelo módulo do tamanho da grade mais uma meia linha extra. Isso significa que a linha de baixo passa para o topo e vice-versa, com o deslocamento horizontal correto.
Se a formiga estiver em um quadrado que não seja uma letra, ela deverá zigue-zague em um movimento de escada até encontrar um quadrado de letras. Ela zizag na direção sudeste ou noroeste. Isso é simulado por chamadas recursivas, com o d
parâmetro sendo XOR com 1 a cada vez para acompanhar o movimento dela. Até que ela atinja o próximo quadrado da letra, não há encurtamento da palavra de entrada. Convenientemente, isso pode ser feito pela mesma recursão usada quando estamos pesquisando na área com letras. A diferença é que a recursão tem apenas um ramo quando a formiga está na área de espaço em branco, em oposição a 4 na área da letra.
Código comentado
->n,l{ #n=square size, l=list of words to search
c='' #empty grid
x=[p=6*n,1,-p,-1] #offsets for south, east, north, west. p is also number of characters per line
(m=3*p*n).times{|i| #m=total cells in grid. for each cell
c<<(5+i/n%6-i/n/p&6==6? #apppend to c (according to the formula)
65+rand(26): #either a random letter
i%p==p-1?10:46) #or a "whitespace character" (newline, ASCII 10 or period, ASCII 46)
}
q=m+3*n #offset for vertical wraparound = grid size plus half a row.
puts c #print grid
g=->w,i,d{ #search function. w=word to search for, i=start index in grid, d=direction
w==''? #if length zero, already found,
$r=1: #so set flag to 1. Else
c[i]<?A? #if grid cell is not a letter
g[w,(i+x[d])%q,d^1]: #recursively call from the cell in front, with the direction reflected in NW-SE axis
w[0]==c[i]&& #else if the letter on the grid cell matches the start of the word
4.times{|j| #for each direction (iterate 4 times, each time a different direction is "in front")
g[w[1..-1],(i+x[j])%q,j^1]} #recursively call from the cell in front. Chop first letter off word.
} #Direction parameter is XORed (reflected in NW-SE axis) in case ant hits whitespace and has to zigzag.
l.each{|w| #for each word in the list
$r=0 #set global variable $r to zero to act as a flag
m.times{|i|c[i]>?@&&g[w,i,0]} #call g from all cells in the grid that contain a letter
puts $r,w} #output flag value and word
}