0
votes

I am trying to convert a simple Python program to Prolog.

I have reached the move() function, and I'm stuck trying to do a basic list operation.

Here's move() in Python:

def move(kd,fot) :
   k,d=kd
   f,o,t=fot
   if d[f]==1 and d[o]==1 and d[t]==0 :
     c=list(d)
     c[f]=0 # moved away
     c[o]=0 # remove jumped over
     c[t]=1 # landing here after jump
     return (k-1,c)
   else :
     return None

Here's my attempt at the Prolog version (plus additional context):

use_module(library(lists)).

moves(0,1,3).
moves(0,2,5).
moves(1,3,6).
moves(1,4,8).
moves(2,4,7).
moves(2,5,9).
moves(3,6,10).
moves(3,7,12).
moves(4,7,11).
moves(4,8,13).
moves(5,8,12).
moves(5,9,14).
moves(3,4,5).
moves(6,7,8).
moves(7,8,9).
moves(10,11,12).
moves(11,12,13).
moves(12,13,14).

step(Step, Reversed) :-
    moves(F, O, T),
    Step     = [F, O, T],
    Reversed = [T, O, F].

init(I, Board) :-
    length(L0, 14),
    maplist(=(1), L0),
    nth0(I, Cells, 0, L0),
    Board = [14, Cells].

move(Board, Move, BoardAfterMove) :-
    [PegsLeft | [CellList]] = Board,
    (step(Move, _); step(_, Move)),
    PegsLeft > 2,
    [F, O, T] = Move,
    nth0(F, CellList, 1),
    nth0(O, CellList, 1),
    nth0(T, CellList, 0),
    NewPegsLeft is PegsLeft-1,
    nth0(F, NewCellList, 0),
    nth0(O, NewCellList, 0),
    nth0(T, NewCellList, 1),
    nth0(I, CellList, V),    % Questionable
    I \= F, I \= O, I \= T,  % Questionable
    nth0(I, NewCellList, V), % Questionable
    length(CellList, Length) = length(NewCellList, Length), % Questionable
    BoardAfterMove = [NewPegsLeft, NewCellList].

I have narrowed down my problem to creating NewCellList and my usage of length().

All I want to do is create a new list that is a copy of CellList with a few elements at indices F, O, and T set to different values.

Current output:

?- move([14,[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]], Move, Board).
Move = [3, 1, 0],
Board = [13, [1, 0, 1, 0|_G7261]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, 1|_G7267]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, 1|_G7270]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, 1|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
Move = [3, 1, 0],
Board = [13, [1, 0, _G7257, 0, _G7266, _G7269, _G7272|...]] ;
% (results for next move, [5, 2, 0] omitted)

Desired Output:

?- move([14,[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]], Move, Board).
Move = [3, 1, 0],
Board = [13, [1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] ;
% (results for next move, [5, 2, 0] omitted)

Basically, this problem boils down to performing the following in Prolog:

c=list(d)
c[f]=0
c[o]=0
c[t]=1

What am I doing wrong?

EDIT

Here's the answer (helper that uses nth0/4) applied to move():

setat(P,LO,V,LN):-nth0(P,LO,_,T),nth0(P,LN,V,T).

move(Board, Move, BoardAfterMove):-
    [PegsLeft | [CellList]] = Board,
    (step(Move, _) ; step(_, Move)),
    PegsLeft > 2,
    [F, O, T] = Move,
    nth0(F, CellList, 1),
    nth0(O, CellList, 1),
    nth0(T, CellList, 0),
    NewPegsLeft is PegsLeft-1,
    setat(F, CellList,     0, NewCellList0),
    setat(O, NewCellList0, 0, NewCellList1),
    setat(T, NewCellList1, 1, NewCellListFinal),
    BoardAfterMove = [NewPegsLeft, NewCellListFinal].

EDIT 2

Here's a simplified version based on feedback:

setat(Index, List, Val, OldVal, Result):-
    nth0(Index, List,   OldVal, BeforeSet),
    nth0(Index, Result, Val,    BeforeSet).

move(Board, Move, BoardAfterMove):-
    [PegsLeft | [CellList]] = Board,
    (step(Move, _) ; step(_, Move)),
    PegsLeft > 2,
    [F, O, T] = Move,
    NewPegsLeft is PegsLeft-1,
    setat(F, CellList,     0, 1, NewCellList0),
    setat(O, NewCellList0, 0, 1, NewCellList1),
    setat(T, NewCellList1, 1, 0, NewCellListFinal),
    BoardAfterMove = [NewPegsLeft, NewCellListFinal].

EDIT 3

Here's an even simpler version (PegsLeft > 2 is unnecessary):

move(Board, Move, BoardAfterMove):-
    [PegsLeft | [CellList]] = Board,
    (step(Move, _); step(_, Move)),
    [F, O, T] = Move, NewPegsLeft is PegsLeft-1,
    set_at(F, CellList,     0, 1, NewCellList0),
    set_at(O, NewCellList0, 0, 1, NewCellList1),
    set_at(T, NewCellList1, 1, 0, NewCellListFinal),
    BoardAfterMove = [NewPegsLeft, NewCellListFinal].

Thanks!!

1

1 Answers

2
votes

there is nth0/4: for instance

?- [user].
|: setat(P,LO,V,LN) :- nth0(P,LO,_,T),nth0(P,LN,V,T).
% user://1 compiled 0.11 sec, 1 clauses
true.

?- setat(2,[a,b,c,d],0,R).
R = [a, b, 0, d].