2010-07-24 14 views
5

Data una matrice di lettere nxn e un elenco di parole, il programma dovrebbe trovare tutti gli aspetti delle parole nella matrice e la loro posizione.Prolog - trova le parole nella matrice

Possono apparire su-giù, a destra-sinistra e in diagonale (su tutte le 8 direzioni). Una parola può apparire un numero qualsiasi di volte (compreso lo zero) e possono sovrapporsi (come le parole bad e adult) e possono anche essere un sottoinsieme di un altro (come le parole bad e ad).

+1

Non mi preoccuperei della cosa del "mio amico". La tua reputazione SO parla da sola che hai fatto molti contributi qui. – Greg

+0

@Greg Harman hai praticamente reso la mia giornata, grazie! –

risposta

2

EDIT Ecco un codice completo (trova anche le parole in diagonale). Uno svantaggio: le parole delle diagonali principali si trovano due volte.

% word(X) iff X is a word 
word("foo"). 
word("bar"). 
word("baz"). 

% prefix(?A, +B) iff A is a prefix of B 
prefix([], _). 
prefix([A|B], [A|C]) :- prefix(B, C). 

% sublist(?A, +B) iff A is a sublist of B 
sublist(A, B) :- prefix(A, B). 
sublist(A, [_|B]) :- sublist(A, B). 

% reversed(?A, +B) iff A is reversed B 
reversed(A, B) :- reversed(B, [], A). 
reversed([A|B], C, D) :- reversed(B, [A|C], D). 
reversed([], A, A). 

% rowsreversed(?A, +B) iff matrix A is matrix B with reversed rows 
rowsreversed([A|B], [C|D]) :- reversed(A, C), rowsreversed(B, D). 
rowsreversed([], []). 

% transposed(+A, ?B) iff matrix B is transposed matrix A 
transposed(A, B) :- transposed(A, [], B). 
transposed(M, X, X) :- empty(M), !. 
transposed(M, A, X) :- columns(M, Hs, Ts), transposed(Ts, [Hs|A], X). 

% empty(+A) iff A is empty list or a list of empty lists 
empty([[]|A]) :- empty(A). 
empty([]). 

% columns(+M, ?Hs, ?Ts) iff Hs is the first column 
% of matrix M and Ts is the rest of matrix M 
columns([[Rh|Rt]|Rs], [Rh|Hs], [Rt|Ts]) :- columns(Rs, Hs, Ts). 
columns([[]], [], []). 
columns([], [], []). 

% inmatrix(+M, ?W) iff word W is in the matrix M 
inmatrix(M, W) :- inrows(M, W). 
inmatrix(M, W) :- incolumns(M, W). 
inmatrix(M, W) :- inleftdiagonals(M, W). 
inmatrix(M, W) :- inrightdiagonals(M, W). 

% inrows(+M, ?W) iff W or reversed W is in a row of M 
inrows([R|_], W) :- word(W), sublist(W, R). 
inrows([R|_], W) :- word(W), reversed(V, W), sublist(V, R). 
inrows([_|Rs], W) :- inrows(Rs, W). 

% incolumns(+M, ?W) iff W or reversed W is in a column of M 
incolumns(M, W) :- transposed(M, N), inrows(N, W). 

% inleftdiagonals(+M, ?W) iff W or reversed W is in a left diagonal of M 
inleftdiagonals(M, W) :- inupperleftdiagonals(M, W). 
inleftdiagonals(M, W) :- transposed(M, N), inupperleftdiagonals(N, W). 

% inupperleftdiagonals(+M, ?W) iff W or reversed W is in an upper left diagonal of M 
inupperleftdiagonals(M, W) :- upperdiags(M, N), inrows(N, W). 

% upperdiags(+M, ?X) iff X is a list of upper diagonals of matrix M 
upperdiags(M, X) :- upperdiags(M, [], Y), reversed(Z, Y), transposed(Z, X). 
upperdiags([R|Rs], A, X) :- columns(Rs, _, T), upperdiags(T, [R|A], X). 
upperdiags([], X, X). 

% inrightdiagonals(+M, ?W) iff W or reversed W is in a right diagonal of M 
inrightdiagonals(M, W) :- rowsreversed(N, M), inleftdiagonals(N, W). 
+0

Ci scusiamo per l'ordine incoerente dei parametri in e out. È tardi e sono sicuro che farò dei listkes se tento di scambiarli adesso. – Bolo

2

Ecco una soluzione parziale per retta orizzontale e verticale e ricerca inversa:

count_hits(Word, Matrix, Result):- 
     atom_chars(Word, Chars), 
     reverse(Chars, C2), 
     transpose_matrix(Matrix, M2), 
     findall(1, find_chars_in_matrix(Chars,Matrix), A), 
     findall(1, find_chars_in_matrix(Chars,M2), B), 
     findall(1, find_chars_in_matrix(C2,Matrix), C), 
     findall(1, find_chars_in_matrix(C2,M2), D), 
     length(A, X1), 
     length(B, X2), 
     length(C, X3), 
     length(D, X4), 
     Result is X1 + X2 + X3 + X4. 

transpose_matrix([],[]). 
transpose_matrix([[ULCorner|Header]|Body], [[ULCorner|NewHeader]|NewBody]) :- 
     collect_heads_and_tails(Body, NewHeader, Kernel), 
     collect_heads_and_tails(NewBody, Header, X2), 
     transpose_matrix(Kernel, X2). 

collect_heads_and_tails([], [], []). 
collect_heads_and_tails([[H|T]|TT], [H|X], [T|Y]):-collect_heads_and_tails(TT, X, Y). 

find_chars_in_matrix(Chars, [H|_]):- 
     sublist(Chars, H). 

find_chars_in_matrix(Chars, [_|T]):- 
     find_chars_in_matrix(Chars, T). 

sublist(L, [_|T]) :- sublist(L, T). 
sublist(A, B) :- prefix(A, B). 

prefix([H|T], [H|T2]) :- prefix(T, T2). 
prefix([], _). 


% test data 
matrix([[e,t,r,e], 
     [r,r,t,r], 
     [t,r,t,t], 
     [e,e,t,e]]). 
go :- matrix(M), count_hits(etre, M, X), write(X). 
:-go. 

Due carenze: (a) parole palindromi si trovano due volte, e una sola lettera parole si trovano quattro volte - matematicamente giustificabile, ma probabilmente indesiderato dal punto di vista del buon senso. (b) le corrispondenze diagonali non vengono trovate affatto, per questo è necessaria una ricorsione maggiormente coinvolta con almeno un argomento di conteggio aggiuntivo.

Full disclosure: transpose_matrix/2 è stato adattato dalla bella risposta alla domanda this. È incredibile, la ricchezza di codice che lo stackoverflow si è accumulato in soli due anni ...

Problemi correlati