Lottery Analysis Exercise from Python Crash Course (Eric Matthes)

Hey guys, I’m new to Python so apologies for my ignorance.

I’m currently going through Python Crash Course (3rd Edition) and I’m stuck on exercise 9:15 (Lottery Analysis)

Here is the exercise:

9-15. Lottery Analysis: You can use a loop to see how hard it might be to win the kind of lottery you just modeled. Make a list or tuple called my_ticket. Write a loop that keeps pulling numbers until your ticket wins. Print a message reporting how many times the loop had to run to give you a winning ticket.

I’ve checked out the author’s solution here. I’m not fully comfortable with my understanding on his solution based upon what’s been taught so far throughout the book.

I’m wondering if you guys could advise me on where I can further my understanding on how to answer this question.

Thanks, Taylor.

Which parts are you having trouble with? Without more targeted questions it’s difficult to guess which part is tripping you up.

3 Likes

Sorry I wasn’t direct with my issue.

I will post Eric’s solution in full first and then quote that which is unclear to me, here is his solution:

from random import choice

def get_winning_ticket(possibilities):
    """Return a winning ticket from a set of possibilities."""
    winning_ticket = []

    # We don't want to repeat winning numbers or letters, so we'll use a
    #   while loop.
    while len(winning_ticket) < 4:
        pulled_item = choice(possibilities)

        # Only add the pulled item to the winning ticket if it hasn't
        #   already been pulled.
        if pulled_item not in winning_ticket:
            winning_ticket.append(pulled_item)

    return winning_ticket

def check_ticket(played_ticket, winning_ticket):
    # Check all elements in the played ticket. If any are not in the 
    #   winning ticket, return False.
    for element in played_ticket:
        if element not in winning_ticket:
            return False

    # We must have a winning ticket!
    return True

def make_random_ticket(possibilities):
    """Return a random ticket from a set of possibilities."""
    ticket = []
    # We don't want to repeat numbers or letters, so we'll use a while loop.
    while len(ticket) < 4:
        pulled_item = choice(possibilities)

        # Only add the pulled item to the ticket if it hasn't already
        #   been pulled.
        if pulled_item not in ticket:
            ticket.append(pulled_item)

    return ticket


possibilities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'a', 'b', 'c', 'd', 'e']
winning_ticket = get_winning_ticket(possibilities)

plays = 0
won = False

# Let's set a max number of tries, in case this takes forever!
max_tries = 1_000_000

while not won:
    new_ticket = make_random_ticket(possibilities)
    won = check_ticket(new_ticket, winning_ticket)
    plays += 1
    if plays >= max_tries:
        break

if won:
    print("We have a winning ticket!")
    print(f"Your ticket: {new_ticket}")
    print(f"Winning ticket: {winning_ticket}")
    print(f"It only took {plays} tries to win!")
else:
    print(f"Tried {plays} times, without pulling a winner. :(")
    print(f"Your ticket: {new_ticket}")
    print(f"Winning ticket: {winning_ticket}")

In Eric’s solution here:

def check_ticket(played_ticket, winning_ticket):
    # Check all elements in the played ticket. If any are not in the 
    #   winning ticket, return False.
    for element in played_ticket:
        if element not in winning_ticket:
            return False

    # We must have a winning ticket!
    return True

I don’t understand the value of played_ticket or its purpose. Likewise the purpose of returning True.

Then secondly I see that in Eric’s solution he generates a ticket for himself in the following code:

def make_random_ticket(possibilities):
    """Return a random ticket from a set of possibilities."""
    ticket = []
    # We don't want to repeat numbers or letters, so we'll use a while loop.
    while len(ticket) < 4:
        pulled_item = choice(possibilities)

        # Only add the pulled item to the ticket if it hasn't already
        #   been pulled.
        if pulled_item not in ticket:
            ticket.append(pulled_item)

    return ticket

I’m wondering if I created a list called my_ticket with 4 numbers from ‘possibilities’, how would one run a loop that pulls numbers until it matches my_ticket? Instead of generating a ticket for myself.

Thank you.

That’s not how the lottery works, unfortunately :joy:

[Editorializing: I have to say, I do not like the “solution” code of your course very much. It’s correct, yes, but not elegant or concise, and it’s less understandable than it could be. ]

def check_ticket(played_ticket: list, winning_ticket: list):
      # Are all the numbers (or letters) of the played ticket 
      # also in winning_ticket? Return True if that is so.
      return all(x in winning_ticket for x in played_ticket)

Sets would have been much more appropriate for this problem, since a “ticket” needs to contain unique items (and since ordering of those doesn’t matter). If sets had been used you could do:

def check_ticket(played_ticket: set, winning_ticket: set):
    return played_ticket == winning_ticket    # as simple as that

With lists as tickets you can actually also do:

def check_ticket(played_ticket: list, winning_ticket: list):
      # Are all the numbers (or letters) of the played ticket 
      # also in winning_ticket? Return True if that is so.
      return set(played_ticket) == set(winning_ticket)

In the solution the ‘while’ block is a loop in which at every step a new random ticket (with 4 items) is made, and each time it checks again to see if that ticket was winning.

while not won:
    new_ticket = make_random_ticket(possibilities)
    won = check_ticket(new_ticket, winning_ticket)
    plays += 1
    if plays >= max_tries:
        break

If you already had created a particular random ticket, you won’t need to loop: you could just call check_ticket(my_ticket, winning_ticket). Inside the check_ticket function, you can see it’s looping again (checking all the numbers or letters of the ticket against the number of the winning_ticket), using a “for” loop, rather than “while” loop. (Or as in my version, using “all” which is an implicit looping construct. Do help(all) to see. A check like set(a) == set(b) will under the cover also contain a loop, since it needs to check that all elements of a or in b and vice-versa.)

1 Like

I think that exposes the fact I’ve never done the lottery before :joy:

Thank you for the help, much appreciated!