Prolog - Lotto Machine - list

This is my first post. I have been teaching myself Prolog for a university project and I am tasked with generating a program that simulates the lotto and compares the random numbers (6 in this case) with the numbers that the user has. If they all match then you are deemed the winner if not, then it returns 'hard luck'.
All I have been able to do so far is generate one random number in the range of 1-50. I don't know how to do much else after that.
:- use_module(library(random)).
?- random(1,50,Out).
I understand I have to add the random number to a list, but I'm not sure how to implement it. And to then have another list of numbers (user_numbers) in the database or fact-base. Then use SWI-Prolog to check if they're equal.
It is a really tough program for me to try and do in Prolog, especially seeing as I am teaching it to myself. If anybody could give me some pointers on how to approach it I would be very grateful.

pick_number(N) :- random(1, 50, N).
We need to pick a list of 6 numbers
lotto_numbers(Ns) :-
length(Ns, 6), % The length of our list is 6, now we have a list of 6 free variables.
select_numbers(Ns). % We need to select our numbers, binding them to our free variables.
select_numbers([]). % An empty list needs no picking
select_numbers([N|Ns]) :-
pick_number(N), % We pick the first number (bind the free variable to a random number)
select_numbers(Ns). % Then we pick the rest of the numbers.
We need to check if the ticket holder has winning numbers. Does it matter what order the numbers are in? If so, then we can check if the two lists unify: LottoNumbers = LottoTicketNumbers. If we don't care about order, then we need a slightly more complex solution:
numbers_match([], []). % if both lists are empty, then they must have all matched.
numbers_match([N|Ns], Ms) :-
select(N, Ms, NewMs), % remove N from Ms (if N matches an element in Ms), leaving NewMs
numbers_match(Ns, NewMs). % remove the rest of Ns from NewMs.
If both lists don't empty at the same time, then they didn't all match up.
Supposing we have some loto ticket in the database,
lotto_ticket(Ns) :- lotto_numbers(Ns).
With all the above definitions in our program, we can generate a lotto ticket, and generate some lotto numbers (actually the same process, but named differently for illustrative purposes), and see if they have all and only the same numbers:
?- lotto_ticket(T), lotto_numbers(L), numbers_match(T, L).
false.
Ah. No surprise that we lost...
That's all fine and good, but we can save a lot of steps by using a higher-order
predicate and some common library predicates:
alt_lotto_numbers(Ns) :-
length(Ns, 6),
maplist(random(1,50), Ns). % `maplist/2` is just a way of calling a predicate on every member of a list.
alt_numbers_match(Ns, Ms) :-
same_length(Ns, Ms),
subset(Ns, Ms).

Related

How to find and output lists including the max number(of all lists)? Prolog

I need to find the max number in a list of lists in Prolog, and then 'print' (output in a new list) the lists that include this max number.
For example: lists_with_max([[1,2,3],[2,3,44],[44,5,6]],Lists).
Should output: Lists = [[2,3,44],[44,5,6]]
Code below is the closest I could think of that works and has no errors, but it's obviously wrong because everytime it finds a new max and then outputs wrong lists.
'max' finds the max number in a list.
'flat' "flattens" a list.
'maxl' finds the max number in a list of lists.
max([X], X).
max([H|T], H):-
max(T, MaxT),
H > MaxT.
max([H|T], MaxT):-
max(T, MaxT),
H =< MaxT.
flat([], []).
flat([H|T], [H|LT]):-
atomic(H),
flat(T, LT).
flat([H|T], L):-
flat(T, LT),
not(atomic(H)),
flat(H, LH),
append(LH, LT, L).
maxl(List,Max):-
flat(List,Newlist),
max(Newlist,Max).
lists_with_max([],[]).
lists_with_max([H|T],[H|L]):-
maxl([H|T],Max),
member(Max,H),
lists_with_max(T,L).
lists_with_max([_H|T],L):-
lists_with_max(T,L).
Here's another approach using builting predicates max_list/2, maplist/3, include/3 and memberchk/2:
lists_with_max(LL, LL1):-
maplist(max_list, LL, ML),
max_list(ML, M),
include(memberchk(M), LL, LL1).
I think you went off the rails a bit with maxl/2 and flat/2, you don't really need them to solve your problem. This isn't, IMO, a great example of something you can do by throwing a bunch of recursion at the problem, you really are going to have to look through all the lists, find the max element, and then look through them all again. Your max/2 is fine though.
So, let's find the max element:
setof(Max, L^(member(L, Lists), max(L, Max)), Maxes),
This is a meta-predicate, it's just going to look through all the lists for the max of that list, and make a new list of the maxes of each list. I think good Prolog should have a fluent quality; if you reworded your query into something more like logic, you would have something like "The Maxes of the Lists is a list containing the max of each List" and eventually you would arrive at something like what you see there. The L^ is saying, we do not want to group this by the list L it generates (there will come other times in your life as a Prolog programmer where you will want this grouping). Probably using findall/3 would have the same effect, but I like setof/3 more.
Next, let's find the max-of-maxes:
max(Maxes, Max),
Pretty straight-forward. Now let's find all the lists that have the maximum in them:
setof(L, (member(L, Lists), member(Max, L)), Result).
This is another one like the first, where we're saying "find me all the lists L such that L is in Lists and Max is in L". Putting it all together we have:
lists_with_max(Lists, Result) :-
setof(Max, L^(member(L, Lists), max(L, Max)), Maxes),
max(Maxes, Max),
setof(L, (member(L, Lists), member(Max, L)), Result).
Another way of doing max/2, which I include here mostly to show you another way to think about Prolog because it is way, way less efficient and sort of terrible is this:
max(List, Max) :-
member(Max, List),
\+ (member(Y, List), Y > Max).
This isn't great style, but it does demonstrate that you can sometimes tell Prolog what you want rather than how to find it. This says the Max of List is the member of Max of List such that there is no member Y of List which is greater than it. Food for thought, I hope.

Remove Multiple Elements in a Python List Once

(Using Python 3)
Given this list named numList: [1,1,2,2,3,3,3,4].
I want to remove exactly one instance of “1” and “3” from numList.
In other words, I want a function that will turn numList into: [1,2,2,3,3,4].
What function will let me remove an X number of elements from a Python list once per element I want to remove?
(The elements I want to remove are guaranteed to exist in the list)
For the sake of clarity, I will give more examples:
[1,2,3,3,4]
Remove 2 and 3
[1,3,4]
[3,3,3]
Remove 3
[3,3]
[1,1,2,2,3,4,4,4,4]
Remove 2, 3 and 4
[1,1,2,4,4,4]
I’ve tried doing this:
numList=[1,2,2,3,3,4,4,4]
remList = [2,3,4]
for x in remList:
numList.remove(x)
This turns numList to [1,2,3,4,4] which is what I want. However, this has a complexity of:
O((len(numList))^(len(remList)))
This is a problem because remList and numList can have a length of 10^5. The program will take a long time to run. Is there a built-in function that does what I want faster?
Also, I would prefer the optimum function which can do this job in terms of space and time because the program needs to run in less than a second and the size of the list is large.
Your approach:
for x in rem_list:
num_list.remove(x)
is intuitative and unless the lists are going to be very large I might do that because it is easy to read.
One alternative would be:
result = []
for x in num_list:
if x in rem_list:
rem_list.remove(x)
else:
result.append(x)
This would be O(len(rem_list) ^ len(num_list)) and faster than the first solution if len(rem_list) < len(num_list).
If rem_list was guaranteed to not contain any duplicates (as per your examples) you could use a set instead and the complexity would be O(len(num_list)).

Generate square from matrix in Prolog

I have a matrix of 6x6 numbers and I'm writing a prolog code that gives me the numbers in a certain row, column or square. For instance:
0n 1n 2n 3n 4n 5n
0n [[1,2,3,4,5,6]
1n [2,3,4,5,6,1]
2n [3,4,5,6,1,2]
3n [4,5,6,1,2,3]
4n [5,6,1,2,3,4]
5n [6,1,2,3,4,5]]
I already have code for rows and columns, which is something like:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y-1 is Y1,
row(Y1,B,X).
But now I'm stuck on how to generate a 3x3 square. I want to work with coordinates, so the first argument should be something like (1,3) and it will give the square of row 1n and column 3n, then the matrix as the second and the numbers in the square as third argument.
Does anyone have any tips? I was thinking I might have to work with a head tail pattern again; getting the first three numbers of the given row/column, then doing this three times, but I don't know how or if this is possible and effective.
Any comments are greatly appreciated!
First of all, your predicate to obtain the row, is not safe:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y-1 is Y1,
row(Y1,B,X).
In case I query for row(0,[1,4,2,5],X). it will get stuck into an infinite loop immediately, in case i work with row(2,[1,4,2,5]). it will first give me the correct result, but then get into an infinite loop when searching for more answers.
A better approach would be:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y > 1,
Y-1 is Y1,
row(Y1,B,X).
Since now the Y > 1 guards the fact that you will not perform recursion if Y is less than or equal to 1.
That being said, you do not need to construct this predicate yourself: most Prolog interpreters already have such a predicate: nth1/3:
nth1(?Index, ?List, ?Elem)
Is true when Elem is the Index'th element of List. Counting
starts at 1.
If you can assume that this predicate exists, you can use:
elem(I,J,Matrix,Cell) :-
nth1(I,Matrix,Row),
nth1(J,Row,Cell).
Where I is the number of the row, and J the number of the column we wish to fetch.
In case it does not exists, I suggest renaming your row/3 predicate to nth1/3 since it is equivalent.
In case you want to start counting at 0 (which the top of your question suggests), you can use nth0/3 instead of nth1/3.

Creating a table of square roots of a given list in Prolog

I am a newbie to Prolog and trying to develop a simple code to get the following output.
?-sqrt_table(7, 4, Result).
Result = [[4, 2.0],[7, 2.64575],[6, 2.44949],[5, 2.23607]] ;
false.
However the output I'm getting is,
?- sqrt_table(4,7,X).
X = [[5, 2.23606797749979], [[6, 2.449489742783178], [[7, 2.6457513110645907], []]]].
I think the issue is in the nested list created by get_sqrt/2. If I can get it flattened down to tuples I think it might work. Your ideas and help are much appreciated.
%main predicate
sqrt_table(N,M,Result):-
full_list(N,M,Out),
get_sqrt(Out,[Rest,Result]).
%Creates a range of outputs within the given upper and lower limits
range(Low,Low,High).
range(Out,Low,High):-
NewLow is Low+1,NewLow=<High,
range(Out,NewLow,High).
%Creates a list of the outputs created by range/3
full_list(Low,High,Out):-
findall(X,range(X,Low,High),Out).
%Calculates the square root of each item in the list and gives a list consisted
%of sublists such that [Input,Squareroot of the input]
get_sqrt([],[]).
get_sqrt([H|T],[[H,Sqrt],SqrtRest]):-
SqrtOf_H is sqrt(H),
get_sqrt(T,SqrtRest),
Sqrt = SqrtOf_H.
Thanks in advance.
In the head of the second clause ofget_sqrt/2, simply write [[H,Sqrt]|SqrtRest], i.e., use (|)/2 instead of (,)/2.
In fact, it would be even better to use the more readable and more idiomatic [H-Sqrt|HSqrts], i.e., use (-)/2 do denote pairs.
And in second fact, a better way altogether is to simply state the relation for one element at a time, using for example:
integer_isqrt(I, I-Sq) :- Sq is sqrt(I).
and then to use the meta-predicate maplist/3 to relate lists of such elements to one another:
?- maplist(integer_isqrt, [0,1,2,3,4], Ls).
Ls = [0-0.0, 1-1.0, 2-1.4142135623730951, 3-1.7320508075688772, 4-2.0].
P.S.: Using flatten/2 always indicates a problem with your data structures, you should avoid flatten/2 entirely. If you need to remove one level of nesting, use append/2. But in this case, neither is needed.

Prolog IntList definition

hill(+IntList) succeeds if IntList consists of monotonically increasing >integers followed by monotonically decreasing integers. For example, >[1,2,5,8,11,6,3,-1] is a hill, but [1,2,5,8,11,6,9,3,-1] and [1,2,3,4,5,6] are >not hills. You may assume that IntList contains only integers.
This is what I have done so far:
hill(List) :-
increasing(List), decreasing(List).
increasing([H|Tail]) :-
sm(H,Tail),
increasing(Tail).
increasing([]).
decreasing([H|Tail]) :-
gr(H,Tail),
decreasing(Tail).
decreasing([]).
hill([]).
gr(X,[H|Tail]) :- X>H.
gr(X,[]).
sm(X,[H|Tail]) :- X<H.
sm(X,[]).
But this doesn't work. The logic is: A list of numbers is hill IF it is increasing and then decreasing. How do I say that? This code does increasing and decreasing, but no list can be both increasing and decreasing.
Any ideas?
I don't want to give a complete, working solution to a homework problem, but I'll describe in words how I would proceed from the code you've got right now. Right now your increasing and decreasing predicates test the entire list. By your definition, though, a hill is neither entirely increasing nor entirely decreasing. I would modify these predicates to have two arguments instead of one. The additional argument would be bound to the tail of the list which is not does not satisfy the increasing/decreasing criteria. Then, I'd modify hill slightly to use the new argument of increasing to test decreasingness not of the entire list, but of the portion after the initial increasing subsequence. Finally, I would use the new argument of decreasing to verify that there are no non-decreasing elements after the decreasing subsequence.
If you need better hints, or if I seem to be talking nonsense (quite possible as I'm not that good with Prolog), just let me know and I'll try to clarify more.
Edit based on OP's comments: Alright, let's try something else. L is a hill if and only if L is a list of at least two monotone increasing elements ending with some element M, followed by a list of at least one monotone decreasing element starting with some element N, where N < M. Can you translate that description to Prolog clauses?
Edit take two (SPOILER WARNING):
In your revised code, drop these three predicates: increasing([])., hill([])., and hill(List) :- decreasing(List).. This will almost give you a solution, but it will still fail, e.g. on [3, 2, 1]. Fixing this should be fairly easy, though.
Use clpfd!
:- use_module(library(clpfd)).
We don't need to worry about getting recursion right if we use append/3 and chain/2 like this:
hill(Zs) :-
Ascending0 = [_|_],
Descending = [M,_|_],
append(Ascending0,Descending,Zs),
append(Ascending0,[M],Ascending),
chain(Ascending ,#<),
chain(Descending,#>).
Let's run the queries the OP gave!
?- hill([1,2,5,8,11,6,3,-1]).
true % as expected
; false.
?- hill([1,2,5,8,11,6,9,3,-1]).
false. % as expected
?- hill([1,2,3,4,5,6]).
false. % as expected
hill(L1) :- concatenate(L2,L3,L1), inc(L2), dec(L3).
dec([X|[Y|[]]]) :- X > Y.
dec([X|[Y|L]]) :- X > Y, dec([Y|L]).
inc([X|[Y|[]]]) :- Y > X.
inc([X|[Y|L]]) :- Y > X, inc([Y|L]).
concatenate([],L2,L2).
concatenate([X|L1],L2,[X|L3]) :- concatenate(L1,L2,L3).
This works :)