how do i print out stars using prolog [duplicate] - prolog

This question already has an answer here:
how do you print stars n amount of times on multiple lines using prolog
(1 answer)
Closed 3 years ago.
I need to print out stars on one line and then n-1 on the next until one star, and then back to n amount.

What about as follows?
line(N) :-
foreach(between(1, N, _), write('*')),
nl.
star(1) :-
line(1).
star(N) :-
line(N),
NM1 is N-1,
star(NM1),
line(N).
Calling star(N).

This should work:
%this is the main function you want to call
star(N) :-
starl(N),
starr(1,N).
% counts down from n to zero and
% writes according amount of stars
starl(0):- !.
starl(N):-
write_n_times("*", N),
Nm is N-1,
starl(Nm).
% counts up from X to Np and
% writes according amount of stars
starr(N, N):- write_n_times("*", N), !.
starr(X, Np):-
write_n_times("*", X),
Xp is X+1,
starr(Xp, Np).
% writes X for I times and makes then a new line
write_n_times(_,0) :- nl, !.
write_n_times(X,I) :-
write(X),
Im is I - 1,
write_n_times(X,Im).

Related

Delete items that occur an odd number of times in a list

I have written code including count function that calculates how many times elements occurs in list, then I have function that go through all array and deletes the elements that occur odd number of times. But I got problem, an warning telling me "Arithmetic: `element_count' is not a function".
What is wrong and how to fix it?
countX([],_,0).
countX([X|T], X, P1) :- countX(T, X, P), P1 is P+1.
countX([H|T], X, P) :- H=\=X, countX(T, X, P).
goal([], []).
goal(Start, Result):-
remove_odd_count_numbers(Start, Start, Result).
remove_odd_count_numbers(_, [], []).
remove_odd_count_numbers(Start, [A|List], Result):-
count(Start, A, count_element),
count_element mod 2 =:= 0,
remove_odd_count_numbers(Start, List, Result), !.
remove_odd_count_numbers(Start, [Head|Tail], [Head|TailResult]):-
remove_odd_count_numbers(Start, Tail, TailResult), !.
count(Start, A, count_element),
count_element mod 2 =:= 0,
Variable names cannot start with lowercase letters in Prolog. You need Count_element. (At least that; it may not be enough to make it work).

Predicate in prolog

I need to define a predicate in prolog which takes a list as input and sums the squares of numbers >= 5 and subtract sum of absolute value of numbers <=2.
This is what I have currently :-
pred([], 0).
pred([Head|Tail], Result) :-
gr85(Head),
pred(Tail, Total),
Result is Head*Head + Total.
pred([Head|Tail], Result) :-
leq2(Head),
pred(Tail, Total),
Result is Total - Head.
gr85(Number):-
Number >= 5.
leq2(Number):-
Number =< 2.
My question is how do I exclude anything between 2 and 5. If I input 3 in the list, it returns false.
Expected input
pred([3,6,2,-1], Result).
Expected output
Result= 33 (6*6 -2-1)
add a 'skip all' clause:
weird_sum([_|Tail], Result) :- weird_sum(Tail, Result).
I think you will gain some insight into Prolog working when you analyze where this clause should be added.
Maybe it is simpler if you keep it more simple, you can use accumulator to make it simpler. And also it is maybe less typing if you move the condiditional out, like this;
weird_sum(List, Sum) :-
weird_sum(List, 0, Sum).
weird_sum([], Acc, Sum) :- Sum is Acc.
weird_sum([X|Xs], Sum0, Sum) :-
once( weird_sum_helper(X, Sum0, Sum1) ),
weird_sum(Xs, Sum1, Sum).
weird_sum_helper(X, Acc, Acc + X*X) :- X >= 5.
weird_sum_helper(X, Acc, Acc - abs(X)) :- X =< 2.
weird_sum_helper(X, Acc, Acc) :- X < 5, X > 2.
But the actual answer to your original question is in the last line above, just say that when X is smaller than 5 AND X is larger than 2 than you don't do anything.
But I get different answer from 33 because when number is negative and you subtract you get positive not negative but I am not sure if this is what you mean.
I used once once just because you want to do this only once since the three conditions are excluding each other but somehow Prolog doesn't know that it should only take one and tries the others too.

Count number of matching elements in two lists

I have 2 lists with random number of elemets. Eg A=[1,2,4,5] and B=[1,2,3]. Result should be 2.
Code that I tried:
domains
Numbers1 = integer*
Numbers2 = integer*
int_list=integer*
predicates
nondeterm prinadl(integer, int_list)
clauses
//here going the code that read number that I've entered, and according to entered numer,programm should do something
answer(T):- T=5,
P = 0,
write ("Enter the 1st list"), readterm (int_list, L),
write ("Enter the 2nd list"), readterm (int_list, L2),
L2 = [H|V], prinadl(H, L), P1 = P + 1,
write(L2, P1, V).
prinadl (X, L):- L=[X|_], !.
prinadl (X, L):- L=[_|T], prinadl (X, T).
I'm totally new with prolog. Can you please say me where I'm wrong? All I need is to get number of matches printed to the console.
Thanks in advance.
This answer is based on two things: first, guesswork. second, if_/3 by #false.
Let's define
the meta-predicate count_left_while2/4.
count_left_while2(P_2,Xs,Ys,N)
counts
the number N of corresponding list items in Xs and Ys fulfilling P_2. Proceeding from left to right, count_left_while2 stops at the first two items not satisfying P_2. It also stops when one list is empty, but the other one is not.
:- use_module(library(clpfd)).
:- meta_predicate count_left_while2(2,?,?,?).
count_left_while2(P_2,Xs,Ys,N) :-
N #>= 0,
list_list_countleft_while(Xs,Ys,N,P_2).
nil_or_cons([]).
nil_or_cons([_|_]).
:- meta_predicate list_list_countleft_while(?,?,?,2).
list_list_countleft_while([],Xs,0,_) :-
nil_or_cons(Xs).
list_list_countleft_while([X|Xs],Ys,N,P_2) :-
list_list_prev_countleft_while(Ys,Xs,X,N,P_2).
:- meta_predicate list_list_prev_countleft_while(?,?,?,?,2).
list_list_prev_countleft_while([],_,_,0,_).
list_list_prev_countleft_while([Y|Ys],Xs,X,N,P_2) :-
if_(call(P_2,X,Y),
( N0 #>= 0, N #= N0+1, list_list_countleft_while(Xs,Ys,N0,P_2) ),
N = 0).
Let's use it in combination with reified term equality predicate (=)/3, like this:
:- count_left_while2(=,[1,2,4,5],[1,2,3],N).
N = 2.

How to make program run in linear time?

So I would like to make this code to execute in linear time and I'm not sure what's making it take long than that so all help would be appriciated.
Sorry for not explaining earlier what the program does, medellangd is pretty much calculating the average length of the words sent in within the string.
medellangd([],0) :- !.
medellangd([Head1|[]], 0) :-
\+ check(Head1), !.
medellangd([Head1|[]], 1) :- !.
medellangd(Text, AvgLen) :-
medel(Text, X, Y),
AvgLen is X/Y.
medel([], 0, 0) :- !.
medel([Head1,Head2|Tail], Letters, Words) :-
check(Head1),
check(Head2), !,
medel([Head2|Tail], Letters1, Words),
Letters is Letters1 + 1.
medel([Head1|Tail], Letters, Words) :-
check(Head1),
medel(Tail, Letters1, Words1), !,
Letters is Letters1 + 1,
Words is Words1 + 1.
medel([_|T], Avg, Words) :-
medel(T, Avg, Words).
% We check that the input is a letter.
check(X) :-
(X >= 65, X =< 90);
(X >= 97, X =< 122).
Alright, seems like it was my method of checking it that was the problem, by using char-type on head instead of my check it solved my problem and I got i to run in linear time.

Prolog Programming

I have made two programs in Prolog for the nqueens puzzle using hill climbing and beam search algorithms.
Unfortunately I do not have the experience to check whether the programs are correct and I am in dead end.
I would appreciate if someone could help me out on that.
Unfortunately the program in hill climbing is incorrect. :(
The program in beam search is:
queens(N, Qs) :-
range(1, N, Ns),
queens(Ns, [], Qs).
range(N, N, [N]) :- !.
range(M, N, [M|Ns]) :-
M < N,
M1 is M+1,
range(M1, N, Ns).
queens([], Qs, Qs).
queens(UnplacedQs, SafeQs, Qs) :-
select(UnplacedQs, UnplacedQs1,Q),
not_attack(SafeQs, Q),
queens(UnplacedQs1, [Q|SafeQs], Qs).
not_attack(Xs, X) :-
not_attack(Xs, X, 1).
not_attack([], _, _) :- !.
not_attack([Y|Ys], X, N) :-
X =\= Y+N,
X =\= Y-N,
N1 is N+1,
not_attack(Ys, X, N1).
select([X|Xs], Xs, X).
select([Y|Ys], [Y|Zs], X) :- select(Ys, Zs, X).
I would like to mention this problem is a typical constraint satisfaction problem and can be efficiency solved using the CSP module of SWI-Prolog. Here is the full algorithm:
:- use_module(library(clpfd)).
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
N is the number of queens or the size of the board (), and , where , being the position of the queen on the line .
Let's details each part of the algorithm above to understand what happens.
:- use_module(library(clpfd)).
It indicates to SWI-Prolog to load the module containing the predicates for constraint satisfaction problems.
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
The queens predicate is the entry point of the algorithm and checks if the terms are properly formatted (number range, length of the list). It checks if the queens are on different lines as well.
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
It checks if there is a queen on the descendant diagonal of the current queen that is iterated.
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
Same as previous, but it checks if there is a queen on the ascendant diagonal.
Finally, the results can be found by calling the predicate queens/2, such as:
?- findall(X, queens(4, X), L).
L = [[2, 4, 1, 3], [3, 1, 4, 2]]
If I read your code correctly, the algorithm you're trying to implement is a simple depth-first search rather than beam search. That's ok, because it should be (I don't see how beam search will be effective for this problem and it can be hard to program).
I'm not going to debug this code for you, but I will give you a suggestion: build the chess board bottom-up with
queens(0, []).
queens(N, [Q|Qs]) :-
M is N-1,
queens(M, Qs),
between(1, N, Q),
safe(Q, Qs).
where safe(Q,Qs) is true iff none of Qs attack Q. safe/2 is then the conjunction of a simple memberchk/2 check (see SWI-Prolog manual) and your not_attack/2 predicate, which on first sight seems to be correct.
A quick check on Google has found a few candidates for you to compare with your code and find what to change.
My favoured solution for sheer clarity would be the second of the ones linked to above:
% This program finds a solution to the 8 queens problem. That is, the problem of placing 8
% queens on an 8x8 chessboard so that no two queens attack each other. The prototype
% board is passed in as a list with the rows instantiated from 1 to 8, and a corresponding
% variable for each column. The Prolog program instantiates those column variables as it
% finds the solution.
% Programmed by Ron Danielson, from an idea by Ivan Bratko.
% 2/17/00
queens([]). % when place queen in empty list, solution found
queens([ Row/Col | Rest]) :- % otherwise, for each row
queens(Rest), % place a queen in each higher numbered row
member(Col, [1,2,3,4,5,6,7,8]), % pick one of the possible column positions
safe( Row/Col, Rest). % and see if that is a safe position
% if not, fail back and try another column, until
% the columns are all tried, when fail back to
% previous row
safe(Anything, []). % the empty board is always safe
safe(Row/Col, [Row1/Col1 | Rest]) :- % see if attack the queen in next row down
Col =\= Col1, % same column?
Col1 - Col =\= Row1 - Row, % check diagonal
Col1 - Col =\= Row - Row1,
safe(Row/Col, Rest). % no attack on next row, try the rest of board
member(X, [X | Tail]). % member will pick successive column values
member(X, [Head | Tail]) :-
member(X, Tail).
board([1/C1, 2/C2, 3/C3, 4/C4, 5/C5, 6/C6, 7/C7, 8/C8]). % prototype board
The final link, however, solves it in three different ways so you can compare against three known solutions.

Resources