Python图形化Blackjack游戏:实现游戏循环重置的技术问询
解决Blackjack游戏New Game按钮无法重置的问题
我看了你的Blackjack代码,问题主要出在没有统一管理游戏状态和重置逻辑,而且New Game按钮的点击判断完全没生效。咱们一步步来解决这个问题:
核心问题分析
- 元素无统一管理:你直接绘制手牌文本、总分文本,但没保存引用,重置时无法批量清除旧内容
- New Game按钮逻辑错误:代码里判断的是第一次点击的
s变量,而非主循环里的clickPoint,永远触发不了重置 card_value()函数bug:直接用全局total判断Ace价值,后续抽牌时计算错误,需传入当前手牌总分作为参数- 缺少重置函数:初始化逻辑线性执行,无法回到初始状态
修复后的完整代码
import graphics as gr import random win = gr.GraphWin("Blackjack", 700, 700) win.setCoords(0.0, 0.0, 61.0, 80.0) # 初始化固定UI元素(不需要重置的部分) def init_static_ui(): # Game Title ptitle = gr.Point(30, 77) title = gr.Text(ptitle, "Black Jack") title.draw(win) # Player/Dealer Titles playerp = gr.Point(10, 70) player_title = gr.Text(playerp, "Player") player_title.draw(win) dealerp = gr.Point(50, 70) dealer_title = gr.Text(dealerp, "Dealer") dealer_title.draw(win) # Money Display money_sign = gr.Text(gr.Point(27,70), "$").draw(win) global player_money, money_point player_money = 100 money_point = gr.Text(gr.Point(30, 70), player_money) money_point.draw(win) # Card Slots (玩家和庄家的牌框) global player_slots, dealer_slots, player_text_points, dealer_text_points player_slots = [] for x in range(1, 20, 10): for y in range(20, 68, 8): rect = gr.Rectangle(gr.Point(x, y), gr.Point(x + 10, y + 8)) rect.draw(win) player_slots.append(rect) dealer_slots = [] for x in range(40, 60, 10): for y in range(20, 68, 8): rect = gr.Rectangle(gr.Point(x, y), gr.Point(x + 10, y + 8)) rect.draw(win) dealer_slots.append(rect) # 文本位置标记 player_text_points = [] for x in range(6, 20, 10): for y in range(23, 68, 8): player_text_points.append(gr.Point(x, y)) dealer_text_points = [] for x in range(45, 60, 10): for y in range(23, 68, 8): dealer_text_points.append(gr.Point(x, y)) # 按钮 global hitbox, standB, newbox hitbox = gr.Rectangle(gr.Point(25, 55), gr.Point(35, 65)) hitbox.draw(win) hitButton = gr.Text(gr.Point(30, 60), "Hit") hitButton.draw(win) standB = gr.Rectangle(gr.Point(25, 40), gr.Point(35, 50)) standB.draw(win) standTextp = gr.Text(gr.Point(30, 45), "Stand") standTextp.draw(win) newbox = gr.Rectangle(gr.Point(25.5, 5), gr.Point(35.5, 15)) newbox.draw(win) newButton = gr.Text(gr.Point(30.5, 10), "New Game") newButton.draw(win) # 总分标签(固定文本) gr.Text(gr.Point(10, 10), "Player Hand Total:").draw(win) gr.Text(gr.Point(50, 10), "Dealer Hand Total:").draw(win) # 生成牌堆 def card_deck(): card_value = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] card_type = ['Hearts', 'Spades', 'Clubs', 'Diamonds'] deck = [] for i in card_type: for j in card_value: deck.append(j + ' of ' + i) return deck # 计算单张牌的价值(修正:传入当前总分判断Ace的价值) def card_value(card, current_total): card_prefix = card.split()[0] if card_prefix in ('J', 'Q', 'K', '10'): return 10 elif card_prefix in ('2', '3', '4', '5', '6', '7', '8', '9'): return int(card_prefix) elif card_prefix == 'Ace': return 11 if current_total <= 10 else 1 # 重置游戏状态 def reset_game(): global game_elements, player_hand, dealer_hand, player_total, dealer_total, handcount, dealercount # 清除所有需要重置的元素 for elem in game_elements: elem.undraw() game_elements = [] # 初始化手牌和计数 player_hand = [] dealer_hand = [] player_total = 0 dealer_total = 0 handcount = 0 dealercount = 0 # 发玩家初始两张牌 for _ in range(2): card = random.choice(card_deck()) player_hand.append(card) card_text = gr.Text(player_text_points[handcount], card) card_text.setSize(10) card_text.draw(win) game_elements.append(card_text) player_total += card_value(card, player_total) handcount += 1 # 发庄家初始两张牌 for _ in range(2): card = random.choice(card_deck()) dealer_hand.append(card) card_text = gr.Text(dealer_text_points[dealercount], card) card_text.setSize(10) card_text.draw(win) game_elements.append(card_text) dealer_total += card_value(card, dealer_total) dealercount += 1 # 绘制总分 global player_total_text, dealer_total_text player_total_text = gr.Text(gr.Point(10, 6), player_total) player_total_text.draw(win) game_elements.append(player_total_text) dealer_total_text = gr.Text(gr.Point(50, 6), dealer_total) dealer_total_text.draw(win) game_elements.append(dealer_total_text) # 判断点击是否在按钮内 def inside(point, rectangle): ll = rectangle.getP1() ur = rectangle.getP2() return ll.getX() < point.getX() < ur.getX() and ll.getY() < point.getY() < ur.getY() # 初始化固定UI和游戏状态 init_static_ui() game_elements = [] reset_game() # 主游戏循环 while True: clickPoint = win.getMouse() if clickPoint is None: break # 处理Hit按钮 if inside(clickPoint, hitbox): # 清除旧总分 player_total_text.undraw() game_elements.remove(player_total_text) # 抽新牌 card = random.choice(card_deck()) player_hand.append(card) card_text = gr.Text(player_text_points[handcount], card) card_text.setSize(10) card_text.draw(win) game_elements.append(card_text) # 更新总分 player_total += card_value(card, player_total) player_total_text = gr.Text(gr.Point(10, 6), player_total) player_total_text.draw(win) game_elements.append(player_total_text) handcount += 1 # 判断是否爆牌 if player_total > 21: bust_text = gr.Text(gr.Point(30, 20), "Player Busts!") bust_text.draw(win) game_elements.append(bust_text) # 更新金钱 global player_money, money_point money_point.undraw() player_money -= 10 money_point = gr.Text(gr.Point(30, 70), player_money) money_point.draw(win) # 处理Stand按钮(这里可以补充庄家抽牌逻辑) elif inside(clickPoint, standB): # 你可以在这里添加庄家自动抽牌的逻辑,然后判断胜负 pass # 处理New Game按钮 elif inside(clickPoint, newbox): reset_game()
关键改动说明
- 拆分UI为固定和可变部分:
init_static_ui()负责绘制标题、按钮、牌框等不需要重置的元素,避免重复绘制。 - 游戏元素统一管理:用
game_elements列表存储所有需要重置的文本元素,重置时批量清除。 reset_game()函数:负责清除旧元素、重新初始化手牌、总分和计数,重新发初始牌。- 修正
card_value():传入当前手牌总分作为参数,正确判断Ace的价值。 - 修复New Game按钮逻辑:在主循环里检测点击是否在New Game按钮区域,调用
reset_game()。
内容的提问来源于stack exchange,提问作者K. Mo3r
相关产品推荐
相关产品推荐

