Игровой автомат в Python 3


Я сделал эту программу, которая имитирует игровой автомат.

import random, time, os

def input_verify(message):
    while True:
        user_input = input(message).lower()
        if user_input in ("yes", "no"):
            return user_input
        print("Invalid Input")

def win(number_of_matches, fruit):
    global balance
    print("Well done! You got", number_of_matches, "of the same fruit!")
    time.sleep(0.5)
    reward = fruits[fruit][1] * number_of_matches
    print("You won £{}!".format(reward))
    balance += reward

fruits = {"apple": [10000, 1], "banana": [7000, 1.5], "lemon": [6000, 1.75], "orange": [5000, 2], "kiwi": [4000, 4],
          "peach": [3000, 6], "avocado": [2000, 10], "grapes": [1000, 20], "mango": [500, 100], "melon": [1, 10000]}
weighted_fruits = [fruit for fruit in fruits for i in range(fruits[fruit][0])]

print("Welcome to my slot machine! Each turn costs £1.")
balance = 10
if os.path.exists("One Armed Bandit.txt"):
    with open("One Armed Bandit.txt", "r") as f:
        contents = f.readlines()
    continue_saved_game = input_verify("Do you want to continue your saved game?")
    if continue_saved_game == "yes":
        balance = float(contents[1].strip())

time.sleep(0.5)
print("\nYour current balance is £{}.\n".format(balance))
time.sleep(1)
while True:
    balance -= 1
    reward = 0
    a, b, c = [random.choice(weighted_fruits) for i in range(3)]
    print("Spinning...")
    for fruit in (a, b, c):
        time.sleep(0.5)
        print(fruit)
    time.sleep(0.5)
    if a == b == c:
        win(3, a)
    elif a == b or a == c or b == c:
        if b == c:
            win(2, c)
        else:
            win(2, a)
    else:
        print("Unlucky. None of your fruits matched each other.")
    time.sleep(0.5)
    print("\nYour current balance is £{}.\n".format(balance))
    time.sleep(0.5)
    replay = input_verify("Do you want to play again?")
    if replay == "no":
        save = input_verify("Do you want to save your game?")
        if save == "yes":
            name = input("What is you name?")
            with open("One Armed Bandit.txt", "w") as f:
                f.write("{}'s Balance:\n{}".format(name, balance))
        break

Мне не нравится, как есть так много time.sleep() звонки, разбросанных на протяжении всей моей код. Есть ли способ, чтобы достичь того же, но в более чистый путь. Кроме того, могли бы вы предложить некоторые способы, чтобы сделать его более эффективным?



609
4
задан 27 января 2018 в 01:01 Источник Поделиться
Комментарии
2 ответа

Спасибо за ваш код,

Вы должны написать код, чтобы придерживаться PEP8 стандарт, по большей части вы сделали это правильно, вы snake_case переменные и имена функций, но вы вложили весь свой импорт на одной линии.

import random, time, os

должно стать

import random
import time
import os

Давать по одной строке на импорт.

Ваш код не хватает главного охранника. Если я импортировать какие-либо функции или классы с вашего текущего кода, ваш игровой автомат будет начать! Как правило, вы просто хотите, чтобы обернуть main код в условном проверить, что выглядит как

if __name__ == "__main__":
main()

где main это функция, которая начинается выполнение программы.

Шаблон можно использовать в коде, опираясь на строковое значение ("да" или "нет"), чтобы определить, какие функции выполняет. Это достаточно стандартный и ничего действительно неправильно с ним, но я бы порекомендовал вместо того, чтобы проверить для этого строковые литералы, чтобы использовать логические значения, которое взято из коротких вспомогательных функций. Быстрый пример.

Вы предлагаете возможность сохранять и загружать состояние игры, это хорошая вещь. Тем не менее, вы сохранить государство в удобочитаемое мода - т. е. "Боба баланс: 24". Если вы полагаетесь на этот формат где-то еще или даже просто показывать его, вы могли бы просто сохранить один номер в файле. Не нужно записывать имя.

Основной код делает много, вы могли бы разорвать этот на вспомогательные функции. Некоторые возможные имена функций, которые выпрыгивают являются.

load_game, save_game, wants_to_save, wants_to_replay

Шаблон можно использовать в коде, опираясь на строковое значение ("да" или "нет"), чтобы определить, какие функции выполняет. Это достаточно стандартный и ничего действительно неправильно с ним, но я бы порекомендовал вместо того, чтобы проверить для этого строковые литералы, чтобы использовать логические значения, которое взято из коротких вспомогательных функций. Быстрый пример.

Ваш текущий код для побуждения для сохранения игры

    replay = input_verify("Do you want to play again?")
if replay == "no":
save = input_verify("Do you want to save your game?")
if save == "yes":
name = input("What is you name?")
with open("One Armed Bandit.txt", "w") as f:
f.write("{}'s Balance:\n{}".format(name, balance))
break

Я хотел бы создать некоторые вспомогательные функции, которые выглядят как

def wants_to_replay():
return input_verify("Do you want to play again?") == "yes"

def wants_to_save():
return input_verify("Do you want to save your game?") == "yes"

def save():
name = input("What is you name?")
with open("One Armed Bandit.txt", "w") as f:
f.write("{}'s Balance:\n{}".format(name, balance))

И тогда код становится

 if not wants_to_replay():
if wants_to_save():
name = input("What is you name?")
with open("One Armed Bandit.txt", "w") as f:
f.write("{}'s Balance:\n{}".format(name, balance))
break

Наличие global переменная-это немного подозрительно. Обычно это означает, что может быть, вы должны использовать класс. Возможно SlotMachine объект.

Было бы неплохо, чтобы иметь возможность инстанцировать игровой автомат объект и вызвать start метод на нем.

slot_machine = SlotMachine(saved_balance)
slot_machine.start()

эта линия,

a, b, c = [random.choice(weighted_fruits) for i in range(3)]

при наличии неиспользуемых переменных, вы должны указать, как таковой, назвав его _
так что эта линия становится

a, b, c = [random.choice(weighted_fruits) for _ in range(3)]

Но потом a, b и c не большие имена переменных. Они имеют небольшой объем и используются сразу после, но нет никаких причин, чтобы не дать им лучшего названия.

Почему бы просто не назвать их all_fruit затем в следующую петлю вы можете просто использовать

for fruit in all_fruit:
...

В следующем разделе вы сравниваете их друг с другом, вы могли бы просто положить их в переменные, такие как

fruit_a, fruit_b, fruit_c = all_fruit

Я думаю, что однобуквенные имена переменных (за исключением _ и петли счетчики) следует избегать любой ценой.

В настоящее время у вас есть все фрукты ценности жестко, то может быть стоит время, чтобы извлечь эти данные в файл, чтобы сделать его проще добавить/удалить новые. Это, наверное, не большая проблема, хотя и может иметь никакой реальной пользы.

Я не уверен, если есть какой-нибудь более точный способ для достижения sleepбез рассеяния вызовы по всему коду. Вы могли бы использовать именованные константы для продолжительности, но не может быть большого значения в этом.

У вас не Комментарии в коде. В print отчетности законом как форма документации, однако и ваши имена переменных (в основном) очень хорошо. Но там могут быть некоторые места для некоторых полезные замечания.

Надеюсь, этот обзор был полезным для вас!

3
ответ дан 27 января 2018 в 11:01 Источник Поделиться

@чаттон уже говорит, что характеристики плодов должны быть сохранены в отдельный файл. Я предлагаю читать их в список namedtupleС. Например, ваш Fruit определение класса будет выглядеть следующим образом:

from collections import namedtuple

Fruit = namedtuple('Fruit', ['name', 'weight', 'reward'])

А потом после прочтения плоды, вы будете иметь список Fruit случаи вроде этого:

fruits = [Fruit(name='apple', weight=10000, reward=1),
Fruit(name='banana', weight=7000, reward=1.5),
Fruit(name='lemon', weight=6000, reward=1.75),
...
Fruit(name='melon', weight=1, reward=10000)]



weighted_fruits = [fruit for fruit in fruits for i in range(fruits[fruit][0])]
...
a, b, c = [random.choice(weighted_fruits) for i in range(3)]

Тебе не нужен этот огромный weighted_fruits список из тысячи элементов, чтобы получить случайных предметов с весами. Вместо этого вы можете использовать random.choices:

weights = [fruit.weight
for fruit in fruits]
while True:
selected_fruits = random.choices(fruits,
k=3,
weights=weights)
...


Используйте счетчик , чтобы получить плоды, которые были выбраны 2 или 3 раза:

most_common_fruit, most_common_fruit_count = (Counter(selected_fruits)
.most_common(n=1)[0])
if most_common_fruit_count == 1:
print("Unlucky. None of your fruits matched each other.")
else:
...


Вместо странно именованную функцию win вы должны иметь что-то вроде этого:

def get_new_balance(original_balance: float,
*,
matches: int,
reward: float) -> float:
return original_balance + reward * matches

Сама не глобальные (очень плохая практика), без печати (она должна быть снаружи) и поставляя сумма вознаграждения напрямую вместо фруктов. Я добавил типа подсказки , а также. Это хорошая практика, чтобы включить их. Вы помогаете себе и другим людям быть явными о том, какие данные должны быть представлены и возвращены из функции. А звездочка означает, что все аргументы, которые следуют после ключевого слова-только сейчас:

if most_common_fruit_count == 1:
print("Unlucky. None of your fruits matched each other.")
else:
balance = get_new_balance(balance,
matches=most_common_fruit_count,
reward=most_common_fruit.reward)


Некоторые другие советы:


  1. Не читал файл сохранения перед просьбой, если пользователь хочет прочитать его.

  2. float(contents[1].strip()) - нет необходимости strip здесь.

  3. reward = 0 никогда не используется.

  4. Избежать хардкодить такие вещи, как 'One Armed Bandit.txt' или Магия чисел, как balance = 10. Вы могли бы поставить их подписи главная функция в качестве параметров по умолчанию.

  5. Можно использовать Ф-строк Если вы находитесь в Python 3.6: print(f"You won £{reward}!").

  6. Стараюсь следовать PEP 8 в стиле руководства. @чаттон уже говорил об импорте в отдельных строках. Кроме того, не должна превышать 79 символов на одной линии и отдельные функции по 2 пустые строки.

  7. open("One Armed Bandit.txt", "r") - можно опустить "r" как это параметр по умолчанию.

1
ответ дан 28 января 2018 в 06:01 Источник Поделиться