Aplikacja loteria - losowanie zwycięzców

0

Cześć,
jestem początkujący, przerabiam różne materiały i stanąłem przed zadaniem, które ma polegać na stworzeniu aplikacji a'la loterii. Na ten moment należy:

  1. Wczytać dane z zewnętrznych plików (json/csv). Dane zawierają spis uczestników loterii (ID, imie, nazwisko oraz opcjonalnie wagę (waga miałaby póżniej pozwalać na zmianę prawdopodobieństwa wylosowania uczestnika loterii).
  2. Pozwolić użytkownikowi wybrać czy ma losować z pliku z wagami czy bez (domyślnie z pliku json ale ma byc tez dostepna funkcja do pobrania z csv)
  3. Pozwolić użytkownikowi wybrać liczbę zwycięzców z przedziału
  4. Wylosować z wczytanych danych taką liczbę zwycięzców jaką wybrał użytkownik
  5. Wypisać wylosowanych zwycięzców

Tak jak napisałem jestem początkujący dopiero zaczynam i chciałem prosić o sprawdzenie napisanego kodu oraz o pomoc w przypadku losowania podanej przez uzytkownika liczby zwycięzców z wczytanych danych bo się tutaj zablokowałem i nie wiem za bardzo jak to ugryźć. Zapewne są błedy, jednak prosiłbym o konstruktywną krytykę.

Kod:

# Import modules
import csv
import json
import random


# Load JSON files - participants without weights
def load_json_wow():
    with open('participants1.json.', 'r', encoding='utf-8') as jsonfile:
        participants = json.load(jsonfile)
        for row in participants:
            print('\n ', 'ID:', row['id'])
            print('First Name:', row['first_name'])
            print('Last Name:', row['last_name'])


# Load JSON files - participants with weights
# (The weights are to enable the control of the probability of a given participant being drawn.)
def load_json_ww():
    with open('participants2.json.', 'r', encoding='utf-8') as jsonfile:
        participants = json.load(jsonfile)
        for row in participants:
            print('\n ', 'ID:', row['id'])
            print('First Name:', row['first_name'])
            print('Last Name:', row['last_name'])
            print('Weight:', row['weight'])


# Load CSV files - participants without weights
def load_csv_wow():
    with open('participants1.csv.', 'r', encoding='utf-8') as csvfile:
        participants = csv.DictReader(csvfile)
        for row in participants:
            print('\n ', 'ID:', row['id'])
            print('First Name:', row['first_name'])
            print('Last Name:', row['last_name'])


# Load CSV files - participants with weights
# (The weights are to enable the control of the probability of a given participant being drawn.)
def load_csv_ww():
    with open('participants2.csv.', 'r', encoding='utf-8') as csvfile:
        participants_w = csv.DictReader(csvfile)
        for row in participants_w:
            print('\n ', 'ID:', row['id'])
            print('First Name:', row['first_name'])
            print('Last Name:', row['last_name'])
            print('Weight:', row['weight'])


def ask_yes_no(question):
    """Ask the question yes or no"""
    response = None
    while response not in ("y", "n"):
        response = input(question).lower()
    return response


def ask_number(question, low, high):
    """Enter the number of winners"""
    response = None
    while response not in range(low, high):
        response = int(input(question))
    return response


def draw_winners_wow():
    """Draw the winners from the indicated range"""
    winner = ask_number("Choose the number of winners (1 - 10):", 1, 10)


def draw_winners_ww():
    """Draw the winners from the indicated range"""
    winner = ask_number("Choose the number of winners (1 - 10):", 1, 10)


choice = None

# The loop of lottery menu
while choice != 0:
    print(
        """
    The lottery menu

    0 - Close the application
    1 - Choose a file with or without weights
    """
    )
    choice = input("Choose: ")

    # Choice 0 - Exit the application
    if choice == "0":
        input("\nPress 'Enter' to close the application: ")
        break

    # Choice 1 - choose a file with or without weights
    elif choice == "1":
        choose = ask_yes_no("To choose a file without weights press y, otherwise press n. (y/n): ")

        # Load the function with the JSON file without weights
        if choose == "y":
            draw_winners_wow()

        # Load the function with the JSON file with weights
        elif choose == "n":
            draw_winners_ww()

        # The user selected an undefined option.
        else:
            print("\nSomething went wrong! Try again please.")

    # The user selected an undefined option.
    else:
        print("\nSomething went wrong! Try again please.")

0

Ciekawe... chyba byłem zmęczony... siadłem teraz nad tym i działa :D

Mierze sie teraz jednak z innym problemem, otóż próbuje w funkcji def load_json_ww() zastosować losowanie z wagami, ale kiedy probuje uzyc random.choices() to wyskakują mi różne błędy np.

Traceback (most recent call last):
  /Skrypt_venv/skrypt.py", line 112, in <module>
    load_json_ww()
 /Skrypt_venv/skrypt.py", line 28, in load_json_ww
    resume = random.choices(participants, weights=row["weight"], k=winner)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\lib\random.py", line 404, in choices
    raise ValueError('The number of weights does not match the population')
ValueError: The number of weights does not match the population

Moja funkcja wygląda obecnie tak:

# Load JSON files - participants with weights
# (The weights are to enable the control of the probability of a given participant being drawn.)
def load_json_ww():
    with open("data\\participants2.json.", "r", encoding="utf-8") as jsonfile:
        participants = json.load(jsonfile)
        winner = ask_number("Choose the number of winners (1 - 10):", 1, 10)
        for row in participants:
            id_lottery = row["id"]
            weight = row["weight"]
            #print(weight)
            #print(id_lottery)
            resume = random.choices(population=id_lottery, weights=weight, k=winner)
            print("\n ", "ID:", row["id"])
            print("First Name:", row["first_name"])
            print("Last Name:", row["last_name"])
            print("Weight:", row["weight"])

W pliku mam dokłądnie 30 id i do każdego po jednej wadze. Nie wiem właśnie skąd taki błąd. Może trzeba się jakoś inaczej dostać do danych z listy...

0

Wydaje mi się że sobie poradziłem z problemem, przynajmniej tak wynika z printa, ale pojawia mi się nowy błąd...
Robie to teraz w ten sposób:

def load_json_ww():
    path = Path.cwd() / "data" / "participants2.json"
    with path.open() as path:
        participants = json.load(path)
        participant = {}
        ids = []
        weights = []
        for participant in participants:
            ids.append(participant['id'])
            weights.append(participant['weight'])
        print("ID", ids, "WAGI", weights, "Wszystko", participants)
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.choices(population=ids, weights=weights, k=winner)
        for row in resume:
            print("\n ", "ID:", row["id"])
            print("First Name:", row["first_name"])
            print("Last Name:", row["last_name"])
            print("Weight:", row["weight"])

Jednak rzuca takim błędem:

total = cum_weights[-1] + 0.0   # convert to float
TypeError: can only concatenate str (not "float") to str

EDIT: To też udało się załatwić:

def load_json_ww():
    path = Path.cwd() / "data" / "participants2.json"
    with path.open() as path:
        participants = json.load(path)
        weights = []
        for participant in participants:
            weights.append(int(participant['weight']))
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.choices(population=participants, weights=weights, k=winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()

Pojawił mi się też nowy problem ponieważ muszę dostać się do zagnieżdżonej wartości słownikowej... struktura danych w kolejnym jsonie wygląda tak:

{'name': 'Item giveaway: 5 identical prizes', 'prizes': [{'id': 1, 'name': 'Annual Vim subscription', 'amount': 5}]}

Potwierdziłem sobie, że typ to dict, a klucze do niego to 'name' i 'prizes' i do tych danych nie mam problemu się dostać, mogę wypisać np. to co po 'prizes'. Jak jednak dostać się do danych w prizes - 'name' i 'amount'? Typ tych danych jest wskazywany jako NoneType... Może ma ktos jakieś sugestie?

EDIT: Znalazłem fajny poradnik i z tym nowym problemem poradziłem sobie bez większych problemów.:

def item_giveaway():
    """Load the giveaway prize template"""
    path = Path.cwd() / "data" / "item_giveaway.json"
    with path.open() as path:
        prize = json.load(path)
        print("As a winner you received a prize: ")
        for name_of_prize in prize['prizes']:
            name = print(name_of_prize['name'])
        for amount_of_prizes in prize['prizes']:
            amount = (int(amount_of_prizes['amount']))

Teraz tak name - zwraca nazwę nagrody, a amount max liczbę nagród w puli. Jak teraz to ugryźć, że jak user wybierze 7 zwycięzców to nagroda będzie dodana tylko do wylosowanych pierwszych pięciu, a pozostałych tylko wypisze wyciągając te dane z funkcji def item_giveaway i dodając do load_json_wow()?

0

Napiszę nowy komentarz, żeby było przejrzyście. Obecny cały kod:

# Import modules
import csv
import json
import random
from pathlib import Path
import click

# The template of the 'requirements' text file containing names of external modules
requirements = Path.cwd() / "requirements.txt"
requirements.write_text('External modules:\n')


# Load JSON files - participants without weights
def load_json_wow():
    path = Path.cwd() / "data" / "participants1.json"
    with path.open() as path:
        participants = json.load(path)
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.sample(participants, winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()


# Load JSON files - participants with weights
# (The weights are to enable the control of the probability of a given participant being drawn.)
def load_json_ww():
    path = Path.cwd() / "data" / "participants2.json"
    with path.open() as path:
        participants = json.load(path)
        weights = []
        for participant in participants:
            weights.append(int(participant['weight']))
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.choices(population=participants, weights=weights, k=winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()


# Load CSV files - participants without weights
def load_csv_wow():
    path = Path.cwd() / "data" / "participants1.csv"
    with open(path) as path:
        participants = csv.DictReader(path)
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.sample(list(participants), winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()


# Load CSV files - participants with weights
# (The weights are to enable the control of the probability of a given participant being drawn.)
def load_csv_ww():
    """Load a CSV file - participants with weights and draw chosen number of winners"""
    path = Path.cwd() / "data" / "participants2.csv"
    with open(path) as path:
        participants = list(csv.DictReader(path))
        weights = []
        for participant in participants:
            weights.append(int(participant['weight']))
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.choices(population=participants, weights=weights, k=winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()


def ask_yes_no(question):
    """Ask the question yes or no"""
    response = None
    while response not in ("y", "n"):
        response = input(question).lower()
    return response


def ask_number(question, low, high):
    """Enter the number of winners"""
    response = None
    while response not in range(low, high):
        response = int(input(question))
    return response


def item_giveaway():
    """Load the giveaway prize template"""
    path = Path.cwd() / "data" / "item_giveaway.json"
    with path.open() as path:
        prize = json.load(path)
        print("As a winner you received a prize: ")
        for name_of_prize in prize['prizes']:
            name = print(name_of_prize['name'])
        for amount_of_prizes in prize['prizes']:
            amount = (int(amount_of_prizes['amount']))


def separate_prizes():
    """Load the separate prize template"""
    path = Path.cwd() / "data" / "separate_prizes.json"
    with path.open() as path:
        prize = json.load(path)
        print("As a winner you received a prize: ")
        for name_of_prize in prize['prizes']:
            name = print(name_of_prize['name'])
            amount = (int(name_of_prize['amount']))


choice = None

# The loop of the lottery menu
while choice != 0:
    print(
        """
    The lottery menu

    0 - Close the application
    1 - Choose JSON files with or without weights
    2 - Choose CSV files with or without weights
    """
    )
    choice = input("Choose: ")

    # Choice 0 - Exit the application
    if choice == "0":
        input("\nPress 'Enter'' to confirm and close the application: ")
        break

    # Choice 1 - Choose JSON files with or without weights
    elif choice == "1":
        choose = ask_yes_no("To choose JSON file without weights press y, otherwise press n. (y/n): ")

        # Load the function with the JSON file without weights
        if choose == "y":
            load_json_wow()
            # add_item_giveaway()
            # separate_prizes()
        # Load the function with the JSON file with weights
        elif choose == "n":
            load_json_ww()

        # The user selected an undefined option.
        else:
            print("\nSomething went wrong! Try again please.")

    elif choice == "2":
        choose = ask_yes_no("To choose CSV file without weights press y, otherwise press n. (y/n): ")

        # Load the function with the CSV file without weights
        if choose == "y":
            load_csv_wow()

        # Load the function with the CSV file with weights
        elif choose == "n":
            load_csv_ww()

        # The user selected an undefined option.
        else:
            print("\nSomething went wrong! Try again please.")

    # The user selected an undefined option.
    else:
        print("\nSomething went wrong! Try again please.")

Problemy / wyzwania:
1.Funkcja:
def item_giveaway():
zwraca nazwę nagrody i liczbę 5
Funkcja
def separate_prizes():
zwraca
3 nazwy nagród i liczbe 1 do każdej
jak do wylosowanych uczestników przypisać nagrody tak, żeby pierwszych pięciu lub 3 (w przypadku drugiej funkcji) miało wypisane te nagrody?

  1. Random.choices którego musiałem użyć ponieważ musiałem skorzystać z wag (weight) nie zwraca unikalnych wyników, czasami losuje dwie takie same osoby. Jak zabezpieczyć się przed takim czymś? Nie znalazłem po googlowaniu odpowiedzi, większość pisze żeby uzyć random.sample, no ale tu nie ma racji bytu bo wagi.
    Nie znalazłem innego rozwiązania niz uzycie numpy, wtaki sposób działa:
def load_json_ww():
    path = Path.cwd() / "data" / "participants2.json"
    with path.open() as path:
        participants = json.load(path)
        weights = []
        for participant in participants:
            weights.append(int(participant['weight']))
        winner = ask_number("Choose the number of winners (1 - 5):", 1, 6)
        resume = random.choices(population=participants, weights=weights, k=winner)
        print("\nOur reliable lottery machine has chosen lottery winners: ")
        for row in resume:
            lottery_winners = f"\nCongratulations! \n~~ {row['first_name']} {row['last_name']} ~~ You are a winner one"
            print(lottery_winners)
            item_giveaway()
0

Niestety dalej nie wiem jak wywołać funkcję item_giveaway() tak żeby wywołała sie po każdym wylosowanym uczestniku i wyświetliła nazwę nagrody... Pomoże ktoś?

1 użytkowników online, w tym zalogowanych: 0, gości: 1