Related
I have made a function which in it I call several functions, but when one of them returns false the main function stops and returns false. So is there a way to tell Prolog if the function returns false then skip it and check the rest?
In detail: I am trying to make the 15 puzzle game as a project,
and I want to make function that gives me all the possible next moves.
I end up with calling all the previous functions that controls the blank tile.
next_move(Board, Moves):-
swapup(Board,Result),
swapdown(Board,Result),
swapright(Board,Result),
swapleft(Board,Result).
I want this function to return all the next possible moves
Here is the full code:
position([Tile|_], Tile, 0).
position([_|Tail], Tile, Index):-
position(Tail, Tile, Index1),
Index is Index1+1.
swap(Board,I,J,R) :-
same_length(Board,R),
append(BeforeI,[AtI|PastI],Board),
append(BeforeI,[AtJ|PastI],Bs),
append(BeforeJ,[AtJ|PastJ],Bs),
append(BeforeJ,[AtI|PastJ],R),
length(BeforeI,I),
length(BeforeJ,J).
swapup(Board,Result):-
position(Board,0,Index),
Index \=0,
Index \=1,
Index \=2,
Index \=3,
Up is Index-4,
swap(Board,Up,Index,Result).
swapdown(Board,Result):-
position([],0,Index),
Index \=12,
Index \=13,
Index \=14,
Index \=15,
Down is Index+4,
swap(Board, Down, Index, Result).
swapright(Board,Result):-
position([],0,Index),
Index \=3,
Index \=7,
Index \=11,
Index \=15,
Right is Index+1,
swap(Board, Right, Index, Result).
swapleft(Board,Result):-
position([],0,Index),
Index \=0,
Index \=4,
Index \=8,
Index \=12,
Left is Index-1,
swap(Board, Left, Index, Result).
swap(Board,Result) :- swapup(Board,Result).
swap(Board,Result) :- swapdown(Board,Result).
swap(Board,Result) :- swapright(Board,Result).
swap(Board,Result) :- swapleft(Board,Result).
next_move(Board,Moves) :- findall(Result,swap(Board,Result),Moves).
Here's a simple program:
a.
b :- fail.
c.
g :- a, b, c.
I can ask if g succeeds:
?- g.
false.
It does not.
I can solve this two ways.
(1)
g :- a, b, c.
g :- a, c.
(2)
g :- a, (b; true), c.
Either way, g succeeds now:
?- g.
true.
Update
This is the code you've posted:
next_move(Board, Moves) :-
swapup(Board,Result),
swapdown(Board,Result),
swapright(Board,Result),
swapleft(Board,Result).
On the LHS you have a variable Moves that is not on the RHS. Moves can never be unified and will always remain a variable.
Let's ignore that for a minute and look at the swap predicates.
If I assume that Result is a valid move given the current state of the Board then what your code is saying next_move(Board, Moves) succeeds when each of the swap predicates succeed and that can't happen unless the move you get from each of the swap predicates is the same.
Once swapup(Board,Result) succeeds it will have unified Result with the "swap up" move. Then you ask if swapdown(Board,Result) succeeds. Well, Result isn't a variable anymore so you're asking if the Result you get from swapdown is the same as the Result you get from swapup. I'm guessing it's not.
It's possible that you need something like this:
next_move(Board,[U,D,R,L]):-
swapup(Board,U),
swapdown(Board,D),
swapright(Board,R),
swapleft(Board,L).
But that's not clear because I don't know what value you get when your open space on your board is already at an edge.
It's probably more likely that you need this:
swap(Board,Result) :- swapup(Board,Result).
swap(Board,Result) :- swadown(Board,Result).
swap(Board,Result) :- swapright(Board,Result).
swap(Board,Result) :- swapleft(Board,Result).
next_move(Board,Moves) :- findall(Result,swap(Board,Result),Moves).
But all of this is guessing without seeing your full code.
Here's your code working now. There were a number of issues.
position/3 just simply didn't work.
Here's a version that does:
position(List,Element,Index) :-
position(List,Element,0,Index).
position([Element|_],Element,Index,Index).
position([_|Tail],Element,Counter,Index) :-
Next is Counter + 1,
position(Tail,Element,Next,Index).
You were always calling swap/4 with the same order of the two indices. You have to make sure they go in in ascending order. swap/4 didn't work in any case. Here's the new version:
swap(BoardIn,I,J,BoardOut) :-
position(BoardIn,X,I), % find the value `X` at position `I`
position(BoardIn,Y,J), % find the value `Y` at position `J`
append(Left,[X|MiddleEnd1],BoardIn), % find the list that is `Left` of `X`
append(Middle,[Y|End],MiddleEnd1), % find the `Middle` that is left of `Y` and the list `End` that is to the right of `Y`
append(Middle,[X|End],MiddleEnd2), % put `X` between `Middle` and `End`.
append(Left,[Y|MiddleEnd2],BoardOut). % put the `Y` between `Left` & `Middle`.
I cleaned up the swap*/2 predicates.
swapup(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Up is Index - 4,
Up >= 0,
swap(BoardIn,Up,Index,BoardOut).
swapdown(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Down is Index + 4,
Down =< 15,
swap(BoardIn,Index,Down,BoardOut).
swapright(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Index mod 4 =\= 3,
Right is Index + 1,
swap(BoardIn,Index,Right,BoardOut).
swapleft(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Index mod 4 =\= 0,
Left is Index - 1,
swap(BoardIn,Left,Index,BoardOut).
swap(BoardIn,BoardOut) :- swapup(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapdown(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapright(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapleft(BoardIn,BoardOut).
And finally, here's the next_move/2 predicate:
next_move(BoardIn,Moves) :-
length(BoardIn,16),
position(BoardIn,0,_),
findall(BoardOut,swap(BoardIn,BoardOut),Moves).
Now I can call this query:
?- next_move([1,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15],Result),write(Result).
I get this result:
[[1,5,2,3,4,0,6,7,8,9,10,11,12,13,14,15],[1,2,0,3,4,5,6,7,8,9,10,11,12,13,14,15],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]]
I have basic Tick-tack-toe game, where 2 players both make moves on a grid of 9 cells. The problem is that after the frist player makes the last and winnig move, the game doesnt stop and player 2 still can play. And if second player, somehow, makes winning move too, he will be the winner, despite player 1 actually getting the win first. It doesnt make same error if second player wins frist. Draw works fine. Here`s the code:
:- dynamic o/1.
:- dynamic x/1.
/* the various combinations of a successful horizontal, vertical
or diagonal line */
ordered_line(1,2,3).
ordered_line(4,5,6).
ordered_line(7,8,9).
ordered_line(1,4,7).
ordered_line(2,5,8).
ordered_line(3,6,9).
ordered_line(1,5,9).
ordered_line(3,5,7).
/*line predicate to complete lines
line(A,B,C) :- ordered_line(A,B,C).
line(A,B,C) :- ordered_line(A,C,B).
line(A,B,C) :- ordered_line(B,A,C).
line(A,B,C) :- ordered_line(B,C,A).
line(A,B,C) :- ordered_line(C,A,B).
line(A,B,C) :- ordered_line(C,B,A).
full(A) :- x(A).
full(A) :- o(A).
empty(A) :- not(full(A)).
all_full :- full(1),full(2),full(3),full(4),full(5),
full(6),full(7),full(8),full(9).
done :- ordered_line(A,B,C), x(A), x(B), x(C), write('Player 2 win.'),nl.
done :- ordered_line(A,B,C), o(A), o(B), o(C), write('Player 1 win.'),nl.
done :- all_full, write('Draw.'), nl.
move1 :- write('Player 1 (o) enter a move: '), read(X), between(1,9,X),
empty(X), assert(o(X)).
move1:-all_full.
move2 :- write('Player 2 (x) enter a move: '), read(X), between(1,9,X),
empty(X),assert(x(X)).
move2:- all_full.
printsquare(N) :- o(N), write(' o ').
printsquare(N) :- x(N), write(' x ').
printsquare(N) :- empty(N), write(' ').
printboard :- printsquare(1),printsquare(2),printsquare(3),nl,
printsquare(4),printsquare(5),printsquare(6),nl,
printsquare(7),printsquare(8),printsquare(9),nl.
clear :- x(A), retract(x(A)), fail.
clear :- o(A), retract(o(A)), fail.
play :- not(clear), repeat, move1, printboard, move2,printboard, done.
And that`s the error I get:
Game doesnt stop when player 1 wins
Hope you can help me :) Thanks in advance.
Edit: The "Player 2 wins" shows in "done" predicate. After successfull finishing line of 3 'o' or 'x' game should end with either Player 1 wins or Player 2 wins. I`ll include original code, which might help with understanding the problem I get Original code with comments
The problem is in the main predicate of the game:
play :- not(clear), repeat, move1, printboard, move2,printboard, done.
You do not check for done after player's 1 move.
In Prolog's syntax, logical "or" is written as ;. So one way to express the play predicate is:
play :- not(clear), repeat, move1, printboard, (done; move2, printboard, done).
Which says "after move1, check if the game is done (i.e., finished); if not, player 2 makes the move, and then the check is repeated.
I want to apply a list of effects in a current state in other words, have a list of effects generated by an action if the current state has a condition that corresponds to the denial of a effect that condition will be removed.
If i have the current state:
[clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,desk)]
And the list of effects :
[-clear(d), -on(d.c), on(c,d)]
The result would be :
[clear(b),on(b,a),on(a,mesa), on(c,d), on(c,desk)]
This is what i got right now, any help would be appreciated!
applyEffects(currentState,Effects,result)
insert(Element, List,result)
remove(Element,List, result)
applyEffects([],L,L).
applyEffects(L,[],L).
applyEffects([X|XTail], [-X|YTail], A) :-
insert(X, A, B),
applyEffects([X|XTail],YTail, B).
insert(E, L1, [E|L1]).
remove(X, [X|L1], L1).
remove(X, [Y|L1], A):- remove(X,L1,[L1|Y]).
Your insert and remove should both be select (which is often built-in).
You might want to distinguish, if you have a "negative" argument or not:
applyEffects(L,[],L).
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
select(X,Y,A).
applyEffects(L,[X|R],[X|Y]):-
applyEffects(L,R,Y).
The cut used in the second clause is a red cut, to make it green, add a \+ X = - _ line to the third clause.
if you want to allow non-existing negatives, change the second clause to this:
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
(select(X,Y,A),!;
Y = A).
Now applyEffects([],[-on(something)],X) doesn't fail.
I am new in Prolog and I need a little help. There is this problem:
The input is a given certain state space, which is edge-labeled tree.
Write a program in Prolog that implements a search by BFS method and
finds its way to the destination node (g) of the state space with a
minimum price.
E.g. : Edge-labeled tree --> (a, g, [a-b/1, a-c/3, b-d/4, b-e/7, c-f/6, c-g/9])
e.g. tree
Thx for help, need it.
EDIT:
This is what i done, but its only for NOT edge-labeled tree. I dont know how add edge-labeled.
oh(a,*).
oh(c,a).
oh(b,a).
oh(d,b).
oh(b,e).
oh(c,f).
oh(c,g).
oh(f,h).
bFS(Start, Finish, Path) :-
assertz(gen(Start, *)),
retract(gen(From, To)),
assertz(exp(From, To)),
oh(From, New),
not(gen(New, _)),
not(exp(New, _)),
assertz(gen(New, From)), New = Finish, find(From, [Finish], Path).
find(*, Path, Path).
find(Add, List, Path) :-
oh(Pridavany, Previous),
find(Previous,[Add|List],Path).
%find(b,[e],Path).
These are some good tips on Prolog search.
Try reading these before you see the answer.
The Breadth First Algorithm has been posted on cs.unm.edu and works fine with SWI Prolog.
state_record(State, Parent, [State, Parent]).
go(Start, Goal) :-
empty_queue(Empty_open),
state_record(Start, nil, State),
add_to_queue(State, Empty_open, Open),
empty_set(Closed),
path(Open, Closed, Goal).
path(Open,_,_) :- empty_queue(Open),
write('graph searched, no solution found').
path(Open, Closed, Goal) :-
remove_from_queue(Next_record, Open, _),
state_record(State, _, Next_record),
State = Goal,
write('Solution path is: '), nl,
printsolution(Next_record, Closed).
path(Open, Closed, Goal) :-
remove_from_queue(Next_record, Open, Rest_of_open),
(bagof(Child, moves(Next_record, Open, Closed, Child), Children);Children = []),
add_list_to_queue(Children, Rest_of_open, New_open),
add_to_set(Next_record, Closed, New_closed),
path(New_open, New_closed, Goal),!.
moves(State_record, Open, Closed, Child_record) :-
state_record(State, _, State_record),
mov(State, Next),
% not (unsafe(Next)),
state_record(Next, _, Test),
not(member_queue(Test, Open)),
not(member_set(Test, Closed)),
state_record(Next, State, Child_record).
printsolution(State_record, _):-
state_record(State,nil, State_record),
write(State), nl.
printsolution(State_record, Closed) :-
state_record(State, Parent, State_record),
state_record(Parent, _, Parent_record),
member(Parent_record, Closed),
printsolution(Parent_record, Closed),
write(State), nl.
add_list_to_queue([], Queue, Queue).
add_list_to_queue([H|T], Queue, New_queue) :-
add_to_queue(H, Queue, Temp_queue),
add_list_to_queue(T, Temp_queue, New_queue).
The code is free to use, for education purposes.
We offer them for use, free of charge, for educational purposes only.
We cannot know for sure what you want to achieve, but this is the algorithm.
I'm trying to make a simple hangman game in SWI Prolog.
Since we made this program run can you help me enchance the program with the following:
1) By keeping up with the letters that have been guessed so far. If the user guesses a letter that has already been guessed, the program should say 'You guessed that!' and just continue the game.
2) Lastly, add a counter that counts the number of incorrect guesses and quits the game when a certain number is reached. The program should tell the user that they lose, display what the phrase really was, and terminate. Duplicate guesses should not be counted as wrong.
I would like to thank everyone who helped me so far. This means a lot to me.
I provide you with the code and comments.
% This top-level predicate runs the game. It prints a
% welcome message, picks a phrase, and calls getGuess.
% Ans = Answer
% AnsList = AnswerList
hangman:-
getPhrase(Ans),
!,
write('Welcome to hangman.'),
nl,
name(Ans,AnsList),
makeBlanks(AnsList, BlankList),
getGuess(AnsList,BlankList).
% Randomly returns a phrase from the list of possibilities.
getPhrase(Ans):-
phrases(L),
length(L, X),
R is random(X),
N is R+1,
getNth(L, N, Ans).
% Possible phrases to guess.
phrases(['a_picture_is_worth_a_thousand_words','one_for_the_money','dead_or_alive','computer_science']).
% Asks the user for a letter guess. Starts by writing the
% current "display phrase" with blanks, then asks for a guess and
% calls process on the guess.
getGuess(AnsList, BlankList):-
name(BlankName, BlankList),
write(BlankName),
nl,
write('Enter your guess, followed by a period and return.'),
nl,
read(Guess),
!,
name(Guess, [GuessName]),
processGuess(AnsList,BlankList,GuessName).
% Process guess takes a list of codes representing the answer, a list of codes representing the current
% "display phrase" with blanks in it, and the code of the letter that was just guessed. If the guess
% was right, call substitute to put the letter in the display phrase and check for a win. Otherwise, just
% get another guess from the user.
processGuess(AnsList,BlankList,GuessName):-
member(GuessName,AnsList),
!,
write('Correct!'),
nl,
substitute(AnsList, BlankList, GuessName, NewBlanks),
checkWin(AnsList,NewBlanks).
processGuess(AnsList, BlankList,_):-
write('Nope!'),
nl,
getGuess(AnsList, BlankList).
% Check to see if the phrase is guessed. If so, write 'You win' and if not, go back and get another guess.
checkWin(AnsList, BlankList):-
name(Ans, AnsList),
name(BlankName, BlankList),
BlankName = Ans,
!,
write('You win!').
checkWin(AnsList, BlankList):-
!,
getGuess(AnsList, BlankList).
% getNth(L,N,E) should be true when E is the Nth element of the list L. N will always
% be at least 1.
getNth([H|T],1,H).
getNth([H|T],N,E):-
N1 is N-1,
getNth(T,N1,E1),
E=E1.
% makeBlanks(AnsList, BlankList) should take an answer phrase, which is a list
% of character codes that represent the answer phrase, and return a list
% where all codes but the '_' turn into the code for '*'. The underscores
% need to remain to show where the words start and end. Please note that
% both input and output lists for this predicate are lists of character codes.
% You can test your code with a query like this:
% testMakeBlanks:- name('csc_is_awesome', List), makeBlanks(List, BlankList), name(Towrite, BlankList), write(Towrite).
makeBlanks(AnsCodes, BlankCodes) :-
maplist(answer_blank, AnsCodes, BlankCodes).
answer_blank(Ans, Blank) :-
Ans == 0'_ -> Blank = Ans ; Blank = 0'* .
% substitute(AnsList, BlankList, GuessName, NewBlanks) Takes character code lists AnsList and BlankList,
% and GuessName, which is the character code for the guessed letter. The NewBlanks should again be a
% character code list, which puts all the guesses into the display word and keeps the *'s and _'s otherwise.
% For example, if the answer is 'csc_is_awesome' and the display is 'c*c_**_*******' and the guess is 's', the
% new display should be 'csc_*s_***s***'.
% You can test your predicate with a query like this:
% testSubstitute:- name('csc_is_awesome', AnsList), name('c*c_**_*******', BlankList), name('s',[GuessName]), substitute(AnsList, BlankList, GuessName, NewBlanks),
% name(Towrite, NewBlanks), write(Towrite).
% Also, since the predicate doesn't deal directly with character codes, this should also work:
% substitute(['c','s','c'],['c','*','c'],'s',L). L should be ['c','s','c'].
substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).
place_guess(Guess, Ans, Blank, Display) :-
Guess == Ans -> Display = Ans ; Display = Blank.
maplist/3 & maplist/4 apply their first argument (a predicate of appropriate arity) against all elements of other arguments lists, then your makeBlanks could be:
makeBlanks(AnsCodes, BlankCodes) :-
maplist(answer_blank, AnsCodes, BlankCodes).
answer_blank(Ans, Blank) :-
Ans == 0'_ -> Blank = Ans ; Blank = 0'* .
and substitute:
substitute(AnsCodes, BlankCodes, GuessName, NewBlanks) :-
maplist(place_guess(GuessName), AnsCodes, BlankCodes, NewBlanks).
place_guess(Guess, Ans, Blank, Display) :-
Guess == Ans -> Display = Ans ; Display = Blank.
edit:
on additional requests: 1) can be solved with an additional predicate:
alreadyGuessed(Guess, AnsCodes) :-
memberchk(Guess, AnsCodes).
while regards 2) getGuess and processGuess together make a loop, that will just terminate when no more calls happen. Remove the last rule of checkWin, add an argument as counter to keep track of failed guesses, and extend processGuess to signal failure:
processGuess(AnsList, BlankList, _, CountFailed) :-
( CountFailed == 5
-> format('Sorry, game over. You didn\'t guess (~s)~n', [AnsList])
; write('Nope!'),
CountFailed1 is CountFailed + 1,
getGuess(AnsList, BlankList, CountFailed1)
).
Why so many cuts? Check out SWI library predicates that may be useful to you: memberchk/2, format/2 and nth1/3.