循环在第三次迭代开始时结束
你好,正在阅读这段话的你,我现在在调试我的代码,卡在一个奇怪的错误上。
我为这个项目使用了两个主要文件,一个叫做 logic.py,一个叫做 card.py。整个游戏循环依赖两个变量为真,match_going 和 PlayerTurn。我在继续游戏提示中确保把这些值设为True,但在程序的第三次循环时,它会执行 startMatch(),然后结束程序。
请见下方的期望结果。我在GitHub上的代码位于bin文件夹,可以在此处查看 这里。此外,还有一个Pastebin链接在这里 --> https://paste.pythondiscord.com/7RKQ 我今晚可以上传一个调试器输出的视频。我已经把导致问题的主要代码放在下面,我完全知道 我的游戏循环代码真的很不规范。我想知道为什么我的代码不会返回到while循环,
#This code is ran before the code above
while match_going and PlayerTurn:
# Grab input inside the loop so it asks every time
player_input = input("Stand or Hit:\n").lower()
if player_input == "hit":
deck.draw_card(Player_Hand,"Player")
player_score = deck.ScoreCard(Player_Hand)
print("Player's Hand Score Currently:\n", player_score)
# Check if they busted
if player_score > 21:
print("Past 21! You busted...")
PlayerTurn = False
match_going = False
elif player_input == "stand":
PlayerTurn = False
print("**Dealer's Turn**")
deck.draw_card(Dealer_Hand,"Dealer")
dealer_score = deck.ScoreCard(Dealer_Hand)
# Dealer must hit until they beat 16 or land on 16
while dealer_score < 16:
deck.draw_card(Dealer_Hand,"Dealer")
dealer_score = deck.ScoreCard(Dealer_Hand)
if dealer_score == 16 and player_score > dealer_score:
print("You win!")
match_going = endMatch()
WinCounter += 1
if dealer_score == 16 and dealer_score > player_score:
print("Dealer Wins!")
match_going = endMatch()
if dealer_score >= player_score and dealer_score <= 21:
print("Dealer wins!")
match_going = endMatch()
elif dealer_score < player_score and player_score <= 21:
print("You win!")
match_going = endMatch()
WinCounter += 1
elif dealer_score > 21:
print("Dealer bust you win!")
match_going = endMatch()
WinCounter += 1
elif dealer_score == player_score:
print("Match was a draw!")
match_going = endMatch() # Ends game loop
print("Current Win Streak:",WinCounter)
user_continue_match = str(input("\nContinue Playing? Y/N").upper())
if user_continue_match == "Y":
reset()
match_going = True
PlayerTurn = True
startMatch()
player_score = deck.ScoreCard(Player_Hand)
dealer_score = deck.ScoreCard(Dealer_Hand)
if user_continue_match == "N":
print("Your Are Safe To Close Program")
#This runs in the same file after match_going & PlayerTurn has been set to false
预期结果:
程序应一直运行,直到用户输入“ N ”。也就是说,程序会不断返回到logic.py第 53行所在的while循环。
实际情况:
程序提前结束,在执行完第103行的if语句后不会跳回到第53行。
如果有人能提供帮助那就太好了。我在Python Discord请求帮助,结果却得到了一些让人困惑的回复。
解决方案
我运行了你的代码,发现了两个问题:
- 如果你在文件
logic.py的开头放入类似print('run logic.py')的内容,你会看到它会执行两次。这很奇怪。但我发现问题出在在logic.py处你运行了deck.draw_card(...),它包含第import logic as Logic行,这会让logic.py第二次执行——循环会执行两次,但本应只执行一次(这是第二个错误)。即使你为Continue Playing选择了N,它也会再次运行。
如果你把card.py中的两个位置的所有 import logic as Logic 去掉,这个问题就解决了。坦率地说,你在 card 里其实并不需要这个 logic。
顺便说一句:一个很好的规则是在文件开头放置所有的 import,这样有助于看清这个文件还使用了哪些其他模块。
- 第二个问题是你的
while循环和Continue Playing——它应该只执行一次,因为你需要把它放到另一个/外部的while循环中(例如while True),并在用户为Continue Playing选择N时使用break来退出它。
# --- external loop
while True:
# -- inner loop
while match_going and PlayerTurn:
# ... code ...
# --- after inner loop
user_continue_match = input("\nContinue Playing? Y/N").upper()
if user_continue_match == "Y":
# ... code ...
else:
break # exit external loop
最终你也可以为此再使用一个变量
# --- before external loop
running = True
# --- external loop
while running:
# --- inner loop
while match_going and PlayerTurn:
# ... code ...
# --- after inner loop
user_continue_match = input("\nContinue Playing? Y/N").upper()
if user_continue_match == "Y":
# ... code ...
else:
running = False # exit external loop
用于测试的完整可运行代码(包含其他改动):
我使用了 Linux,因此为Linux终端添加了颜色代码。
logic.py
# -----
import platform
# colors for linux terminal
COLOR = (platform.system() == 'Linux')
C_R = "\033[31;1m" # red bold/bright
C_G = "\033[32;1m" # green bold/bright
C_X = "\033[m" # reset
def debug(text):
if COLOR:
print(f"{C_R}[DEBUG]: {text}{C_X}")
else:
print(f"[DEBUG]: {text}")
# -----
debug("run logic.py")
import random
import card as deck
# --- functions ---
def reset(): # NOTE: Purpose of this function is to reset values that need to be used in the next loop
debug("reset")
player_hand.clear()
dealer_hand.clear()
total_hand_score = 0
dealer_score = 0
dealer_score = 0
player_score = 0
return (
player_hand,
dealer_hand,
total_hand_score,
dealer_score,
dealer_score,
player_score,
)
def start_match():
debug("start_match")
deck.draw_card(player_hand, "Player")
deck.draw_card(player_hand, "Player")
deck.draw_card(dealer_hand, "Dealer")
print("Current Dealer Hand \n", dealer_hand)
print("Current Player Hand\n", player_hand)
return True
def end_match():
debug("end_match")
return False
# --- main ---
# Functions to be called throughout the game multiple times#
# deck.draw_card((hand you are giving the card to), "Text you want to print out")
# deck.score_card((hand you are scoring aka dealer_hand or player_hand))
# Variables
player_hand = []
dealer_hand = []
match_going = True
player_turn = True
total_hand_score = 0
dealer_score = 0
running = True
while running:
debug("run external loop")
start_match()
dealer_score = deck.score_card(dealer_hand)
player_score = deck.score_card(player_hand)
print("Dealer's Hand Score:\n", dealer_score)
print("Player's Hand Score:\n", player_score)
while match_going and player_turn:
debug("run inner loop")
# Grab input inside the loop so it asks every time
player_input = input("[S]tand or [H]it:\n").lower()
if player_input in ("hit", "h"): # I prefer single `h` instead of `hit`
deck.draw_card(player_hand, "Player")
player_score = deck.score_card(player_hand)
print("Player's Hand Score Currently:\n", player_score)
# Check if they busted
if player_score > 21:
print("Past 21! You busted...")
player_turn = False
match_going = False
elif player_input in ("stand", "s"): # I prefer single `s` instead of `stand`
player_turn = False
print("**Dealer's Turn**")
deck.draw_card(dealer_hand, "Dealer")
dealer_score = deck.score_card(dealer_hand)
# Dealer must hit until they beat 16
while dealer_score <= 16:
deck.draw_card(dealer_hand, "Dealer")
dealer_score = deck.score_card(dealer_hand)
if dealer_score >= player_score and dealer_score <= 21:
print("Dealer wins!")
match_going = end_match()
elif dealer_score < player_score and player_score <= 21:
print("You win!")
match_going = end_match()
elif dealer_score > 21:
print("Dealer bust you win!")
match_going = end_match()
if dealer_score == player_score:
print("Match was a draw!")
match_going = end_match() # Ends game loop
# --- after inner loop
debug("after inner loop")
user_continue_match = input("Continue Playing? Y/N").upper()
if user_continue_match == "Y":
(
player_hand,
dealer_hand,
total_hand_score,
dealer_score,
dealer_score,
player_score,
) = reset()
match_going = True
player_turn = True
elif user_continue_match == "N":
running = False # exit external loop and exit program
# --- after external loop
print("Your Are Safe To Close Program")
debug("end of file")
card.py
import random
card_faces = ["King", "Queen", "Jack"]
card_types = ["Spades", "Diamonds", "Hearts", "Clubs"]
card_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# def withdrawl(hand): # send `player_hand` as parameter, don't use global variable
# hand.clear()
# def deal(cards_wanted, hand, player_hand, dealer_hand):
#
# for cards_needed in range(cards_wanted):
#
# if hand[0] == dealer_hand[0]:
# print("Drawing For Dealer")
# draw_card(dealer_hand, "Dealer")
# if hand == player_hand:
# draw_card(player_hand, "Player")
#
# return hand
def draw_card(hand, user_name):
# TODO: create list with all_cards, random.shuffle(all_card), and get cards from all_cards - to make sure cards are unique
drawn_type = random.choice(card_types)
probe = random.uniform(0, 1)
if probe <= 0.23:
drawn_face = random.choice(card_faces)
drawn_card = f"{drawn_face} of {drawn_type}"
else:
drawn_number = random.choice(card_numbers)
if drawn_number == 1:
drawn_number = "Ace"
drawn_card = f"{drawn_number} of {drawn_type}"
hand.append(drawn_card)
print(user_name, "has drawn a: \n", drawn_card)
return drawn_card, hand
def score_card(hand):
total_hand_score = 0
for current_card in hand:
first_char = current_card[0]
if first_char in ["2", "3", "4", "5", "6", "7", "8", "9"]:
total_hand_score += int(first_char)
elif first_char in ["1", "K", "Q", "J"]: # `1` instead of `10`
total_hand_score += 10
elif first_char in ["A"]:
total_hand_score += 0
else:
print("unknown card:", current_card)
return total_hand_score