0

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.

false
  • 10,264
  • 13
  • 101
  • 209
Jack Noone
  • 1
  • 1
  • 3

1 Answers1

1
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).
Shon
  • 3,989
  • 1
  • 22
  • 35
  • Thank you so much aBathologist. That is very kind of you to write back to me like this. It's a pity you're not my professor. I still don't understand some aspects of the answer you have given me, probably because of my little knowledge of Prolog, but in the first section: pick_number(N) :- random(1, 50, N). lotto_numbers(Ns) :- length(Ns, 6), select_numbers(Ns). select_numbers([]). select_numbers([N|Ns]) :- pick_number(N), select_numbers(Ns). % ?- ticket_numbers(TNs), lotto_numbers(LNs), TNs = LNs. I doesn't work when I run that in SWI – Jack Noone Mar 10 '15 at 16:21
  • @JackNoone It's possible there's a mistake in my code, and that's why it's not working: But I'm not entirely clear what you're trying to query and what "not working" means here. Are you receiving errors? Simply "false"? Or some error you didn't expect? – Shon Mar 10 '15 at 16:41
  • I used the rules and facts that you have posted above, but when I tried to run it by asking the program if they are equal to each other it returned: 4 ?- ['/Users/JackNoone/Desktop/Prolog/lotto.pl']. % /Users/JackNoone/Desktop/Prolog/lotto.pl compiled 0.00 sec, 1 clauses true. 5 ?- ticket_numbers(TNs), lotto_numbers(LNs), TNs = LNs. ERROR: toplevel: Undefined procedure: ticket_numbers/1 (DWIM could not correct goal) – Jack Noone Mar 10 '15 at 19:34
  • @JackNoone Ah! I see. Sorry, that was a result of some unclarity on my part: that query was just meant to be an example of something I thought wouldn't work. If you look at the predicates I defined, you should see that, just as swipl is telling you, the predicate `ticket_numbers/1` is not defined anywhere. It was just an example predicate I made up for illustrative purposes. I edited my answer to make things clearer. Let me know if you have more trouble or further questions ;) – Shon Mar 10 '15 at 19:47
  • 1
    Thanks, you're very helpful! Just to help me understand the code slightly better, is Ms short for something? and the lotto_ticket(T) and lotto_numbers(L), did you just use T and L yourself or are they linked to something. Sorry for these questions. They probably seem very silly to you, but I am an absolute beginner trying to teach myself. – Jack Noone Mar 10 '15 at 19:57
  • No worries. Those all are just variable names which are chosen more or less arbitrarily, and I was a bit lazy in picking them :P—but they have no relation to any functionality, unless it is because the variable occurs multiple times and is thus linking values occurring in different places together. My thinking in naming the variables: `Ms` is a list of numbers of `M1,M2,...,Mn`, to complement `Ns`, which is list of `N1,N2,...,Nn`. `T` is short for `Ticket` and `L` is short for `LottoNumbers`, but I should have probably just written out the whole names to be more clear. – Shon Mar 10 '15 at 20:02