Assignment question about lists using findall and between

Hello, I have an assignment in prologue and I’m very not used to code in this language :slight_smile:
So I need to implement something quite simple to say but hard to me to code.

Let’s say I have a square room (Dimension 4x4 for example).
And I want a function that has as argument pos(Ligne,Column) that can verify if the position entered is correct considering the square Dimension.

So I want it to check if pos(1,2) for example is true in this context.
I thought about creating a list with findall or between of Valid positions considering the Dimension of the square and then verify if the position entered is inside of this list.

But I’m quite confused.

So i have

pos(Ligne,Column) :-
     Ligne>=0,
     Column>=0.
square(Dimension).
shape(square,Dimension) :- square(Dimension).

%Verifying if the position is correct here.
in_shape(pos(Ligne,Colonne), shape(square,Dimension)) :-
     pos(Ligne,Colonne), 
     shape(square,Dimension),
     ListValidPositions = ???,
     member(pos(Ligne,Colonne), ListValidPositions).


I really dont know if the way i structured this is correct.
Thanks for your help !

  1. Prolog, not Prologue, because it standards for PROgramming LOGic.

  2. In your example are you opposed to arithmetic? If I understand you, you want

Ligne <= 4 and Ligne >= 0 and Colonne <= 4 and Colonne >= 0.

You can translate that directly without having to list the positions:

<= is written as =< in Prolog.
and is reprented by , (the comma).

Hey, sorry for the name I was pronouncing it in French in my head.
I listed the positions just to make it more visible for my little brain.

Let me clarify a little more. Prolog does not have data declarations. Only predicates, which are both logical statements and implicitly an algorithm to evaluate the statement. So

pos(Ligne,Column) :-
 Ligne>=0,
 Column>=0.

Because you want to use pos as a term, not a predicate, you should not write this way. You should write

positif_position(pos(Ligne, Colonne)) :-
    Ligne >= 0, Colonne >= 0.


square(Dimension).
shape(square,Dimension) :- square(Dimension).

This does nothing useful. You can use square and shape terms without making predicates that do nothing. So simply remove this from your code. Thus your final code:

in_shape(pos(Ligne,Colonne), shape(square,Dimension)) :-
   positif_position(pos(Ligne, Colonne)),
   Ligne =< Dimension, Colonne =< Dimension.

If you want to use member. consider this:

  member(A, [0,1,2,3]), member(B, [0,1,2,3])

Prolog will find A that matches and B that matches, or fail if A or B are predefined out of range.

also look up the definition of between to change this code to allow any Dimension.

1 Like

Ohhh, its very well explained thank you.
I will go with Ligne =< Dimension, Colonne =< Dimension, its quite easy to understand.

Now, i tried something like this to do the job for any Dimension:

in_shape(pos(Ligne,Colonne), shape(square,Dimension)) :-
     positif_position(pos(Ligne, Colonne)),
     Ligne =< Dimension, Colonne =< Dimension,
     between(0,Dimension,Range),
     member(Ligne, [Range]), member(Colonne, [Range]).

but in_shape(pos(1,2), shape(square,4)). failed here and im not sure why. I turned one trace to see what is happening and i dont get it.
EDIT
I just realized that I’m verifying the range 2 times x)
But I still don’t understand why this part below between didn’t work.
Someone told me to use this instead.

   findall( I, between(0,Dimension,I), Range),
     member(Ligne, Range), member(Column, Range).

But I want to understand why my example didn’t work because I find it way simpler to visualize.
Thanks ;0

findall/3

findall (+Template, :Goal, -Bag)

is part of a family of predicates that is typically used to read data from facts. Each of them have an argument named Goal which is a predicate itself and the facts are read using the Goal predicate. So in your example the Goal would be between(0,Dimension,I) which would mean that there would have to be facts with a functor named between. But between/3 is already a defined predicate with SWI-Prolog, so using between as a functor is not a good choice.

Another bit of advise if you are not sure how a predicate works before using it, take the time to use it by itself to understand how it works so that you are not compounding your problem by introducing more unknowns.

findall examples

value(1).
value(2).
value(3).
value(4).
value(5).
value(6).
value(7).
value(8).

?- findall(Number,value(Number),Numbers).
Numbers = [1, 2, 3, 4, 5, 6, 7, 8].

?- findall(N,(value(N),0 is N mod 2),Evens).
Evens = [2, 4, 6, 8].

The Template tells findall what part of the Goal is needed, and Bag is the name given to collect all of the values returned as Template

So for findall(Number,value(Number),Numbers) the Goal reads the facts value/1 and unifies the number in value/1 with the variable Number in goal. Then since the Template is just Number that is saved, and collected into the variable in Bag which is Numbers.

Some variations that prints the values as they are found

?- findall(N,(value(N),format('N: ~w~n',[N])),Numbers).
N: 1
N: 2
N: 3
N: 4
N: 5
N: 6
N: 7
N: 8
Numbers = [1, 2, 3, 4, 5, 6, 7, 8].

?- findall(N,(value(N),format('N: ~w~n',[N]),0 is N mod 2,format('Even: ~w~n',[N])),Evens).
N: 1
N: 2
Even: 2
N: 3
N: 4
Even: 4
N: 5
N: 6
Even: 6
N: 7
N: 8
Even: 8
Evens = [2, 4, 6, 8].

Also what the other person suggested might be correct, but without seeing the all of the code and knowing the details of the conversation I can’t say if what they said is correct. It is possibly correct, but details are missing.

1 Like

Okay, I’m starting to understand.

I also realized that the predicate between does not return a list (though it was).

So with findall(Number,value(Number),Result).

I’m telling in that statement that I want all the possible Numbers of the predicate value(Number) which gives me a list that I store inside of Result to use it later on.

It’s all I wanted to know because i wasn’t sure why my first try didn’t worked.

Thanks a lot for your time :slight_smile:

1 Like

That is correct.

Some of us here also regularly check StackOverflow.

Now I see where you received that advise from.


Now it makes more sense.

What Will Ness is doing is to create the list of valid values for use with member/3, e.g. member(Ligne, Range), member(Column, Range).

One of the nicest features of Prolog once you get good with it is that not only is it good at deconstructing values, it is also good at generating values. In this case WIll used findall/3 as a generator and not as a reader of facts as I demonstrated.

Examples:

findall(I,between(0,4,I),Range).
Range = [0, 1, 2, 3, 4].

?- findall(N,(between(0,10,N),0 is N mod 2),Evens).
Evens = [0, 2, 4, 6, 8, 10].

Overall the better answer is this one

as it does not have to generate the list of possible values then test against them with member/3.

Yes, I posted it on Stack Overflow too because I’m new here and I didn’t know if it takes a lot of time to get a reply on a little question like this.But it’s very well explained, Thanks again. x)

Hello, I’m back again.

I’m stuck in my assignment (the same) but this time in more complex predicates
I think that I’m in the right path of reasoning but there are some things I can’t manipulate well enough to use in my code to solve the specific problem I’m going to explain.

Also, I don’t know if I should make another post of this or continue in this one?
If I need to please tell me

So here is some context.

Let’s say I have 3 rooms, room1, room2 & room3.
The shapes don’t really matter here so ill take the square I talked about previously.
All of them are square.
I can move in a room Up Down Left and Right (only by 1).

Each movement takes 1 unit of time to use(it doesn’t matter for my current problem it’s just for context)
If I have a special item(diagonalizer), it allows me to move in diagonal.
Each room have portals (I don’t know how many) that can teleport our current state in another room.
And we can come back too (Using a portal cost 1 unit of time).

room1           room2           room3
. . . . .       . . . . x       . . . . e
. t . . .       . . . . .       . . . x .
. . . . .       . . t . .       . . . . .
. . . . .       . . . . .       . . . . .
s . . . .       . . . . .       . . . . .

These are the rooms.
s= start ->pos(Line,Column)
e= end
t&x = portals

Here is how I see my problem.
state here means where am i (the position, the room and the time i’ve spent moving)

%Movments in a room.
move((state(pos(Line,Column), room(Index, shape(Shape,Dimension)), item(TheItem))),
     (state(pos(Line2,Column2), room(Index2, shape(Shape2,Dimension2)), item(CollectedItem))), 
     TimeSpent,
     Time) :-
%Verify if the movement is done in the same room
%If the index of the room is different, then there is a portal???
Index =:= Index2, Shape =:= Shape2, %this might change
%Verify if the resulting position of the movement is in the shape.
in_shape(pos(Line2,Column2), shape(Shape2,Dimension)),
%Definition of possible movements
Right is Column+1, Left is Column-1, Up is Line+1, Down is Line-1,

%This is an if else statement inside another one.
%If the item is a diagonalizer, then we can move in diag,
%CollectedItem is a diagonaliser and Time remains unchanged.
%else, we cant move in diag, CollectedItem is nothing and Time
%is Time+1.
(item(TheItem) -> CollectedItem = diagonalizer, Time is TimeSpent,
     member(Line2,[Up,Down]), member(Column2,[Left,Right]) ; %else
     CollectedItem = nothing, 
     Time is TimeSpent+1,
     (Column=:=Column2 -> member(Line2,[Up,Down]); Line2=:=Line, member(Column2,[Left,Right])) ).

As you can see, what my predicate move does is: it take a current state and verify if everything is correct (like if the positions are inside the shapes) to move us to the second state. It also takes the previous time spent and returns the new time cost with that movement.

I’m problem is :
I thought about adding a list of portals to room like this :
room(Index,[portals] ,shape(Shape,Dimension))
portals would be some position pos(Line,Collums) that represents if there is a portal in that position.(btw i really don’t know if i think right to solve that)

The thing is, how can even access that lists and tell my predicate move that if we are in a portal, then allow the index to be different. And verify that the portal takes us to the right index / position in the next room. Is it possible to deconstruct the elements of the list to use them?
In a OOP language i would have used a portal class but i dont see how to do it in here :confused: .
This is how i see my portals inside the list:

portail(pos(Line,Column), Id). % Id to recognize them x)

My brain hurts :slight_smile: .

I’m sorry it’s a lot of code but I needed to give the context for you to understand me.
If there is something unclear tell, me :S.

Thanks a lot.

This is not StackOverflow where each question requires a new question. Also here you can have long open discussion and go off the path without repercussions.

I use to spend a lot of time on StackOverflow, but now spend more of it here because it is more amenable to learning.

1 Like

Ohh this is cool :o,

I had a lot of down votes on stack Overflow in the beginning because my question was not specific enough since I use it when I’m completely new to a language :slight_smile: .

@Hazel I think your problem boils down to something most of us Prolog newbies struggle with: there are input and output arguments rather than return values.

Functions that return boolean values are called predicates in normal programming languages, and Prolog programs are constructed entirely out of predicates – a very weird but wonderful (once you get the hang of it) concept.

Prolog documentation uses functor(+Arg1, ?Arg2, -Arg3) notation to show that Arg1 is an input value (ie should not be a variable), Arg2 is bidirectional (a cool thing about Prolog is that unlike Erlang which I’m busy learning which needs atom_to_list(Atom), list_to_atom(List)... etc for type conversion, in Prolog you just have one predicate atom_string(?Atom, ?String) which works in either direction), and Arg3 which is akin to the return value in a normal programming language.

So your predicate should look something like:

move(+State0, -State1, +TimeSpent, +Time0, -Time1)

where you input the current state State0 and get the next state State1. To get the new Time1 is Time0 + TimeSpent, you need to include the current time Time0 as an input argument.

I’ve spent quite a lot of time using Prolog to write gameplaying programs (I’ve put some notes here https://swish.swi-prolog.org/p/Graphs1.swinb and would suggest that rather than using move(State0, State1,…) you do something like move(State0, Action1, State1,…).

The reason is there is likely to be more than one State1 for a given State0 (for instance with diagonal moves on a chess board, that could vary from one to four directions, plus a number of squares if moves like for a bishop or queen). That’s why I recommend keeping the Action1 to remember how you got to State1.

Don’t get disheartened with Prolog. It’s ability to store complex information like state(pos(Line,Column), room(Index, shape(Shape,Dimension)), item(TheItem))) as simply State0 (note surrounding a complex statement with brackets isn’t necessary), and then quickly get whatever element you want from the complex data structure by pattern matching makes it way cooler than OOP once you get the hang of it.

1 Like

I started to work on your problem and started down this path of reasoning.

A player needs to take up a space in a room. A room also needs boundaries that can be a wall, a door, etc.

Since you are using an x,y coordinate system then to create a room with one space to stand would need something like

% room t
% ┌─┐
% │ │
% └─┘
room(t,location(0,0),size(1,1)).
boundry(t,-1,-1).
boundry(t,-1,0).
boundry(t,-1,1).
boundry(t,0,-1).
space(t,0,0).
boundry(t,0,0).
boundry(t,1,-1).
boundry(t,1,0).
boundry(t,1,1).

Does this work for you? If so then I can continue otherwise I don’t know how to model your idea in Prolog and make it work.

The next step is to generate the boundary values using a predicate given just the room location and size. This assumes all boundaries are walls to start.


Side note

Unicode box drawing characters (Use these for copy and paste) - https://en.wikipedia.org/wiki/Box-drawing_character

┌ ─ ┬ ─ ┐
│   │   │
├ ─ ┼ ─ ┤
│   │   │
└ ─ ┴ ─ ┘

Hey,
I set up the boundaries of my room right here (I’m taking only squares as an example but we have more shapes of rooms in the assignment) :

in_shape(pos(Line,Column), shape(square,Dimension)) :-
     %les position doivent etre > 0.
     positif_position(pos(Line, Column)),
     %verifications des positions et de la dimension
     Dimension >= 0, Line =< Dimension, Column =< Dimension,
     %optionnel?
     shape(square,Dimension).

So this will immediately verify if the position is in the shape of the room… it simulates the boundaries.

Then, I use something like move(+state1,-state2,-Time) that makes me move to the state1-> to the second.

We use state, to represent where we are.
I imagined state like this :
state(pos(Line,Column), room(Index,shape(Shape,Dimension)),item(TheItem))

Note: the whole purpose of the assignment is to use dijkstra algorithms(already written) to find the quickest time to reach a point. Also, the teacher gave us those hints: in_shape and move, he used those predicates in his solution and we have to implement it. the rest is up to me

When asking for help with homework assignments, it works best if you post the assignment as given in the question, that avoids the back and forth starting discussions that takes up time for us trying to answer to figure the problem out. Had I know that those predicates had to be used as given I would have focused on that.

Also, some teachers do not like their students getting help from others online, so make sure your teacher has agreed to this. I have seen some students get banned from these sites because they did not note when turning in the assignment they had help.

Hey, thanks for the reply.

My teacher wants us to keep move as something that takes state1 and gives us state2 with the time without Action like you said.

I understand the fact that there is inputs and outputs.

My problem is more in state : if I choose to give each room a list of portals, how can I access the list.

:smiley:

Yeah sorry I study in French so I tried my best to explain.
And yeah he probably doesn’t want his student to get help.

There is a good chance they are aware of this site and also StackOverflow and since the predicates in_shape/2 and move/4 in the question are unique they know that you are getting help.