1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

Prolog - manipulação de listas

Discussão em 'Programação' iniciada por OubeLa, 28 de Outubro de 2008. (Respostas: 9; Visualizações: 5999)

  1. OubeLa

    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: 28 de Outubro de 2008
  2. 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
     
  3. Baderous

    Baderous Banido

    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: 28 de Outubro de 2008
  4. OubeLa

    OubeLa Power Member

    Podias explicar o que faz o append, e também, qual a razão de usares um acumulador?

    Cumprimentos
     
  5. Baderous

    Baderous Banido

    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: 28 de Outubro de 2008
  6. OubeLa

    OubeLa Power Member

    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.
     
  7. Baderous

    Baderous Banido

    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.
     
  8. OubeLa

    OubeLa Power Member

    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.
     
  9. Baderous

    Baderous Banido

    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: 30 de Outubro de 2008
  10. OubeLa

    OubeLa Power Member

    Ok, obrigado, já resolvi. O problema era mesmo da verificação estar nesse predicado.
     

Partilhar esta Página