Questa parola è sulla lavagna boggle?


38

introduzione

Dopo una giornata trascorsa a bere e a guardare la coppa del mondo, ti siedi per giocare a boggle amichevole. Gli animi aumentano quando sei accusato di perdere tempo a tutti con parole senza senso che non sono nemmeno sul tabellone! Potresti vedere il doppio, ma sicuramente stai pensando abbastanza bene da scrivere un programma che verificherà che le tue parole siano sulla lavagna.

Il tuo compito

Scrivi un programma, uno script o una funzione che accetta una boggle board e una parola come input e restituisce True se la parola è sulla board e False se la parola non lo è.

L'input avrà la forma di sei \nrighe delimitate. Le prime cinque righe comprenderanno la boggle board 5x5 e conterranno ciascuna cinque lettere maiuscole. La sesta riga conterrà la parola in questione, anche in maiuscolo.

Input di esempio:

AJNES
TNFTR
LSAIL
UDNEX
EQGMM
DAFTER

L'output può essere qualsiasi cosa che significhi inequivocabilmente True o False nel linguaggio di programmazione scelto e aderisca alle convenzioni standard di zero, null e vuoto che significa False.

Output di esempio per l'input sopra:

1

Linee guida I / O

  • L'input può essere letto da stdin e rispondere a stdout.

O

  • L'input può essere un singolo argomento stringa per una funzione e la risposta può essere il valore restituito di quella funzione.

Boggle Rules

  • Una parola è "sul tabellone" se puoi costruirla attraverso un percorso di tessere consecutive, adiacenti, non ripetitive sul tabellone.
  • Una tessera è considerata adiacente alle otto tessere che la circondano (sono consentiti percorsi diagonali). Le tessere sul bordo del tabellone sono adiacenti a sole cinque tessere. Le piastrelle nell'angolo sono adiacenti a solo tre.
  • Le lettere consecutive nella parola devono essere adiacenti, la ilettera th nella parola deve essere adiacente al i-1th e i+1th.
  • Una lettera può apparire in una parola più di una volta, ma non è possibile utilizzare lo stesso quadrato sul tabellone più di una volta per parola.
  • Il sito di boggle online wordsplay.net può essere utile se non hai mai giocato a boggle prima, ma vuoi avere un'idea di queste regole.

A differenza del normale boggle:

  • NON devi preoccuparti che la parola sia una parola inglese valida.
  • Non ci saranno Qupiastrelle singole.
  • La parola in questione può avere una lunghezza> 0

Esempio

Nel consiglio di

AJNES
TNFTR
LSAIL
UDNEX
EQGMM

Queste parole dovrebbero restituire True: FATE, DATING, STANDS, LIFTS.

Queste parole dovrebbero restituire False: SADDEN, SULTANS, EXIST, SUEDE, QUEST

Questa è una sfida di code-golf, quindi vince il codice più corto!


La tavola si avvolge? Non ricordo
Claudiu,

No, non si chiude, ho aggiornato il chiarimento sull'adiacenza per riflettere questo.
turbulencetoo

Il percorso può incrociarsi (in diagonale)?
Martin Ender,

@ m.buettner Yep
turbulencetoo

Boggle è normalmente una scheda 4x4.
mbomb007,

Risposte:


11

GolfScript, 74 caratteri

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

L'ingresso deve essere dato su STDIN. Stampa il numero di percorsi validi sulla scheda, ovvero 0per nessuno e un numero positivo (vero) per il resto.

Puoi testare l'esempio online .

Codice con alcuni commenti:

:^              # 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

12

Javascript (E6) 137 160 175 190

Meno di 2 * Golfscript. Vittoria morale ...

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)

Modifica la riorganizzazione del codice golfizzato. Ancora e ancora

Ungolfed Ultima versione, un po 'difficile da seguire

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 Prima versione, dovrebbe essere più chiara

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")

Test

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

Produzione:

[["DAFTER", true], ["STANDS", true], ["LIFTS", true], ["FATE", true], ["DATING", true], 
["SADDEN", false], ["SULTANS", false], ["EXIST", false], ["SUEDE", false], ["QUEST", false]]

1
qualche piccola ottimizzazione: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

Dovrebbe essere w = a.pop()(golf) o w = b.pop()(non golf, linea 2)? (probabilmente quest'ultimo, credo)
hlt

@androyd Ho lasciato il vecchio codice ungolfed per chiarezza, dopo la riorganizzazione. Ma non è sincronizzato al 100%. Cercherò di chiarire
edc65 il

Mio male, non ti ho visto cambiato in a=a.pop()invece di 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))

La sostituzione ... (b[i]==w[0])*any ...con ... b[i]==w[0]and any ...offre prestazioni molto migliori al costo di 2 caratteri.


1
Puoi radere gli spazi quando sono tra numeri e comandi; 0<=i<25and
Seequ,

3

J - 75 caratteri

Eugh, questo sembra cattivo. E nemmeno legare con Golfscript! Questa è una funzione che prende una stringa come unico argomento. Puoi usare qualsiasi delimitatore di un carattere purché si trovi alla fine di ogni riga, incluso l'ultimo.

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

Segue una spiegazione. Si noti che la funzione può essere suddivisa in 5 parti distinte di livello superiore, ognuna separata da @, quindi tratteremo ciascuna di quelle parti separatamente, da destra a sinistra.

  • (<;._2)- Questo divide le linee sui caratteri di nuova riga / separatore. Usa il carattere alla fine della stringa come carattere su cui dividere. Mettiamo tutto nelle scatole ( <) perché se non lo facciamo otteniamo alcuni problemi di riempimento quando J ci restituisce il risultato.

  • (((<@#:i.)5 5)<@#~&,"2{:=/&:>}:) - Per ogni lettera nella parola da controllare, crea un elenco di indici nella scheda Boggle dove puoi trovare quella lettera.

    • {:è l'ultimo pezzo diviso (la parola da controllare) ed }:è tutto tranne l'ultimo (la tavola Boggle).

    • &:>apre le scatole che abbiamo creato in precedenza, con l'utile sottoprodotto di trasformarsi }:in una matrice 2D di caratteri. =/quindi crea una copia di questa scheda Boggle per ogni lettera della parola e trasforma le posizioni in booleani a seconda che la lettera nella scheda corrisponda a quella lettera nella parola.

    • ((<@#:i.)5 5)è un modo breve per esprimere un array di indici 5x5. x#:yviene convertito yin un array della xrappresentazione di base . (Beh, quasi. La verità è più complessa, ma funziona per i nostri scopi.)

    • <@#~&,"2- Per ogni matrice booleana risultante di ogni lettera, raccogli tutti gli indici corrispondentemente veri insieme. "2fa funzionare tutto sui risultati giusti, #~&,fa la selezione e <@raccoglie ogni risultato in una scatola per prepararsi al passaggio successivo.

  • {- Questo verbo, usato monadicamente, si chiama Catalog, e prende come argomento un elenco di caselle. Combina l'interno di ogni scatola in ogni modo possibile. Ad esempio, un catalogo su alcune scatole contenenti le stringhe "AB" e "abc" darebbe i risultati "Aa", "Ab", "Ac", "Ba", "Bb", "Bc".

    L'esecuzione di questo nel nostro elenco di elenchi di indici in scatola rende ogni possibile combinazione di indici. Questo può essere un grande set se la parola è lunga e ci sono molte lettere ripetute, ma anche vuota se una qualsiasi lettera non è sulla lavagna. Notiamo anche che riutilizziamo le tessere in alcuni di questi percorsi: lo spiegheremo in seguito.

  • ([:*/"1^:2(2(=*)@-/\>@~.)S:1) - Qui controlliamo ogni percorso per vedere se è valido.

    • (...)S:1applica il (...)a ciascun percorso e raccoglie i risultati in un elenco semplice. Questo è cruciale perché il risultato di {è un array multidimensionale e non ci interessa la struttura di tale array, ma solo il suo contenuto in ogni riquadro.

    • 2(=*)@-/\>dà un 1 se ogni coordinata di ciascun indice è al massimo una a partire da quella che lo segue, e 0 altrimenti. Il 2e il /\sono responsabili di farlo in coppia.

    • */"1^:2AND logici tutti insieme alla fine. La [:parte è una cosa strutturale in J, non ti preoccupare.

    • L'aggiunta @~.a >è in realtà un modo intelligente per escludere percorsi con voci ripetute. ~.accetta gli elementi univoci di un elenco, quindi l'elenco viene abbreviato se si interseca automaticamente e gli elenchi più brevi vengono automaticamente riempiti con 0 quando vengono messi insieme, come il modo in cui i risultati vengono combinati quando escono S:. Questo è in definitiva più breve dell'esclusione esplicita di percorsi autointersecanti.

  • +/- Infine, aggiungiamo semplicemente tutto insieme alla fine. Il risultato è il numero di percorsi validi che compongono la parola sulla lavagna, con 0 che significa nessun percorso, ovvero questa parola non è sulla lavagna. Al costo di un carattere, possiamo invece scrivere +./(OR-logico tutto insieme), che fornirà esplicitamente un valore booleano 1 o 0.

Ecco alcune esecuzioni. È possibile ottenere l'interprete J a jsoftware.com o provare online su 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

1
+1 per i dettagli. Mi piacerebbe vedere più risposte in questo modo!
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).

Ho pensato che Prolog potesse essere un buon linguaggio per questo, con il supporto integrato per il backtracking, ma immagino che sia più handicappato avendo bisogno di una variabile per quasi ogni valore calcolato.

Testato con GNU Prolog; dovrebbe essere conforme a 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, _, []).
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.