Структурированные игры в блэкджек в Python 3


Я новичок в программировании, и я делаю какую-то домашнюю работу, чтобы получить больше практического опыта кодирования. Я написал игру на Python 3, и хотел бы пересмотреть код любой и все мои код.

# Simple program simulates Blackjack game.
#   Using method: Top-Down design, spiral development

from random import randrange

def main():
    printIntro()
    player_hand = player()
    dealer_hand = dealer()
    player_win, dealer_win = compare_between(player_hand, dealer_hand)
    printResult(player_hand, dealer_hand, player_win, dealer_win)


def printIntro():
    print("Blackjack (twenty-one) is a casino game played with cards.")
    print("the goal of game is to draw cards that total as close to 21 points, as possibale")
    print("without going over( whose hand > 21 will bust). All face cards count as 10 points,")
    print("aces count as 1 or 11, and all other cards count their numeric value.")
    print("\nFirstly, your turn:")


def player():
    hand = []
    ans = "hit"
    hand.append(card())
    # Ask user whether Hit or Stand?
    # Condition True, if user want to Hit.
    while ans[0] == "h" or ans[0] == "H":
        hand.append(card())
        hand = eval_ace(hand)
        print("Your hand: {0} total = {1}".format(hand, sum(hand)))
        if bust(hand):
            break
        if blackjack(hand):
            break
        ans = input("Do you want to Hit or Stand (H or S)? ")
    return hand


def card():
    # get arbitrary card from 2 to 11.
    shuffle_card = randrange(2, 11 + 1)
    return shuffle_card


def eval_ace(hand):
    # Determine Ace = 1 or 11, relying on total hand. 
    total = sum(hand)
    for ace in hand:
        if ace == 11 and total > 21:
            # at position, where Ace == 11, replace by Ace == 1.
            position_ace = hand.index(11)
            hand[position_ace] = 1
    return hand


def bust(hand):
    # Condition True: if the hand of player (or dealer) > 21.
    total = sum(hand)
    if total > 21:
        return True


def blackjack(hand):
    # Condition True: if the hand of player (or dealer) == 21.
    total = sum(hand)
    if total == 21:
        return True


def dealer():
    hand = []
    hand.append(card())
    while sum(hand) < 18:
        hand.append(card())
        hand = eval_ace(hand)
    return hand


def compare_between(player, dealer):
    total_player = sum(player)
    total_dealer = sum(dealer)
    player_bust = bust(player)
    dealer_bust = bust(dealer)
    player_blackjack = blackjack(player)
    dearler_blackjack = blackjack(dealer)
    player_win = 0
    dealer_win = 0
    # when player (dealer) bust.
    if player_bust:
        if not dearler_blackjack and total_dealer < 21:
            dealer_win += 1
    if dealer_bust:
        if not player_blackjack and total_player < 21:
            player_win += 1
    if player_bust and dealer_bust:
        if total_player > total_dealer:
            player_win += 1
        elif total_dealer > total_player:
            dealer_win += 1
        else:
            player_win == dealer_win
    # when player (dealer) get blackjack.
    if player_blackjack:
        player_win += 1
    if dearler_blackjack:
        dealer_win += 1
    if player_blackjack and dearler_blackjack:
        player_win == dealer_win
    # when total hand of player (dealer) < 21.
    if total_player < 21 and total_dealer < 21:
        if total_player > total_dealer:
            player_win += 1
        elif total_dealer > total_player:
            dealer_win += 1
        else:
            player_win == dealer_win
    return player_win, dealer_win


def printResult(player_hand, dealer_hand, player_win, dealer_win):
    print("\nWe have the result: ")
    print("Player has: {0} total = {1}".format(player_hand, sum(player_hand)))    
    print("Dealer has: {0} total = {1}".format(dealer_hand, sum(dealer_hand)))
    print("player: {} | dealer: {}".format(player_win, dealer_win))


if __name__ == "__main__": main()

Обновление

Через несколько часов, чтобы учиться и применять PEP8. Вот моя версия 2:

# Program simulate Blackjack game.
#   with multiple game
#   Using method: Top-Down design, spiral development

from random import randrange

def main():
    print_intro()
    player_win, dealer_win, game = play_multiple_game()
    final_result(player_win, dealer_win, game)


def print_intro():
    print("Blackjack (twenty-one) is a casino game played with cards.")
    print("the goal of game is to draw cards that total as close to 21 points, as possibale")
    print("without going over (whose hand > 21 will is_bust). All face cards count as 10 points,")
    print("aces count as 1 or 11, and all other cards count their numeric value.")
    print("Firstly, your turn:")
    return None


def play_multiple_game():
    player_win = 0
    dealer_win = 0
    game = 0
    play_again = "yes"
    # Ask user whether continue another game or stop
    # Condition True, if user want to play.
    while (play_again[0] == "y" or play_again[0] == "Y"):
        player_hand = player_turn()
        dealer_hand = dealer_turn()
        player_score, dealer_score = compare_between(player_hand, dealer_hand)
        result_of_this_game(player_hand, dealer_hand)
        if (player_score > dealer_score):
            print("\nPlayer win!")
            player_win += 1
        elif (dealer_score > player_score):
            print("\nDealer win!")
            dealer_win += 1
        else:
            print("\nThis game end in a tie!")
            player_win == dealer_win
        game += 1
        play_again = input("\nDo you want to continue (Y or N)? ")      
    return player_win, dealer_win, game


def player_turn():
    hand = []
    ans = "hit"
    hand.append(take_card())
    # Ask user whether Hit or Stand?
    # Condition True, if user want to Hit.
    while (ans[0] == "h" or ans[0] == "H"):
        hand.append(take_card())
        hand = eval_ace(hand)
        print("\nYour hand: {0} total = {1}".format(hand, sum(hand)))
        if (is_bust(hand) or
            is_blackjack(hand)):
            break
        ans = input("Do you want to Hit or Stand (H or S)?")
    return hand


def take_card():
    # get arbitrary card from 2 to 11.
    shuffle_card = randrange(2, 11 + 1)
    return shuffle_card


def eval_ace(hand):
    # Determine Ace = 1 or 11, relying on total hand. 
    total = sum(hand)
    for ace in hand:
        if (ace == 11 and total > 21):
            # at position, where Ace == 11, replace by Ace == 1.
            position_ace = hand.index(11)
            hand[position_ace] = 1
    return hand


def is_bust(hand):
    # Condition True: if the hand of player (or dealer) > 21.
    total = sum(hand)
    if total > 21:
        return True
    return None


def is_blackjack(hand):
    # Condition True: if the hand of player (or dealer) == 21.
    total = sum(hand)
    if total == 21:
        return True
    return None


def dealer_turn():
    hand = []
    while sum(hand) < 18:
        hand.append(take_card())
        hand = eval_ace(hand)
    return hand


def compare_between(player, dealer):
    total_player = sum(player)
    total_dealer = sum(dealer)
    player_bust = is_bust(player)
    dealer_bust = is_bust(dealer)
    player_blackjack = is_blackjack(player)
    dearler_blackjack = is_blackjack(dealer)
    player_score = 0
    dealer_score = 0
    # when player (dealer) is_bust.
    if player_bust:
        if (not dearler_blackjack and
                total_dealer < 21):
            dealer_score += 1
    if dealer_bust:
        if (not player_blackjack and
                total_player < 21):
            player_score += 1
    if (player_bust and
            dealer_bust):
        if (total_player > total_dealer):
            player_score += 1
        elif (total_dealer > total_player):
            dealer_score += 1
        else:
            player_score == dealer_score
    # when player (dealer) get blackjack.
    if player_blackjack:
        player_score += 1
    if dearler_blackjack:
        dealer_score += 1
    if (player_blackjack and
            dearler_blackjack):
        player_score == dealer_score
    # when total hand of player (dealer) < 21.
    if (total_player < 21 and
            total_dealer < 21):
        if (total_player > total_dealer):
            player_score += 1
        elif (total_dealer > total_player):
            dealer_score += 1
        else:
            player_score == dealer_score
    return player_score, dealer_score


def result_of_this_game(player_hand, dealer_hand):
    print("\nWe have the result: ")
    print("Player has: {0} total = {1}".format(
        player_hand, sum(player_hand)))    
    print("Dealer has: {0} total = {1}".format(
        dealer_hand, sum(dealer_hand)))
    return None


def final_result(player_win, dealer_win, game):
    print("\nThe Final after {} games:".format(game))
    print("player: {} | dealer: {}".format(
        player_win, dealer_win))
    return None


if __name__ == "__main__": main()


Комментарии
2 ответа

Ваш код выглядит хорошо, хорошо документированы и разбивается на мелкие функции. Кроме того, вы использовали if __name__ == "__main__" Что приятно, почти не встречается в beginniner кода. Поздравляем!

Давайте попробуем увидеть, если код может быть улучшен :)

Стиль

Есть официальный стандартный Python стиль руководства называют ПЭП 8. Это настоятельно рекомендуется к прочтению. Он дает рекомендации, помогающие писать код, который можно как читать, так и последовательным. Сообществе Python пытается следовать этим правилам, более или менее строго (ключевой аспект ОПТОСОЗ 8 является то, что оно содержит рекомендации, а не строгие правила, чтобы слепо следовать).

Это касается различных аспектов стиля код: соглашения об именовании, отступы конвенции и т. д.

Вы найдете различные инструменты, чтобы попытаться проверить, является ли ваш код ОПТОСОЗ 8 уступчива и если это не, чтобы попытаться исправить это:


  • pycodestyle пакет (ранее известный как pep8) для проверки кода

  • pep8online чтобы проверить ваш код с помощью онлайн-инструмента

  • autopep8 пакет , чтобы исправить ваш код автоматически

  • Кроме того, это также проверил различные Линта: pylint, pyflakes, flake8и т. д.

В вашем случае, существует не так много, чтобы быть изменены, за исключением функции, имена которых не следуют snake_case правила именования. Например, printIntro должны быть названы print_intro.

Кроме того, другая (последняя) часть ОПТОСОЗ 8 не последовало код:


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

В частности, bust и blackjack функции должны быть однозначно return None в конце (хотя он должен быть даже лучше использовать return False).

Комментарии

Комментарии, строковые литералы, используемые в начале функции/классы/модули, чтобы дать какое-то объяснение для тех, кто читает ваш код. Они также обработаны специальным образом, чтобы быть доступными через __doc__ члена функции/класса/модуля. Вы можете увидеть его в качестве особой формы документов нашли только в начале определения, и это легко получить доступ (что не так # comments like this) например с help.

Кроме того, существуют правила для Python комментарии описано в ПЭП 257. Насколько я могу судить, это не следует так сильно сообществом как ОПТОСОЗ 8 можно, но это все же ссылка стоит прочитать.

Здесь снова, вы найдете инструменты, которые помогут вам таких как pydocstyle (ранее известный как pep257).

(Также, для более подробной документацией вы можете пойти дальше, чем пресный текст и используйте настройки разметки. Пеп 287 дать более подробную информацию об этом, но это не то, что я знаком с).

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

Улучшение bustblackjack) С предыдущими комментариями и многое другое

Из функции:

def bust(hand):
# Condition True: if the hand of player (or dealer) > 21.
total = sum(hand)
if total > 21:
return True

Похоже, мы могли бы добавить return None в конце, что не вернет функция поведения. Однако, если мы будем думать о том, что функция возвращает, True или None кажется немного противоестественным; True или False имеет больше смысла. Изменение этого и документирования его правильно, вы бы что-то вроде:

def bust(hand):
"""Return True if the hand value is bigger than 21, False otherwise."""
total = sum(hand)
if total > 21:
return True
return False

Но тогда, это действительно может быть улучшена значительно, просто возвращаясь total > 21.

def bust(hand):
"""Return True if the hand value is bigger than 21, False otherwise."""
return sum(hand) > 21

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

Обработка ввода пользователя

Вы выполняете проверку типа: play_again[0] == "y" or play_again[0] == "Y" для обработки пользовательского ввода.

Можно упростить логику здесь в 2-разному: play_again[0] in ("y", "Y") или play_again[0].lower() == 'y'.

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

Я попробую продолжить позже...

Ошибка в распределении карт

Насколько я могу понять, когда новую карту дали, просто выбрать значение случайным образом. Тогда вы получите поведение, которое не совсем тот, который вы бы с колодой карт. Действительно, в вашем случае, события независимы. С колодой карт, вероятность получения конкретной карты зависит от предыдущей карты (на крайний случай, после того как вы нарисовали 4 туза, то вероятность выбрать пятый-ноль).

2
ответ дан 23 февраля 2018 в 11:02 Источник Поделиться

Ваш код выглядит хорошо! Вот несколько моментов и ошибка:

Функции переменных против

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

def compare_between(player, dealer):
# *you'll have a problem here if you're expecting more than one person to ever
# have more than one win because you've defined player_win and dealer_win
# locally so they'll never be more than 1
player_win, dealer_win = 0, 0

# I prefer parenthesis, i'm not sure pep8's opinion, and my coworkers hate them :(
if (bust(player)):
if (not blackjack(dealer) and sum(dealer) < 21):
dealer_win += 1
elif (bust(dealer)):
if (not blackjack(player) and sum(player) < 21):
player_win += 1
...
return player_win, dealer_win

Ошибка

*См. комментарии в коде выше.
Для того, чтобы играть несколько игр, затем, и иметь больше, чем одну победу, можно добавить петли в основной, а затем вернуть побед и добавить его в player_wins и dealer_wins внутри main() функция тела.

Петли

Здесь вы сделать переменную при старте, но вы можете просто выполнить петлю и затем установить ans. Это также позволит вам замести условие выхода:

Поворот игрока

def player():
hand = []
while(True):
ans = input("Hit or stay: ")
if(ans=="stay"):
break

hand.append(card())
hand = eval_ace(hand)
print("Your hand: {} total = {}".format(hand, sum(hand)))

# combine conditions with 'and' - 'or'
if(bust(hand) or blackjack(hand)):
break
return hand

Поверните дилера

def dealer():
hand = []
# sum([]) == 0
while (sum(hand) < 18):
hand.append(card())
hand = eval_ace(hand)
return hand

Именования

Он маленький, но постарайтесь быть немного более описательный с вашими именами функций, что большинство функций имеют стиль глагол к ним. player() должно быть что-то вроде players_turn() и card() может быть draw_card(). Чтобы построить от @Josay ответ, если ваше возвращение 0/1 или true/false, то изменения функций намекнуть на тип возвращаемого полезно тоже: bust() становится is_bust().

Это для удобочитаемости и сэкономит вам некоторые имена переменных. Например, может быть, вы хотите использовать card в качестве переменной-то более подходящее.

1
ответ дан 23 февраля 2018 в 12:02 Источник Поделиться