Prolog - manipulação de listas

OubeLa

Power Member
Estou aqui com um problema.

Código:
substituir(0, _, _).
substituir(L, [C|R], Novo_tab) :- L > 0, L1 is L-1, substituir(L1, R, [C | Novo_tab]).
L - numero de elementos a copiar
[C | R] - lista inicial, em que C é a cabeça da lista e R é o resto
Novo_tab - lista final que deve ser devolvida pelo programa

O objectivo é que o programa percorra a lista inicial (2ª argumento) enquanto L vezes e que copie a cabeça da lista para Novo_tab.

Isto:
?- substituir(3, [1, 2, 4, 3], Novo_tab).

Deveria dar
Novo_tab = [1, 2, 4]

Mas dá

- substituir(3, [1, 2, 4, 3], Novo_tab).
true.


Prolog ainda não é o meu forte, portanto precisava da vossa ajuda :P


PS: não liguem ao nome "substituir" visto que isso é o que quero fazer a seguir.
 
Última edição:
dá-me o teu messenger que eu tento ajudar-te. Deves estar a fazer o trabalho de prolog. ainda hoje ajudei um amigo meu. Acho que o Teu problema é a primeira declaração mas não tenho a certeza.... Manda PM ou assim... tb te vou mandar uma com o meu.

Abraço
 
Usei um acumulador:

Código:
copia(N,L,R):-copia(N,L,[],R).
copia(0,_,Ac,Ac):-!.
copia(N,[H|T],Ac,R):-N>0,!,N1 is N-1,append(Ac,[H],S),copia(N1,T,S,R).
 
Última edição:
append(+File)
Similar to tell/1, but positions the file pointer at the end of
File rather than truncating an existing file. The pipe construct
is not accepted by this predicate.

append(?List1, ?List2, ?List3)
Succeeds when List3 unifies with the concatenation of List1 and
List2. The predicate can be used with any instantiation pattern
(even three variables).
Basicamente: append(L1,L2,R), representa a concatenação de L1 com L2, guardando o resultado em R.

Usei um acumulador porque foi a solução a que cheguei primeiro. Também podias não usar:

Código:
cop(0,_,[]):-!.
cop(N,[H|T],[H|R]):-N>0,!,N1 is N-1,cop(N1,T,R).
Basicamente, quando queres copiar n elementos (n>0), partes do princípio que o 1º elemento é logo copiado, logo coloca-lo logo na cabeça da lista resultante, no início da declaração da função. Depois basta invocar recursivamente.

Ou usando os predicados length e append:

Código:
cp(0,_,_):-!.
cp(N,L,R):-N>0,!,append(R,_,L),length(R,N).
Aqui usas o append não para concatenar, mas para "desdobrar", ou seja, podes obter uma visão da lista desdobrada a partir de qualquer ponto. Usei como referência para partir a lista inicial a lista R (resultante) garantindo que esta tem um comprimento igual ao nº de elementos a copiar. Se eu quiser copiar 3 elementos da lista [1,2,4,5], ele separa em ([1,2,4],_,[1,2,4,5]).

Se quiseres ver como funciona, usa o comando trace.
 
Última edição:
Obrigado aos dois.

Já consegui fazer isso, e até já está a substituir o elemento pela Peca (peça :P) mas agora tenho outro problema:

Código:
substituir(L, Peca, Xs, Ys) :- substituir(L, Peca, Xs, [], Ys).
substituir(L, Peca, [X| Xs], Acc, Ys ) :- L1 is L-1, substituir(L1, Peca, Xs, [X|Acc], Ys ).
substituir(1, Peca, [_|Xs], Acc, Ys  ) :- substituir(0, Peca, Xs, [Peca|Acc], Ys).
substituir(0, Peca, [X|Xs], Acc, Ys ) :- substituir(0, Peca, Xs, [X|Acc], Ys).
substituir(0, _, [], Ys, Ys) :- !.
Ao chamar

?- substituir(3, 10, [1, 2, 4, 3, 5, 6], Novo_tab).
Novo_tab = [6, 5, 3, 4, 2, 1] ;
Novo_tab = [6, 5, 3, 10, 2, 1] ;
false.

Ele dá varias soluções. Só queria mesmo aquela segunda solução.

Nota: a lista está ao contrário mas isso eu resolvo.
 
Resolvi da seguinte maneira:

Código:
substituir(L,Peca,Xs,Ys):-substituir(L,Peca,Xs,[],Ys).
substituir(0,_,Xs,Acc,Ys):-reverse(Xs,Xs1),append(Xs1,Acc,Ys),!.
substituir(1,Peca,[_|Xs],Acc,Ys):-substituir(0,Peca,Xs,[Peca|Acc],Ys),!.
substituir(L,Peca,[X|Xs],Acc,Ys):-L1 is L-1,substituir(L1,Peca,Xs,[X|Acc],Ys).

Ele vai percorrendo a lista até encontrar o índice desejado e faz a substituição como tu estavas a fazer. Apenas coloquei um cut na cláusula que executa a substituição, pois a partir daí, não é necessário andar a percorrer mais a lista. Assim, para L=0, apenas fiz o reverse do resto da lista e juntei ao que já tinha sido processado.
 
Tenho mais uma dúvida, agora sobre input.

Código:
init :- abolish(jogador/2), tipo_jogo, estado_inicial(Tab), 
visualiza(Tab), nl, escolher_jogada(1, L, C), jogada(1, L, C, Tab, Resultado, 1), visualiza(Resultado), nl.
Depois tenho, no escolher_jogada o seguinte

Código:
escolher_jogada(Jogador, L, C) :- 
write('Jogador: '), jogador(Jogador), nl, write('Linha: '), repeat,
                    get_code(L), L>=49, L=<56, nl, write('Coluna: '), repeat,
                    get_code(C), C>=49, C=<56, nl.
Ele entra em loop ao pedir a coluna, e não estou a entender porquê..A ideia é passar o L e o C de escolher:jogada para jogada.
 
Penso que tem a ver com os testes que estás a fazer ao input (L>=49 e L<=56 e o C). Faz um predicado validaL(L) e validaC(C), onde faças esse teste. Ou então é um dos predicados que invocas que está a causar o erro. O repeat não precisa de estar a ser repetido 2 vezes. Basta colocá-lo como primeira instrução do predicado "escolher_jogada".
 
Última edição:
Back
Topo