Esta palavra está no quadro de boggle?

38

Introdução

Depois de um dia bebendo e assistindo a copa do mundo, você se senta para jogar amistoso. O temperamento aumenta quando você é acusado de desperdiçar o tempo de todos com palavras sem sentido que nem estão no quadro! Você pode estar vendo o dobro, mas certamente está pensando o suficiente para escrever um programa que verifique se suas palavras estão no quadro.

Sua tarefa

Escreva um programa, script ou função que use uma placa de boggle e uma palavra como entrada e retorne True se a palavra estiver no quadro e False se a palavra não estiver.

A entrada será na forma de seis \nlinhas delimitadas. As cinco primeiras linhas compreenderão o tabuleiro 5x5 e cada uma conterá cinco letras maiúsculas. A sexta linha conterá a palavra em questão, também em letras maiúsculas.

Entrada de amostra:

AJNES
TNFTR
LSAIL
UDNEX
EQGMM
DAFTER

A saída pode ser qualquer coisa que signifique inequivocamente Verdadeiro ou Falso na sua linguagem de programação preferida e adira às convenções padrão de zero, nulo e vazio, significando Falso.

Saída de amostra para a entrada acima:

1

Diretrizes de E / S

  • A entrada pode ser lida em stdin e responder a saída em stdout.

Ou

  • A entrada pode ser um argumento de cadeia única para uma função e resposta é o valor de retorno dessa função.

Regras do Boggle

  • Uma palavra está 'no quadro' se você puder construí-la por um caminho de blocos consecutivos, adjacentes e não repetitivos no quadro.
  • Um bloco é considerado adjacente aos oito blocos que o cercam (caminhos diagonais são permitidos). As peças na borda do tabuleiro são adjacentes a apenas cinco peças. As telhas no canto são adjacentes a apenas três.
  • As letras consecutivas na palavra devem ser adjacentes, a ith letra na palavra deve ser adjacente à i-1th e i+1th.
  • Uma letra pode aparecer em uma palavra mais de uma vez, mas você não pode usar o mesmo quadrado no painel de boggle mais de uma vez por palavra.
  • O site online de boggle wordsplay.net pode ser útil se você nunca jogou boggle antes, mas deseja ter uma idéia dessas regras.

Ao contrário do boggle normal:

  • Você NÃO precisa se preocupar com o fato de a palavra ser uma palavra válida em inglês.
  • Não haverá nenhum Qubloco único.
  • A palavra em questão pode ter qualquer tamanho> 0

Exemplo

No conselho de

AJNES
TNFTR
LSAIL
UDNEX
EQGMM

Essas palavras devem retornar True: FATE, DATING, STANDS, LIFTS.

Estas palavras devem retornar Falso: SADDEN, SULTANS, EXIST, SUEDE, QUEST

Este é um desafio do código-golfe, pelo que o código mais curto vence!

turbulencetoo
fonte
O quadro se enrola? Não consigo lembrar
Claudiu
Não, não quebra, atualizei o esclarecimento sobre adjacência para refletir isso.
turbulencetoo
O caminho pode cruzar-se (na diagonal)?
Martin Ender
@ m.buettner Yep
turbulencetoo
Boggle é normalmente uma placa 4x4.
mbomb007

Respostas:

11

GolfScript, 74 caracteres

:^n%5>)]){{^@==}+29,\,{{+}+1$/}%\;}/{:s$..&=[s{.@-\}*;]1567`{7&.~)}%-!&},,

A entrada deve ser fornecida no STDIN. Imprime o número de caminhos válidos no quadro, ou seja, 0para nenhum e um número positivo (verdadeiro).

Você pode testar o exemplo online .

Código com alguns comentários:

:^              # assign the input to variable ^
n%              # split at newlines
5>              # truncate array such that [WORD] remains
)])             # prepares [[]] and WORD on the stack

# the following loop generates all possible paths (valid and invalid ones)
# by looking up all index combinations which yield the correct word
{               # loop over all characters
  {^@==}+29,\,  # get all indices of current character in the board
  {{+}+1$/}%\;  # append any index to all lists in the result set
}/              # end loop

# filter the results list for valid paths
{               # {...}, -> apply filter
  :s            # save path to variable s
  $..&=         # check if all numbers in path are unique
  [s{.@-\}*;]   # calculate differences along the path
  1567`{7&.~)}% # generate the array [1 -1 5 -5 6 -6 7 -7] of valid
                # differences
  -!            # check if all differences were valid
  &             # are both conditions fulfilled?
},              # end of filter block

,               # count the number of remaining paths
Howard
fonte
12

Javascript (E6) 137 160 175 190

Menos de 2 * Golfscript. Vitória moral ...

F=a=>[...a].some((e,p,b)=>(Q=(p,n)=>p>29||b[p]!=b[n]||(b.r|=!b[++n])||(b[p]=b[n+~[1,5,6,7].map(q=>Q(p+q,n)|Q(p-q,n),b[p]=0)]))(p,30)&b.r)

Editar reorganização do código de golfe. De novo e de novo

Ungolfed Last version, um pouco complicado de seguir

F = a => 
  [...a] // input string to array, 30 chars of board then the target word
  .some ( // use some to scan the board, return true when found
      (e,p,b)=> // params to callback: element, position, complete array 
      (         // NB array b has no .r property, so use it for return value (it's undefined at start) 
        Q = (p,n) =>         // Scan function, p=position in board, n=nth char of target word
          p > 29 ||          // Chaek if going outside the board to the target word
          b[p] != b[n] ||    // if invalid char at current position, return
          (b.r |= !b[++n]) ||  // if at end of target, set r to 1 and return (also increment n )
          (                  // else... (NB next tree lines are coalesced in golfed code)
            b[p] = 0,        // remove current char (to avoid reusing) 
            [1,5,6,7].map( q => Q(p+q,n)|Q(p-q,n)), // recursive call for + - 1,5,6,7
            b[p] = b[n-1]    // put current char into array again 
          )
      )(p,30) & b.r // initial position 0 in target word is 30 in the array
  ) 

Ungolfed First version, deve ser mais clara

F = a => (
  b = a.split('\n'),
  w = b.pop(),
  r = 0,
  Q = (p, n) => 
    (r |= !w[n]) || 
    (
      b[p] = 0,
      [1,5,6,7,-1,-5,-6,-7].map( q => b[q+=p]==w[n] && Q(q,n+1)),
      b[p] = w[n-1]
    ),
  b = [...b+''],
  b.map((e, p) => e==w[0] && Q(p,1)),
  r
)

Uso

F("AJNES\nTNFTR\nLSAIL\nUDNEX\nEQGMM\nLIFTS\nDAFTER")

Teste

['DAFTER', 'STANDS', 'LIFTS', 'FATE', 'DATING' ,
 'SADDEN','SULTANS', 'EXIST', 'SUEDE', 'QUEST']
.map(w => [w, F("AJNES\nTNFTR\nLSAIL\nUDNEX\nEQGMM\n" +w)])

Saída:

[["DAFTER", true], ["STANDS", true], ["LIFTS", true], ["FATE", true], ["DATING", true], 
["SADDEN", false], ["SULTANS", false], ["EXIST", false], ["SUEDE", false], ["QUEST", false]]
edc65
fonte
1
alguma otimização menor:F=a=>(b=a.split('\n'),w=b.pop(Q=(p,n)=>((R|=!w[n])||(b[p]=0)||[1,5,6,7,-1,-5,-6,-7].map(q=>b[q+=p]==w[n]&&Q(q,n+1,b[q]=w[n])))),[Q(~~p,1)for(p in b=[...b.join(R=0)])if(b[p]==w[0])],R)
nderscore
É suposto ser w = a.pop()(golfe) ou w = b.pop()(sem golfe, linha 2)? (provavelmente o último, eu acho)
hlt
@androyd Deixei o código não-antigo para maior clareza, após a reorganização. Mas não é 100% sincronizado. Vou tentar esclarecer
edc65
My bad, não vi você mudou para a=a.pop(), em vez de b=a.pop()...
hlt
4

Python, 207 204 203

g=raw_input
r=range
b=''.join(g()for _ in r(5))
w=g()
s=lambda b,w,i:0<=i<25and(not w or(b[i]==w[0])*any(s(b[:i]+'_'+b[i+1:],w[1:],i+j+k*5-6)for j in r(3)for k in r(3)))
print any(s(b,w,i)for i in r(25))

Substituir ... (b[i]==w[0])*any ...por ... b[i]==w[0]and any ...fornece um desempenho muito melhor ao custo de 2 caracteres.

caixa de papelão
fonte
1
Você pode cortar espaços quando estiverem entre números e comandos; 0<=i<25and
see
3

J - 75 char

Eugh, este parece desagradável. E nem mesmo amarrar com o Golfscript! Esta é uma função que utiliza uma string como seu único argumento. Você pode usar qualquer delimitador de um caractere, desde que seja encontrado no final de cada linha, incluindo a última.

+/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2)

Segue uma explicação. Observe que a função pode ser dividida em 5 partes distintas de nível superior, cada uma separada por @, portanto trataremos cada uma dessas partes separadamente, da direita para a esquerda.

  • (<;._2)- Isso divide as linhas nos caracteres de novas linhas / separadores. Ele usa o caractere no final da string como o caractere no qual dividir. Colocamos tudo em boxes ( <) porque, se não o fizermos, temos alguns problemas de preenchimento quando J nos devolve o resultado.

  • (((<@#:i.)5 5)<@#~&,"2{:=/&:>}:) - Para cada letra da palavra a ser verificada, crie uma lista de índices no quadro do Boggle, onde é possível encontrar essa letra.

    • {:é a última peça dividida (a palavra a ser conferida) e }:é tudo, menos a última (o quadro Boggle).

    • &:>abre as caixas que criamos anteriormente, com o subproduto útil de se transformar }:em uma matriz de caracteres 2D. =/em seguida, faz uma cópia desse quadro Boggle para cada letra da palavra e transforma as posições em booleanos, dependendo se a letra no quadro corresponde à letra da palavra.

    • ((<@#:i.)5 5)é uma maneira curta de expressar uma matriz de índices 5x5. x#:yé convertido yem uma matriz da xrepresentação base . (Bem, quase. A verdade é mais complexa, mas isso funciona para nossos propósitos.)

    • <@#~&,"2- Para a matriz booleana resultante de cada letra, colete todos os índices correspondentes correspondentes juntos. "2faz tudo funcionar com os resultados certos, #~&,faz a seleção e <@coleta cada resultado em uma caixa para se preparar para a próxima etapa.

  • {- Este verbo, usado monadicamente, é chamado de catálogo e recebe uma lista de caixas como argumento. Combina o interior de cada caixa de todas as formas possíveis. Assim, por exemplo, um catálogo em algumas caixas contendo as cadeias "AB" e "abc" forneceria os resultados "Aa", "Ab", "Ac", "Ba", "Bb", "Bc".

    Executar isso em nossa lista de listas de índices em caixas faz todas as combinações possíveis de índices. Pode ser um grande conjunto se a palavra for longa e houver muitas letras repetidas, mas também vazia se alguma letra não estiver no quadro. Também observamos que reutilizamos blocos em alguns desses caminhos: explicaremos isso mais tarde.

  • ([:*/"1^:2(2(=*)@-/\>@~.)S:1) - Aqui verificamos cada caminho para ver se é válido.

    • (...)S:1aplica o (...)a cada caminho e coleta os resultados em uma lista simples. Isso é crucial porque o resultado de {é uma matriz multidimensional e não nos importamos com a estrutura dessa matriz, apenas com o conteúdo de cada caixa.

    • 2(=*)@-/\>fornece 1 se cada coordenada de cada índice estiver no máximo uma distante da que o segue e 0 caso contrário. O 2e o /\são responsáveis ​​por fazer isso em pares.

    • */"1^:2ANDs lógicos todos juntos no final. A [:parte é estrutural em J, não se preocupe.

    • Adicionar @~.ao >é realmente uma maneira inteligente de excluir caminhos com entradas repetidas. ~.usa os itens exclusivos de uma lista, para que a lista seja encurtada se ela se cruzar automaticamente, e as listas mais curtas serão preenchidas automaticamente com 0s quando reunidas, como a maneira como os resultados são combinados à medida que saem S:. Em última análise, isso é mais curto do que excluir explicitamente os caminhos de interseção automática.

  • +/- Finalmente, simplesmente adicionamos tudo no final. O resultado é o número de caminhos válidos que compõem a palavra no quadro, com 0 significando nenhum caminho, ou seja, essa palavra não está no quadro. Pelo custo de um caracter, podemos escrever +./(OR lógico - juntos), o que explicitamente fornecerá 1 ou 0 booleano.

Aqui estão alguns exemplos de execuções. Você pode obter o intérprete J em jsoftware.com ou experimentá-lo on-line em tryj.tk .

   NB. the  0 : 0 ... )  thing is how you do multiline strings in J
   +/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2) 0 : 0
AJNES
TNFTR
LSAIL
UDNEX
EQGMM
DAFTER
)
1
   b =: +/@([:*/"1^:2(2(=*)@-/\>@~.)S:1)@{@(((<@#:i.)5 5)<@#~&,"2{:=/&:>}:)@(<;._2)
   b 'AJNES TNFTR LSAIL UDNEX EQGMM FATE '    NB. any separator will do
1
   b 'AJNES TNFTR LSAIL UDNEX EQGMM SADDEN '  NB. not on the board
0
   b 'AJNES TNFTR LSAIL UDNEX EQGMM SANDS '   NB. self-intersecting path
0
   b 'AJNES TNFTR LSAIL UDNEX EQGMM MEND '    NB. multiple paths
2
algoritmshark
fonte
1
+1 para os detalhes. Eu gostaria de ver mais respostas como essa!
edc65
2

Prolog - 315

r(L):-get_char(C),(C='\n',!,L=[];r(T),L=[C|T]).
b(0,[]):-!.
b(N,[R|T]):-M is N-1,r(R),b(M,T).
d(-1). d(0). d(1).
d([A,B],[C,D]):-d(X),C is A+X,d(Y),D is B+Y.
f([L|W],B,P,U):-P=[X,Y],nth(Y,B,R),nth(X,R,L),\+member(P,U),(W=[];d(P,Q),f(W,B,Q,[P|U])).
m:-b(5,B),r(W),f(W,B,_,[]),write(t);write(f).
:-initialization(m).

Eu pensei que o Prolog poderia ser uma boa linguagem para este, com o suporte integrado de retorno, mas acho que é mais prejudicial ao precisar de uma variável para quase todos os valores calculados.

Testado com GNU Prolog; deve estar em conformidade com o ISO Prolog.

Ungolfed:

get_line(Line) :-
    get_char(C),
    (   C='\n', !, Line=[]
    ;   get_line(Tail), Line=[C|Tail]
    ).

% The cut prevents recursion to help_get_board(-1, MoreRows)
% (and golfs one character shorter than putting N>0 in the second rule).
help_get_board(0, []) :- !.
help_get_board(N, [Row|Tail]) :-
    M is N-1, get_line(Row), help_get_board(M, Tail).

% The golfed version doesn't define an equivalent to get_board/1.
% help_get_board(5,Board) is used directly instead.
get_board(Board) :- help_get_board(5,Board).

small(-1). small(0). small(1).
step([X1,Y1],[X2,Y2]) :-
    small(DX), X2 is X1+DX,
    small(DY), Y2 is Y1+DY.

% The golfed version doesn't define an equivalent to letter_at/3.
% See find_word/4.
letter_at([X,Y], Letter, Board) :-
    nth(Y, Board, Row),
    nth(X, Row, Letter).

find_word([Letter|Word], Board, Pos1, Used) :-
%    letter_at(Pos1, Letter, Board),  % "inlined" to next three lines:
    ( Pos1 = [X,Y],
      nth(Y, Board, Row),
      nth(X, Row, Letter) ),
    \+member(Pos1, Used),
    (   Word=[]
    ;
        step(Pos1, Pos2),
        find_word(Word, Board, Pos2, [Pos1|Used])
    ).

main :-
    get_board(Board),
    get_line(Word),
    % Begin at any position. Initially no positions are "Used".
    find_word(Word, Board, _, []).
aschepler
fonte