prologprolog-findall

Prolog findall/3: more than one bag


I'm writing AI for a Fox and Geese type of game. One of my predicates looks like this:

moveFox(+PrevState, -NextState, -PegList, +VisitedStates, -NewVisitedStates)

It takes a game state and makes a move with a fox. The resulting state is unified with NextState and the actual move is unified with PegList. Everything works as expected.

I am calculating the utility score for all of the moves' NextState. To be able to find the state with the highest utility score, I use findall/3 to get all states in a list before comparing their utility scores.

findall(NextState, moveFox(...), NextStatesList)

By finding the maximum utility score I know the NextState (as well as its position in the list) with the highest utility score. There is only one problem, currently I haven't written any predicate to infer which move was made to come to NextState, e.g.:

getMove(+PrevState, +NextState, -PegList)

Instead of writing such a predicate, I would much rather use findall/3 or equivalent. My question is if there is some way to get two different variables in two different lists. I'm thinking like this (if it would have worked):

findall([NextState, PegList], moveFox(...), [NextStatesList, MoveList])

Could I implement such functionality without having to either run findall/3 twice (ugly overhead) or write that getMove(+PrevState, +NextState, -PegList) predicate?


Solution

  • this problem can be tackled building a list of pairs, and then separating the elements, like library(pairs) does

    ...
    findall(NextState-PegList, moveFox(...), Pairs),
    pairs_keys_values(Pairs, NextStates, Pegs),
    ...
    

    If your Prolog doesn't have pairs_keys_values/3, it's easy to write either with maplist or via a recursive predicate. Here is the maplist way:

    pkv(K-V, K, V).
    pairs_keys_values(Pairs, Keys, Vals) :-
        maplist(pkv, Pairs, Keys, Vals).