From 9b112bfc8e919611d98b1ddd037b0d5b9c363246 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Sat, 23 Aug 2025 18:31:29 +0800 Subject: [PATCH 1/8] first extend my thought --- src/gamesbyexample/liars_pub.py | 302 ++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/gamesbyexample/liars_pub.py diff --git a/src/gamesbyexample/liars_pub.py b/src/gamesbyexample/liars_pub.py new file mode 100644 index 0000000..514bec9 --- /dev/null +++ b/src/gamesbyexample/liars_pub.py @@ -0,0 +1,302 @@ +""" +This file isn't part of the Jack Tendy project. +This is a game that was created by a user named Jack Tendy. +This file is part of the Liars Pub game, which is a simple text-based game + +All the code should be styled according to Al Sweigart's style guide. +""" +import random, sys, time +# Python 2 compatibility for input (remove if only supporting Python 3) +if sys.version_info[0] < 3: + try: + input = raw_input + except NameError: + pass + +# cards +card_img = { + "J": [r"|--------|", + r"| | |", + r"| | |", + r"| __| |", + r"|________|"], + "Q": [r"|--------|", + r"| __ |", + r"| |__| |", + r"| \ |", + r"|________|"], + "K": [r"|--------|", + r"| | / |", + r"| |< |", + r"| | \ |", + r"|________|"], + "A": [r"|--------|", + r"| /\ |", + r"| /--\ |", + r"| | | |", + r"|________|"], + "JOKER": [r"|--------|", # JOKER can be represented as O + r"| O |JO|", + r"| /|\ |KE|", + r"| / \ |R`|", + r"|________|"] +} + +CARD_GAP = " " +def display_cards(cards): + """Display the cards in a list of cards.""" + rows = [""] * 5 + for card in cards: + for i in range(5): + rows[i] += card_img[card][i] + CARD_GAP + for row in rows: + print(row) + +def shoot_at(player, is_killed): + """ Draw a gun and shoot at the player. + If is_killed is True, the player is killed. + """ + print("~ |\ ____________ _",flush=True) + print("~ / |_____________||",end="",flush=True) + if is_killed: + print("■> "+player+" is killed! > x <",flush=True) + else: + print(" > "+player+" is safe! ^ _ ^",flush=True) + print("~ / |______________|ˉˉ",flush=True) + print('~ / /',flush=True) + print("~|_|_|",flush=True) + +def show_remains(remain_dict,last_player,last_action): + """Show the remaining players and their num of cards, one per row. + remain_dict is a dict of {player_name: num_of_cards}. + output should be like: + Player1: o o o o o + Player2: o o o <- if last_player is Player2 and last_action is "put out 2 cards" + Player3: (out) + if last_player and last_action are not None, + show the last action at his row of the output(Who has put out how many cards). + """ + for player, num in remain_dict.items(): + print("# ",end="") # to flush the output buffer + if isinstance(num, list): + card_count = len(num) + else: + card_count = num + if card_count > 0: + cards = "o " * card_count + if player == last_player and last_action is not None: + print(f"{player}: {cards} <- {last_player} {last_action}") + else: + print(f"{player}: {cards}") + else: + print(f"{player}: (out)") + +def _is_false_declaration(): + global last_played_cards, target + """Check if the last declaration is false.""" + for card in last_played_cards: + if card != target and card != "O": + return True + return False + +def show_instructions(): + """Display the instructions for the game.""" + print('''Liars Pub, by Jack Tendy. +A simple card game for 4 players. +The goal is to live the last. +Rules: +- Each player is dealt 5 cards. +- Players take turns playing cards face down and declaring their rank (J, Q, K, A, O). +- Other players can challenge the declaration. +- If the declaration is true, the challenger gets the gun shoot. +- If the declaration is false, the declarer gets the gun shoot. +- When one player has no cards left, refill their hand from the deck. +- The gun has 6 bullets, 1 full and 5 empty.. +- When the gun is shot, if it's a full bullet, the player is out. +- The last player remaining wins the game. +- Press Enter to continue...''') + input() + +# the following code uses generators to manage the game flow, and coroutines to handle player actions. +def gen_gun(): + """A generator that yields True for a full bullet and False for an empty bullet. + """ + while True: + bullet_chamber = [False, False, False, False, False, True] + random.shuffle(bullet_chamber) + for chamber in bullet_chamber: + yield chamber + +def reset_deck(players): + """Reset and shuffle the deck, return a list of cards.""" + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) + return {player: [deck.pop() for _ in range(5)] for player in players} + +def gen_pub(players): + """A generator that manages the game flow""" + remains = reset_deck(players) + index = 0 + while True: + name = players[index] + feedback = yield name, remains + if feedback[0] == "shoot": + # shoot at the player + is_killed = feedback[1] + if is_killed: + remains[name] = [] + if sum(1 for cards in remains.values() if cards) == 1: + # only one player left + winner = [player for player, cards in remains.items() if cards][0] + yield "win", winner + return + elif feedback[0] == "put": + # put out cards + num, cards, target = feedback[1], feedback[2], feedback[3] + for card in cards: + remains[name].remove(card) + if not remains[name]: + # refill if no cards left-- this redistribute all players' cards + remains = reset_deck(players) + index = (index + 1) % len(players) + +def main(): + """ + Runs the main loop for the Liars Pub card game. + This function initializes the game, sets up players, and manages the turn-based gameplay loop. + Players take turns declaring and playing cards, and other players may challenge the declaration. + If challenged, the truthfulness of the declaration is checked, and the loser faces a penalty (simulated by 'shooting'). + The game continues until a win condition is met. + Key steps: + - Shows instructions to the players. + - Initializes player list and game generators for pub and gun mechanics. + - Tracks game state variables such as last player, last action, last played cards, and current target declaration. + - For each turn: + - Displays current player's hand and game state. + - Prompts the player to select cards and make a declaration. + - Allows other players to challenge the declaration. + - Resolves challenges and applies penalties. + - Checks for win condition after each challenge. + - Advances to the next player if no challenge occurs. + Assumes existence of helper functions: + - show_instructions() + - gen_pub(players) + - gen_gun() + - show_remains(remains, last_player, last_action) + - display_cards(cards) + - shoot_at(player, is_killed) + """ + """Main game function.""" + show_instructions() + + # Initialize players + players = ["Player1", "Player2", "Player3", "Player4"] + pub_gen = gen_pub(players) + gun_gen = gen_gun() + + # Game state variables + last_player = None + last_action = None + last_played_cards = [] + target = None + + # Start the game + player, remains = next(pub_gen) + + while True: + print(f"\n--- {player}'s turn ---") + show_remains(remains, last_player, last_action) + + # Display player's hand + print(f"\nYour cards: {', '.join(remains[player])}") + + # Get player's action + while True: + try: + num_cards = int(input("How many cards do you want to play? ")) + if num_cards < 1 or num_cards > len(remains[player]): + print(f"Invalid number. You have {len(remains[player])} cards.") + continue + + # Get which cards to play + print("Your cards: ", end="") + for i, card in enumerate(remains[player]): + print(f"{i+1}:{card} ", end="") + print() + + card_indices = input(f"Enter the indices (1-{len(remains[player])}) of cards to play, separated by spaces: ").split() + cards_to_play = [remains[player][int(i)-1] for i in card_indices] + + if len(cards_to_play) != num_cards: + print("Number of cards doesn't match the indices provided.") + continue + + # Get declaration + valid_declarations = ["J", "Q", "K", "A", "O"] + declaration = input("What are you declaring? (J, Q, K, A, O): ").upper() + if declaration not in valid_declarations: + print("Invalid declaration. Must be J, Q, K, A, or O.") + continue + + break + except (ValueError, IndexError): + print("Invalid input. Please try again.") + + # Update game state + last_player = player + last_action = f"declared {num_cards} {declaration}(s)" + last_played_cards = cards_to_play + target = declaration + + # Send action to game generator + pub_gen.send(("put", num_cards, cards_to_play, declaration)) + + # Check for challenges + challenger = None + for p in players: + if p != player and remains[p]: # Only players still in the game can challenge + challenge = input(f"{p}, do you want to challenge? (y/n): ").lower() + if challenge == 'y': + challenger = p + break + + # Resolve challenge or continue + if challenger: + print(f"\n{challenger} challenges {player}'s declaration!") + print("The played cards are: ") + display_cards(last_played_cards) + + # Check if declaration was true + is_truthful = True + for card in last_played_cards: + if card != target and card != "O": # O (Joker) is wild + is_truthful = False + break + + if is_truthful: + print(f"{player}'s declaration was truthful! {challenger} gets shot.") + shoot_player = challenger + else: + print(f"{player} was lying! {player} gets shot.") + shoot_player = player + + # Perform the shooting + is_killed = next(gun_gen) + shoot_at(shoot_player, is_killed) + + # Update game state + pub_gen.send(("shoot", is_killed)) + + # Check for win condition + result = next(pub_gen) + if result[0] == "win": + print(f"\n🎉 {result[1]} wins the game! 🎉") + break + else: + print("No one challenged. Moving to next player.") + + # Get next player + player, remains = next(pub_gen) + +if __name__ == "__main__": + main() \ No newline at end of file From 51e4996bd849761b9ddf19758f623ac4f78a8093 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Sun, 24 Aug 2025 07:29:17 +0800 Subject: [PATCH 2/8] Change some functions --- src/gamesbyexample/liars_pub.py | 251 +++++++++++++++++--------------- 1 file changed, 130 insertions(+), 121 deletions(-) diff --git a/src/gamesbyexample/liars_pub.py b/src/gamesbyexample/liars_pub.py index 514bec9..5f65c6b 100644 --- a/src/gamesbyexample/liars_pub.py +++ b/src/gamesbyexample/liars_pub.py @@ -132,14 +132,32 @@ def reset_deck(players): deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 random.shuffle(deck) return {player: [deck.pop() for _ in range(5)] for player in players} - def gen_pub(players): """A generator that manages the game flow""" - remains = reset_deck(players) + # 初始化牌堆和玩家手牌 + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) + remains = {player: [deck.pop() for _ in range(5)] for player in players} + index = 0 while True: name = players[index] + + # 检查当前玩家是否有牌,如果没有则重新洗牌 + if not remains[name]: + # 重新洗牌并给所有玩家发牌 + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) + for player in players: + if remains[player]: # 如果玩家还有牌,保留他们的牌 + # 只给没有牌的玩家发牌 + if not remains[player]: + remains[player] = [deck.pop() for _ in range(5)] + feedback = yield name, remains + if feedback is None: + continue + if feedback[0] == "shoot": # shoot at the player is_killed = feedback[1] @@ -155,148 +173,139 @@ def gen_pub(players): num, cards, target = feedback[1], feedback[2], feedback[3] for card in cards: remains[name].remove(card) - if not remains[name]: - # refill if no cards left-- this redistribute all players' cards - remains = reset_deck(players) - index = (index + 1) % len(players) + + # 检查是否需要重新洗牌(任何玩家手牌为空) + if any(not cards for cards in remains.values()): + # 重新洗牌并给所有玩家发牌 + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) + for player in players: + if not remains[player]: # 只给没有牌的玩家发牌 + remains[player] = [deck.pop() for _ in range(5)] + + index = (index + 1) % len(players) + + +def get_players_name(): + """Get player names from input.""" + players = [] + for i in range(4): + name = input(f"Enter name for Player {i+1} (or press Enter for default 'Player{i+1}'): \n") + if not name.strip(): + name = f"Player{i+1}" + players.append(name) + return players def main(): - """ - Runs the main loop for the Liars Pub card game. - This function initializes the game, sets up players, and manages the turn-based gameplay loop. - Players take turns declaring and playing cards, and other players may challenge the declaration. - If challenged, the truthfulness of the declaration is checked, and the loser faces a penalty (simulated by 'shooting'). - The game continues until a win condition is met. - Key steps: - - Shows instructions to the players. - - Initializes player list and game generators for pub and gun mechanics. - - Tracks game state variables such as last player, last action, last played cards, and current target declaration. - - For each turn: - - Displays current player's hand and game state. - - Prompts the player to select cards and make a declaration. - - Allows other players to challenge the declaration. - - Resolves challenges and applies penalties. - - Checks for win condition after each challenge. - - Advances to the next player if no challenge occurs. - Assumes existence of helper functions: - - show_instructions() - - gen_pub(players) - - gen_gun() - - show_remains(remains, last_player, last_action) - - display_cards(cards) - - shoot_at(player, is_killed) - """ - """Main game function.""" + """主函数,运行骗子酒馆游戏""" + global target, last_played_cards + print("Welcome to Liars Pub!") + # 显示游戏说明 show_instructions() - # Initialize players + # 初始化玩家 players = ["Player1", "Player2", "Player3", "Player4"] - pub_gen = gen_pub(players) - gun_gen = gen_gun() + # 初始化游戏状态生成器 + game = gen_pub(players) + # 初始化左轮手枪生成器 + gun = gen_gun() + + # 随机选择目标牌 + global target + target = random.choice(["J", "Q", "K", "A"]) + print(f"\n本局游戏的目标牌是: {target}") - # Game state variables + # 获取初始游戏状态 + current_player, remains = next(game) last_player = None last_action = None last_played_cards = [] - target = None - - # Start the game - player, remains = next(pub_gen) + # 游戏主循环 while True: - print(f"\n--- {player}'s turn ---") - show_remains(remains, last_player, last_action) + print(f"\n===== {current_player}'s turn =====") - # Display player's hand - print(f"\nYour cards: {', '.join(remains[player])}") + # 显示当前玩家手牌 + print(f"Your cards: {', '.join(remains[current_player])}") - # Get player's action - while True: - try: - num_cards = int(input("How many cards do you want to play? ")) - if num_cards < 1 or num_cards > len(remains[player]): - print(f"Invalid number. You have {len(remains[player])} cards.") - continue - - # Get which cards to play - print("Your cards: ", end="") - for i, card in enumerate(remains[player]): - print(f"{i+1}:{card} ", end="") - print() - - card_indices = input(f"Enter the indices (1-{len(remains[player])}) of cards to play, separated by spaces: ").split() - cards_to_play = [remains[player][int(i)-1] for i in card_indices] - - if len(cards_to_play) != num_cards: - print("Number of cards doesn't match the indices provided.") - continue - - # Get declaration - valid_declarations = ["J", "Q", "K", "A", "O"] - declaration = input("What are you declaring? (J, Q, K, A, O): ").upper() - if declaration not in valid_declarations: - print("Invalid declaration. Must be J, Q, K, A, or O.") - continue - + # 检查玩家是否有牌可出 + if not remains[current_player]: + print(f"{current_player} has no cards to play! Refilling...") + # 发送一个空操作以触发重新洗牌 + result = game.send(("pass", None)) + if result and result[0] == "win": + print(f"\n🎉 Game Over! {result[1]} wins! 🎉") break - except (ValueError, IndexError): - print("Invalid input. Please try again.") + else: + current_player, remains = result + continue + + # 玩家选择出牌数量 (简化: 随机出1-2张) + num_to_play = random.randint(1, min(2, len(remains[current_player]))) + cards_to_play = random.sample(remains[current_player], num_to_play) + last_played_cards = cards_to_play.copy() - # Update game state - last_player = player - last_action = f"declared {num_cards} {declaration}(s)" - last_played_cards = cards_to_play - target = declaration + # 玩家声明出牌 (总是声明为目标牌) + print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") - # Send action to game generator - pub_gen.send(("put", num_cards, cards_to_play, declaration)) + # 记录最后动作 + last_action = f"declared {num_to_play} {target}(s)" + last_player = current_player - # Check for challenges - challenger = None - for p in players: - if p != player and remains[p]: # Only players still in the game can challenge - challenge = input(f"{p}, do you want to challenge? (y/n): ").lower() - if challenge == 'y': - challenger = p - break + # 只有下家可以挑战 + next_player_index = (players.index(current_player) + 1) % len(players) + next_player = players[next_player_index] - # Resolve challenge or continue - if challenger: - print(f"\n{challenger} challenges {player}'s declaration!") - print("The played cards are: ") - display_cards(last_played_cards) + # 检查下家是否还在游戏中 + if remains.get(next_player): # 使用get方法避免KeyError + # 下家决定是否挑战 (简化: 有一定概率挑战) + will_challenge = random.random() < 0.4 # 40%概率挑战 - # Check if declaration was true - is_truthful = True - for card in last_played_cards: - if card != target and card != "O": # O (Joker) is wild - is_truthful = False + if will_challenge: + print(f"{next_player} challenges the declaration!") + + # 验证声明 + is_truthful = not _is_false_declaration() + + if is_truthful: + print("The declaration was truthful!") + loser = next_player + else: + print("The declaration was a lie!") + loser = current_player + + # 执行枪击 + print(f"\nShooting at {loser}...") + time.sleep(1) # 增加 suspense + + is_dead = next(gun) + shoot_at(loser, is_dead) + + # 更新游戏状态 + result = game.send(("shoot", is_dead)) + + if result and result[0] == "win": + print(f"\n🎉 Game Over! {result[1]} wins! 🎉") break - - if is_truthful: - print(f"{player}'s declaration was truthful! {challenger} gets shot.") - shoot_player = challenger else: - print(f"{player} was lying! {player} gets shot.") - shoot_player = player - - # Perform the shooting - is_killed = next(gun_gen) - shoot_at(shoot_player, is_killed) - - # Update game state - pub_gen.send(("shoot", is_killed)) - - # Check for win condition - result = next(pub_gen) - if result[0] == "win": - print(f"\n🎉 {result[1]} wins the game! 🎉") - break + print(f"{next_player} does not challenge.") + # 正常出牌,更新游戏状态 + result = game.send(("put", num_to_play, cards_to_play, target)) else: - print("No one challenged. Moving to next player.") + print(f"{next_player} is out, no one to challenge.") + # 正常出牌,更新游戏状态 + result = game.send(("put", num_to_play, cards_to_play, target)) + + # 显示当前游戏状态 + print("\nCurrent game status:") + show_remains(remains, last_player, last_action) - # Get next player - player, remains = next(pub_gen) + # 获取下一个玩家 + if result and result[0] == "win": + print(f"\n🎉 Game Over! {result[1]} wins! 🎉") + break + else: + current_player, remains = result if __name__ == "__main__": main() \ No newline at end of file From e42f967f288b3ef8d6514d476f87063fa15a6740 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Mon, 25 Aug 2025 18:36:39 +0800 Subject: [PATCH 3/8] Update liars_pub.py --- src/gamesbyexample/liars_pub.py | 422 +++++++++++++++----------------- 1 file changed, 199 insertions(+), 223 deletions(-) diff --git a/src/gamesbyexample/liars_pub.py b/src/gamesbyexample/liars_pub.py index 5f65c6b..d71aab4 100644 --- a/src/gamesbyexample/liars_pub.py +++ b/src/gamesbyexample/liars_pub.py @@ -1,56 +1,81 @@ -""" -This file isn't part of the Jack Tendy project. -This is a game that was created by a user named Jack Tendy. -This file is part of the Liars Pub game, which is a simple text-based game +import random +import time -All the code should be styled according to Al Sweigart's style guide. -""" -import random, sys, time -# Python 2 compatibility for input (remove if only supporting Python 3) -if sys.version_info[0] < 3: - try: - input = raw_input - except NameError: - pass +# 全局变量 +target = None # 目标牌 +gun_chamber = [] # 左轮手枪弹巢 +gun_index = 0 # 当前子弹位置 +players = [] # 玩家列表 +active_players = [] # 活跃玩家列表(未被淘汰的玩家) +player_hands = {} # 玩家手牌 +current_player_index = 0 # 当前玩家索引 +deck = [] # 牌堆 -# cards -card_img = { - "J": [r"|--------|", - r"| | |", - r"| | |", - r"| __| |", - r"|________|"], - "Q": [r"|--------|", - r"| __ |", - r"| |__| |", - r"| \ |", - r"|________|"], - "K": [r"|--------|", - r"| | / |", - r"| |< |", - r"| | \ |", - r"|________|"], - "A": [r"|--------|", - r"| /\ |", - r"| /--\ |", - r"| | | |", - r"|________|"], - "JOKER": [r"|--------|", # JOKER can be represented as O - r"| O |JO|", - r"| /|\ |KE|", - r"| / \ |R`|", - r"|________|"] -} +def reset_deck(): + """重置并洗牌""" + global deck + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) -CARD_GAP = " " -def display_cards(cards): - """Display the cards in a list of cards.""" - rows = [""] * 5 - for card in cards: - for i in range(5): - rows[i] += card_img[card][i] + CARD_GAP - for row in rows: - print(row) +def deal_cards(): + """发牌给所有活跃玩家""" + global player_hands, deck + + # 如果牌堆不够,重新洗牌 + if len(deck) < len(active_players) * 5: + reset_deck() + + # 给每个活跃玩家发5张牌 + for player in active_players: + if len(player_hands[player]) == 0: # 只给没有牌的玩家发牌 + player_hands[player] = [deck.pop() for _ in range(min(5, len(deck)))] + +def init_gun(): + """初始化左轮手枪""" + global gun_chamber, gun_index + gun_chamber = [False, False, False, False, False, True] + random.shuffle(gun_chamber) + gun_index = 0 + +def show_instructions(): + """Display the instructions for the game.""" + print('''Liars Pub, by Jack Tendy. +A simple card game for 4 players. +The goal is to live the last. +Rules: +- Each player is dealt 5 cards. +- Players take turns playing cards face down and declaring their rank (J, Q, K, A, O). +- Other players can challenge the declaration. +- If the declaration is true, the challenger gets the gun shoot. +- If the declaration is false, the declarer gets the gun shoot. +- When one player has no cards left, refill their hand from the deck. +- The gun has 6 bullets, 1 full and 5 empty.. +- When the gun is shot, if it's a full bullet, the player is out. +- The last player remaining wins the game. +- Press Enter to continue...''') + input() + + +def shoot(): + """开枪,返回是否击中""" + global gun_index, gun_chamber + + is_hit = gun_chamber[gun_index] + gun_index = (gun_index + 1) % 6 + + # 如果已经用完所有子弹,重新装填 + if gun_index == 0: + random.shuffle(gun_chamber) + + return is_hit + +def is_false_declaration(played_cards): + """检查声明是否虚假""" + global target + for card in played_cards: + if card != target and card != "O": # 如果不是目标牌也不是Joker + return True + return False def shoot_at(player, is_killed): """ Draw a gun and shoot at the player. @@ -66,6 +91,8 @@ def shoot_at(player, is_killed): print('~ / /',flush=True) print("~|_|_|",flush=True) + + def show_remains(remain_dict,last_player,last_action): """Show the remaining players and their num of cards, one per row. remain_dict is a dict of {player_name: num_of_cards}. @@ -91,159 +118,112 @@ def show_remains(remain_dict,last_player,last_action): else: print(f"{player}: (out)") -def _is_false_declaration(): - global last_played_cards, target - """Check if the last declaration is false.""" - for card in last_played_cards: - if card != target and card != "O": - return True - return False +def get_next_player(): + """获取下一个活跃玩家""" + global current_player_index, active_players + + if len(active_players) <= 1: + return current_player_index + + # 找到下一个活跃玩家 + next_index = (current_player_index + 1) % len(active_players) + return next_index -def show_instructions(): - """Display the instructions for the game.""" - print('''Liars Pub, by Jack Tendy. -A simple card game for 4 players. -The goal is to live the last. -Rules: -- Each player is dealt 5 cards. -- Players take turns playing cards face down and declaring their rank (J, Q, K, A, O). -- Other players can challenge the declaration. -- If the declaration is true, the challenger gets the gun shoot. -- If the declaration is false, the declarer gets the gun shoot. -- When one player has no cards left, refill their hand from the deck. -- The gun has 6 bullets, 1 full and 5 empty.. -- When the gun is shot, if it's a full bullet, the player is out. -- The last player remaining wins the game. -- Press Enter to continue...''') - input() +def check_win_condition(): + """检查是否满足胜利条件""" + return len(active_players) == 1, active_players[0] if len(active_players) == 1 else None -# the following code uses generators to manage the game flow, and coroutines to handle player actions. -def gen_gun(): - """A generator that yields True for a full bullet and False for an empty bullet. - """ +def get_player_input(player, hand): + """获取玩家输入""" + print(f"\n{player}'s turn. Your cards: {', '.join(hand)}") + + # 获取出牌数量 while True: - bullet_chamber = [False, False, False, False, False, True] - random.shuffle(bullet_chamber) - for chamber in bullet_chamber: - yield chamber - -def reset_deck(players): - """Reset and shuffle the deck, return a list of cards.""" - deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 - random.shuffle(deck) - return {player: [deck.pop() for _ in range(5)] for player in players} -def gen_pub(players): - """A generator that manages the game flow""" - # 初始化牌堆和玩家手牌 - deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 - random.shuffle(deck) - remains = {player: [deck.pop() for _ in range(5)] for player in players} + try: + num_to_play = int(input("How many cards do you want to play? (1-2): ")) + if 1 <= num_to_play <= 2 and num_to_play <= len(hand): + break + else: + print("Invalid input. Please enter 1 or 2, and make sure you have enough cards.") + except ValueError: + print("Please enter a valid number.") + + # 获取要出的牌 + print("Select cards to play (enter the card letters, separated by spaces):") + print("Available cards:", ", ".join(hand)) - index = 0 while True: - name = players[index] - - # 检查当前玩家是否有牌,如果没有则重新洗牌 - if not remains[name]: - # 重新洗牌并给所有玩家发牌 - deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 - random.shuffle(deck) - for player in players: - if remains[player]: # 如果玩家还有牌,保留他们的牌 - # 只给没有牌的玩家发牌 - if not remains[player]: - remains[player] = [deck.pop() for _ in range(5)] - - feedback = yield name, remains - if feedback is None: - continue + try: + selected_cards = input().strip().upper().split() + # 验证输入 + if len(selected_cards) != num_to_play: + print(f"Please select exactly {num_to_play} card(s).") + continue - if feedback[0] == "shoot": - # shoot at the player - is_killed = feedback[1] - if is_killed: - remains[name] = [] - if sum(1 for cards in remains.values() if cards) == 1: - # only one player left - winner = [player for player, cards in remains.items() if cards][0] - yield "win", winner - return - elif feedback[0] == "put": - # put out cards - num, cards, target = feedback[1], feedback[2], feedback[3] - for card in cards: - remains[name].remove(card) + # 检查所选牌是否在手牌中 + valid_selection = True + temp_hand = hand.copy() + for card in selected_cards: + if card in temp_hand: + temp_hand.remove(card) + else: + print(f"Card {card} is not in your hand or has already been selected.") + valid_selection = False + break - # 检查是否需要重新洗牌(任何玩家手牌为空) - if any(not cards for cards in remains.values()): - # 重新洗牌并给所有玩家发牌 - deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 - random.shuffle(deck) - for player in players: - if not remains[player]: # 只给没有牌的玩家发牌 - remains[player] = [deck.pop() for _ in range(5)] - - index = (index + 1) % len(players) - - -def get_players_name(): - """Get player names from input.""" - players = [] - for i in range(4): - name = input(f"Enter name for Player {i+1} (or press Enter for default 'Player{i+1}'): \n") - if not name.strip(): - name = f"Player{i+1}" - players.append(name) - return players + if valid_selection: + return selected_cards + except Exception as e: + print("Invalid input. Please try again.") def main(): """主函数,运行骗子酒馆游戏""" - global target, last_played_cards - print("Welcome to Liars Pub!") + global target, players, active_players, player_hands, current_player_index, deck + # 显示游戏说明 show_instructions() # 初始化玩家 players = ["Player1", "Player2", "Player3", "Player4"] - # 初始化游戏状态生成器 - game = gen_pub(players) - # 初始化左轮手枪生成器 - gun = gen_gun() + active_players = players.copy() + player_hands = {player: [] for player in players} + + # 初始化牌堆和发牌 + reset_deck() + deal_cards() + + # 初始化左轮手枪 + init_gun() # 随机选择目标牌 - global target target = random.choice(["J", "Q", "K", "A"]) print(f"\n本局游戏的目标牌是: {target}") - # 获取初始游戏状态 - current_player, remains = next(game) + # 游戏主循环 + game_over = False + winner = None last_player = None last_action = None - last_played_cards = [] - # 游戏主循环 - while True: - print(f"\n===== {current_player}'s turn =====") + while not game_over: + current_player = active_players[current_player_index] - # 显示当前玩家手牌 - print(f"Your cards: {', '.join(remains[current_player])}") + # 如果当前玩家没有牌,重新发牌 + if len(player_hands[current_player]) == 0: + deal_cards() + # 如果重新发牌后仍然没有牌,可能是牌堆空了 + if len(player_hands[current_player]) == 0: + print(f"{current_player} has no cards to play! Skipping turn.") + current_player_index = get_next_player() + continue - # 检查玩家是否有牌可出 - if not remains[current_player]: - print(f"{current_player} has no cards to play! Refilling...") - # 发送一个空操作以触发重新洗牌 - result = game.send(("pass", None)) - if result and result[0] == "win": - print(f"\n🎉 Game Over! {result[1]} wins! 🎉") - break - else: - current_player, remains = result - continue - - # 玩家选择出牌数量 (简化: 随机出1-2张) - num_to_play = random.randint(1, min(2, len(remains[current_player]))) - cards_to_play = random.sample(remains[current_player], num_to_play) - last_played_cards = cards_to_play.copy() + # 获取玩家输入 + cards_to_play = get_player_input(current_player, player_hands[current_player]) + num_to_play = len(cards_to_play) + + # 从手牌中移除这些牌 + for card in cards_to_play: + player_hands[current_player].remove(card) # 玩家声明出牌 (总是声明为目标牌) print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") @@ -253,59 +233,55 @@ def main(): last_player = current_player # 只有下家可以挑战 - next_player_index = (players.index(current_player) + 1) % len(players) - next_player = players[next_player_index] + next_player_index = get_next_player() + next_player = active_players[next_player_index] - # 检查下家是否还在游戏中 - if remains.get(next_player): # 使用get方法避免KeyError - # 下家决定是否挑战 (简化: 有一定概率挑战) - will_challenge = random.random() < 0.4 # 40%概率挑战 + # 下家决定是否挑战 + challenge = input(f"{next_player}, do you challenge? (y/n): ").strip().lower() + will_challenge = challenge == 'y' + + if will_challenge: + print(f"{next_player} challenges the declaration!") - if will_challenge: - print(f"{next_player} challenges the declaration!") - - # 验证声明 - is_truthful = not _is_false_declaration() - - if is_truthful: - print("The declaration was truthful!") - loser = next_player - else: - print("The declaration was a lie!") - loser = current_player - - # 执行枪击 - print(f"\nShooting at {loser}...") - time.sleep(1) # 增加 suspense - - is_dead = next(gun) - shoot_at(loser, is_dead) - - # 更新游戏状态 - result = game.send(("shoot", is_dead)) + # 验证声明 + declaration_false = is_false_declaration(cards_to_play) + + if not declaration_false: + print("The declaration was truthful!") + loser = next_player + else: + print("The declaration was a lie!") + loser = current_player + + # 执行枪击 + print(f"\nShooting at {loser}...") + time.sleep(1) # 增加 suspense + + is_dead = shoot() + shoot_at(loser, is_dead) + + # 如果被击中,移除该玩家 + if is_dead: + print(f"{loser} is eliminated from the game!") + active_players.remove(loser) + player_hands[loser] = [] - if result and result[0] == "win": - print(f"\n🎉 Game Over! {result[1]} wins! 🎉") + # 检查游戏是否结束 + game_over, winner = check_win_condition() + if game_over: break - else: - print(f"{next_player} does not challenge.") - # 正常出牌,更新游戏状态 - result = game.send(("put", num_to_play, cards_to_play, target)) else: - print(f"{next_player} is out, no one to challenge.") - # 正常出牌,更新游戏状态 - result = game.send(("put", num_to_play, cards_to_play, target)) + print(f"{next_player} does not challenge.") # 显示当前游戏状态 print("\nCurrent game status:") - show_remains(remains, last_player, last_action) + show_remains(player_hands, last_player, last_action) - # 获取下一个玩家 - if result and result[0] == "win": - print(f"\n🎉 Game Over! {result[1]} wins! 🎉") - break - else: - current_player, remains = result + # 移动到下一个玩家 + current_player_index = get_next_player() + + # 游戏结束 + print(f"\n🎉 Game Over! {winner} wins! 🎉") if __name__ == "__main__": - main() \ No newline at end of file + main() From bc61b908a61b3fc168d827deadb905ce5976e070 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Wed, 27 Aug 2025 07:00:00 +0800 Subject: [PATCH 4/8] add more logics --- src/gamesbyexample/liars_pub.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/gamesbyexample/liars_pub.py b/src/gamesbyexample/liars_pub.py index d71aab4..6477103 100644 --- a/src/gamesbyexample/liars_pub.py +++ b/src/gamesbyexample/liars_pub.py @@ -176,6 +176,16 @@ def get_player_input(player, hand): except Exception as e: print("Invalid input. Please try again.") +def get_player_name(): + responses = [] + max_len = 0 + for i in range(4): + # get the player's name + name = input('#player %d \d'%(i+1)).title() + if len(name) > max_len: + max_len = len(name) + return [name.ljust(max_len) for name in responses] + def main(): """主函数,运行骗子酒馆游戏""" global target, players, active_players, player_hands, current_player_index, deck @@ -184,7 +194,7 @@ def main(): show_instructions() # 初始化玩家 - players = ["Player1", "Player2", "Player3", "Player4"] + players = get_player_name() active_players = players.copy() player_hands = {player: [] for player in players} @@ -197,7 +207,7 @@ def main(): # 随机选择目标牌 target = random.choice(["J", "Q", "K", "A"]) - print(f"\n本局游戏的目标牌是: {target}") + print(f"\n The target of this game is: {target}") # 游戏主循环 game_over = False @@ -226,6 +236,7 @@ def main(): player_hands[current_player].remove(card) # 玩家声明出牌 (总是声明为目标牌) + print('\n'*15, flush=True) print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") # 记录最后动作 @@ -285,3 +296,4 @@ def main(): if __name__ == "__main__": main() + From 7bd799220ccc11b3b230e7e9cc94259ec7b84aca Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Wed, 27 Aug 2025 18:21:06 +0800 Subject: [PATCH 5/8] Add option for whether to show instructions --- src/gamesbyexample/{liars_pub.py => liars-pub.py} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/gamesbyexample/{liars_pub.py => liars-pub.py} (96%) diff --git a/src/gamesbyexample/liars_pub.py b/src/gamesbyexample/liars-pub.py similarity index 96% rename from src/gamesbyexample/liars_pub.py rename to src/gamesbyexample/liars-pub.py index 6477103..9e9b9f1 100644 --- a/src/gamesbyexample/liars_pub.py +++ b/src/gamesbyexample/liars-pub.py @@ -191,7 +191,8 @@ def main(): global target, players, active_players, player_hands, current_player_index, deck # 显示游戏说明 - show_instructions() + if input('Want to view instructions?[y/n]')[0].lower() == 'y': + show_instructions() # 初始化玩家 players = get_player_name() @@ -297,3 +298,4 @@ def main(): if __name__ == "__main__": main() + From 0432ea2da90d760e94f69985f08492b5964ba019 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Fri, 29 Aug 2025 08:04:38 +0800 Subject: [PATCH 6/8] Revise sth --- src/gamesbyexample/liars-pub.py | 652 +++++++++++++++++--------------- 1 file changed, 351 insertions(+), 301 deletions(-) diff --git a/src/gamesbyexample/liars-pub.py b/src/gamesbyexample/liars-pub.py index 9e9b9f1..eece3a1 100644 --- a/src/gamesbyexample/liars-pub.py +++ b/src/gamesbyexample/liars-pub.py @@ -1,301 +1,351 @@ -import random -import time - -# 全局变量 -target = None # 目标牌 -gun_chamber = [] # 左轮手枪弹巢 -gun_index = 0 # 当前子弹位置 -players = [] # 玩家列表 -active_players = [] # 活跃玩家列表(未被淘汰的玩家) -player_hands = {} # 玩家手牌 -current_player_index = 0 # 当前玩家索引 -deck = [] # 牌堆 - -def reset_deck(): - """重置并洗牌""" - global deck - deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 - random.shuffle(deck) - -def deal_cards(): - """发牌给所有活跃玩家""" - global player_hands, deck - - # 如果牌堆不够,重新洗牌 - if len(deck) < len(active_players) * 5: - reset_deck() - - # 给每个活跃玩家发5张牌 - for player in active_players: - if len(player_hands[player]) == 0: # 只给没有牌的玩家发牌 - player_hands[player] = [deck.pop() for _ in range(min(5, len(deck)))] - -def init_gun(): - """初始化左轮手枪""" - global gun_chamber, gun_index - gun_chamber = [False, False, False, False, False, True] - random.shuffle(gun_chamber) - gun_index = 0 - -def show_instructions(): - """Display the instructions for the game.""" - print('''Liars Pub, by Jack Tendy. -A simple card game for 4 players. -The goal is to live the last. -Rules: -- Each player is dealt 5 cards. -- Players take turns playing cards face down and declaring their rank (J, Q, K, A, O). -- Other players can challenge the declaration. -- If the declaration is true, the challenger gets the gun shoot. -- If the declaration is false, the declarer gets the gun shoot. -- When one player has no cards left, refill their hand from the deck. -- The gun has 6 bullets, 1 full and 5 empty.. -- When the gun is shot, if it's a full bullet, the player is out. -- The last player remaining wins the game. -- Press Enter to continue...''') - input() - - -def shoot(): - """开枪,返回是否击中""" - global gun_index, gun_chamber - - is_hit = gun_chamber[gun_index] - gun_index = (gun_index + 1) % 6 - - # 如果已经用完所有子弹,重新装填 - if gun_index == 0: - random.shuffle(gun_chamber) - - return is_hit - -def is_false_declaration(played_cards): - """检查声明是否虚假""" - global target - for card in played_cards: - if card != target and card != "O": # 如果不是目标牌也不是Joker - return True - return False - -def shoot_at(player, is_killed): - """ Draw a gun and shoot at the player. - If is_killed is True, the player is killed. - """ - print("~ |\ ____________ _",flush=True) - print("~ / |_____________||",end="",flush=True) - if is_killed: - print("■> "+player+" is killed! > x <",flush=True) - else: - print(" > "+player+" is safe! ^ _ ^",flush=True) - print("~ / |______________|ˉˉ",flush=True) - print('~ / /',flush=True) - print("~|_|_|",flush=True) - - - -def show_remains(remain_dict,last_player,last_action): - """Show the remaining players and their num of cards, one per row. - remain_dict is a dict of {player_name: num_of_cards}. - output should be like: - Player1: o o o o o - Player2: o o o <- if last_player is Player2 and last_action is "put out 2 cards" - Player3: (out) - if last_player and last_action are not None, - show the last action at his row of the output(Who has put out how many cards). - """ - for player, num in remain_dict.items(): - print("# ",end="") # to flush the output buffer - if isinstance(num, list): - card_count = len(num) - else: - card_count = num - if card_count > 0: - cards = "o " * card_count - if player == last_player and last_action is not None: - print(f"{player}: {cards} <- {last_player} {last_action}") - else: - print(f"{player}: {cards}") - else: - print(f"{player}: (out)") - -def get_next_player(): - """获取下一个活跃玩家""" - global current_player_index, active_players - - if len(active_players) <= 1: - return current_player_index - - # 找到下一个活跃玩家 - next_index = (current_player_index + 1) % len(active_players) - return next_index - -def check_win_condition(): - """检查是否满足胜利条件""" - return len(active_players) == 1, active_players[0] if len(active_players) == 1 else None - -def get_player_input(player, hand): - """获取玩家输入""" - print(f"\n{player}'s turn. Your cards: {', '.join(hand)}") - - # 获取出牌数量 - while True: - try: - num_to_play = int(input("How many cards do you want to play? (1-2): ")) - if 1 <= num_to_play <= 2 and num_to_play <= len(hand): - break - else: - print("Invalid input. Please enter 1 or 2, and make sure you have enough cards.") - except ValueError: - print("Please enter a valid number.") - - # 获取要出的牌 - print("Select cards to play (enter the card letters, separated by spaces):") - print("Available cards:", ", ".join(hand)) - - while True: - try: - selected_cards = input().strip().upper().split() - # 验证输入 - if len(selected_cards) != num_to_play: - print(f"Please select exactly {num_to_play} card(s).") - continue - - # 检查所选牌是否在手牌中 - valid_selection = True - temp_hand = hand.copy() - for card in selected_cards: - if card in temp_hand: - temp_hand.remove(card) - else: - print(f"Card {card} is not in your hand or has already been selected.") - valid_selection = False - break - - if valid_selection: - return selected_cards - except Exception as e: - print("Invalid input. Please try again.") - -def get_player_name(): - responses = [] - max_len = 0 - for i in range(4): - # get the player's name - name = input('#player %d \d'%(i+1)).title() - if len(name) > max_len: - max_len = len(name) - return [name.ljust(max_len) for name in responses] - -def main(): - """主函数,运行骗子酒馆游戏""" - global target, players, active_players, player_hands, current_player_index, deck - - # 显示游戏说明 - if input('Want to view instructions?[y/n]')[0].lower() == 'y': - show_instructions() - - # 初始化玩家 - players = get_player_name() - active_players = players.copy() - player_hands = {player: [] for player in players} - - # 初始化牌堆和发牌 - reset_deck() - deal_cards() - - # 初始化左轮手枪 - init_gun() - - # 随机选择目标牌 - target = random.choice(["J", "Q", "K", "A"]) - print(f"\n The target of this game is: {target}") - - # 游戏主循环 - game_over = False - winner = None - last_player = None - last_action = None - - while not game_over: - current_player = active_players[current_player_index] - - # 如果当前玩家没有牌,重新发牌 - if len(player_hands[current_player]) == 0: - deal_cards() - # 如果重新发牌后仍然没有牌,可能是牌堆空了 - if len(player_hands[current_player]) == 0: - print(f"{current_player} has no cards to play! Skipping turn.") - current_player_index = get_next_player() - continue - - # 获取玩家输入 - cards_to_play = get_player_input(current_player, player_hands[current_player]) - num_to_play = len(cards_to_play) - - # 从手牌中移除这些牌 - for card in cards_to_play: - player_hands[current_player].remove(card) - - # 玩家声明出牌 (总是声明为目标牌) - print('\n'*15, flush=True) - print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") - - # 记录最后动作 - last_action = f"declared {num_to_play} {target}(s)" - last_player = current_player - - # 只有下家可以挑战 - next_player_index = get_next_player() - next_player = active_players[next_player_index] - - # 下家决定是否挑战 - challenge = input(f"{next_player}, do you challenge? (y/n): ").strip().lower() - will_challenge = challenge == 'y' - - if will_challenge: - print(f"{next_player} challenges the declaration!") - - # 验证声明 - declaration_false = is_false_declaration(cards_to_play) - - if not declaration_false: - print("The declaration was truthful!") - loser = next_player - else: - print("The declaration was a lie!") - loser = current_player - - # 执行枪击 - print(f"\nShooting at {loser}...") - time.sleep(1) # 增加 suspense - - is_dead = shoot() - shoot_at(loser, is_dead) - - # 如果被击中,移除该玩家 - if is_dead: - print(f"{loser} is eliminated from the game!") - active_players.remove(loser) - player_hands[loser] = [] - - # 检查游戏是否结束 - game_over, winner = check_win_condition() - if game_over: - break - else: - print(f"{next_player} does not challenge.") - - # 显示当前游戏状态 - print("\nCurrent game status:") - show_remains(player_hands, last_player, last_action) - - # 移动到下一个玩家 - current_player_index = get_next_player() - - # 游戏结束 - print(f"\n🎉 Game Over! {winner} wins! 🎉") - -if __name__ == "__main__": - main() - - +import random +import time + +# 全局变量 +target = None # 目标牌 +gun_chamber = [] # 左轮手枪弹巢 +gun_index = 0 # 当前子弹位置 +players = [] # 玩家列表 +active_players = [] # 活跃玩家列表(未被淘汰的玩家) +player_hands = {} # 玩家手牌 +current_player_index = 0 # 当前玩家索引 +deck = [] # 牌堆 +max_len = 0 + +import random, sys, time +# Python 2 compatibility for input (remove if only supporting Python 3) +if sys.version_info[0] < 3: + try: + input = raw_input + except NameError: + pass + +# cards +card_img = { + "J": [r"|--------|", + r"| | |", + r"| | |", + r"| __| |", + r"|________|"], + "Q": [r"|--------|", + r"| __ |", + r"| |__| |", + r"| \ |", + r"|________|"], + "K": [r"|--------|", + r"| | / |", + r"| |< |", + r"| | \ |", + r"|________|"], + "A": [r"|--------|", + r"| /\ |", + r"| /--\ |", + r"| | | |", + r"|________|"], + "O": [r"|--------|", # JOKER can be represented as O + r"| O |JO|", + r"| /|\ |KE|", + r"| / \ |R`|", + r"|________|"] +} + +CARD_GAP = " " +def display_cards(cards): + """Display the cards in a list of cards.""" + rows = [""] * 5 + for card in cards: + for i in range(5): + rows[i] += card_img[card][i] + CARD_GAP + for row in rows: + print(row) + + +def reset_deck(): + """重置并洗牌""" + global deck + deck = ["J"] * 4 + ["Q"] * 4 + ["K"] * 4 + ["A"] * 4 + ["O"] * 4 + random.shuffle(deck) + +def deal_cards(): + """发牌给所有活跃玩家""" + global player_hands, deck + + # 如果牌堆不够,重新洗牌 + if len(deck) < len(active_players) * 5: + reset_deck() + + # 给每个活跃玩家发5张牌 + for player in active_players: + if len(player_hands[player]) == 0: # 只给没有牌的玩家发牌 + player_hands[player] = [deck.pop() for _ in range(min(5, len(deck)))] + +def init_gun(): + """初始化左轮手枪""" + global gun_chamber, gun_index + gun_chamber = [False, False, False, False, False, True] + random.shuffle(gun_chamber) + gun_index = 0 + +def show_instructions(): + """Display the instructions for the game.""" + print('''Liars Pub, by Jack Tendy. +A simple card game for 4 players. +The goal is to live the last. +Rules: +- Each player is dealt 5 cards. +- Players take turns playing cards face down and declaring their rank (J, Q, K, A, O). +- Other players can challenge the declaration. +- If the declaration is true, the challenger gets the gun shoot. +- If the declaration is false, the declarer gets the gun shoot. +- When one player has no cards left, refill their hand from the deck. +- The gun has 6 bullets, 1 full and 5 empty.. +- When the gun is shot, if it's a full bullet, the player is out. +- The last player remaining wins the game. +- Press Enter to continue...''') + input() + + +def shoot(): + """开枪,返回是否击中""" + global gun_index, gun_chamber + + is_hit = gun_chamber[gun_index] + gun_index = (gun_index + 1) % 6 + + # 如果已经用完所有子弹,重新装填 + if gun_index == 0: + random.shuffle(gun_chamber) + + return is_hit + +def is_false_declaration(played_cards): + """检查声明是否虚假""" + global target + for card in played_cards: + if card != target and card != "O": # 如果不是目标牌也不是Joker + return True + return False + +def shoot_at(player, is_killed): + """ Draw a gun and shoot at the player. + If is_killed is True, the player is killed. + """ + print(r"~ |\ ____________ _",flush=True) + print(r"~ / |_____________||",end="",flush=True) + if is_killed: + print("■> "+player+" is killed! > x <",flush=True) + else: + print(" > "+player+" is safe! ^ _ ^",flush=True) + print(r"~ / |______________|ˉˉ",flush=True) + print(r'~ / /',flush=True) + print(r"~|_|_|",flush=True) + + + +def show_remains(remain_dict,last_player,last_action): + """Show the remaining players and their num of cards, one per row. + remain_dict is a dict of {player_name: num_of_cards}. + output should be like: + Player1: o o o o o + Player2: o o o <- if last_player is Player2 and last_action is "put out 2 cards" + Player3: (out) + if last_player and last_action are not None, + show the last action at his row of the output(Who has put out how many cards). + """ + global max_len + for player, num in remain_dict.items(): + print("# ",end="") # to flush the output buffer + if isinstance(num, list): + card_count = len(num) + else: + card_count = num + if card_count > 0: + cards = "o " * card_count + if player == last_player and last_action is not None: + print(f"{player.ljust(max_len)}: {cards} <- {last_player} {last_action}") + else: + print(f"{player.ljust(max_len)}: {cards}") + else: + print(f"{player}: (out)") + +def get_next_player(): + """获取下一个活跃玩家""" + global current_player_index, active_players + + if len(active_players) <= 1: + return current_player_index + + # 找到下一个活跃玩家 + next_index = (current_player_index + 1) % len(active_players) + return next_index + +def get_player_name(): + responses = [] + max_len = 0 + for i in range(4): + # get the player's name + name = input('#player %d \n'%(i+1)).title() + if len(name) > max_len: + max_len = len(name) + responses.append(name) + return max_len, responses + +def check_win_condition(): + """检查是否满足胜利条件""" + return len(active_players) == 1, active_players[0] if len(active_players) == 1 else None + +def get_player_input(player, hand): + """获取玩家输入""" + input('Turn for %s. Press Enter to continue...'%player) + print(f"\n{player}'s turn. Your cards: ") + display_cards(hand) + + # 获取出牌数量 + while True: + try: + num_to_play = int(input("How many cards do you want to play? (1-2): ")) + if 1 <= num_to_play <= 2 and num_to_play <= len(hand): + break + else: + print("Invalid input. Please enter 1 or 2, and make sure you have enough cards.") + except ValueError: + print("Please enter a valid number.") + + # 获取要出的牌 + print("Select cards to play (enter the card letters, separated by spaces):") + print("Available cards:", ", ".join(hand)) + + while True: + try: + selected_cards = input().strip().upper().split() + # 验证输入 + if len(selected_cards) != num_to_play: + print(f"Please select exactly {num_to_play} card(s).") + continue + + # 检查所选牌是否在手牌中 + valid_selection = True + temp_hand = hand.copy() + for card in selected_cards: + if card in temp_hand: + temp_hand.remove(card) + else: + print(f"Card {card} is not in your hand or has already been selected.") + valid_selection = False + break + + if valid_selection: + return selected_cards + except Exception as e: + print("Invalid input. Please try again.") + print('\n'*25,flush=True) + +def main(): + """主函数,运行骗子酒馆游戏""" + global target, players, active_players, player_hands, current_player_index, deck, max_len + + # 显示游戏说明 + show_instructions() + + # 初始化玩家 + max_len, players = get_player_name() + active_players = players.copy() + player_hands = {player: [] for player in players} + + # 初始化牌堆和发牌 + reset_deck() + deal_cards() + + # 初始化左轮手枪 + init_gun() + + # 随机选择目标牌 + target = random.choice(["J", "Q", "K", "A"]) + print(f"\nThe target of this game is: {target}") + + # 游戏主循环 + game_over = False + winner = None + last_player = None + last_action = None + + while not game_over: + current_player = active_players[current_player_index] + + # 如果当前玩家没有牌,重新发牌 + if len(player_hands[current_player]) == 0: + deal_cards() + # 如果重新发牌后仍然没有牌,可能是牌堆空了 + if len(player_hands[current_player]) == 0: + print(f"{current_player} has no cards to play! Skipping turn.") + current_player_index = get_next_player() + continue + + # 获取玩家输入 + cards_to_play = get_player_input(current_player, player_hands[current_player]) + num_to_play = len(cards_to_play) + + # 从手牌中移除这些牌 + for card in cards_to_play: + player_hands[current_player].remove(card) + + # 玩家声明出牌 (总是声明为目标牌) + print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") + + # 记录最后动作 + last_action = f"declared {num_to_play} {target}(s)" + last_player = current_player + + # 只有下家可以挑战 + next_player_index = get_next_player() + next_player = active_players[next_player_index] + + # 下家决定是否挑战 + challenge = input(f"{next_player}, do you challenge? (y/n): ").strip().lower() + will_challenge = challenge == 'y' + + if will_challenge: + print(f"{next_player} challenges the declaration!") + + # 验证声明 + declaration_false = is_false_declaration(cards_to_play) + + if not declaration_false: + print("The declaration was truthful!") + loser = next_player + else: + print("The declaration was a lie!") + loser = current_player + + # 执行枪击 + print(f"\nShooting at {loser}...") + time.sleep(1) # 增加 suspense + + is_dead = shoot() + shoot_at(loser, is_dead) + + # 如果被击中,移除该玩家 + if is_dead: + print(f"{loser} is eliminated from the game!") + active_players.remove(loser) + player_hands[loser] = [] + + # 检查游戏是否结束 + game_over, winner = check_win_condition() + if game_over: + break + else: + print(f"{next_player} does not challenge.") + + # 显示当前游戏状态 + print("\nCurrent game status:") + show_remains(player_hands, last_player, last_action) + + # 移动到下一个玩家 + current_player_index = get_next_player() + + # 游戏结束 + print(f"\n🎉 Game Over! {winner} wins! 🎉") + + +main() From b16d5316053f3d36db3e821f4033908d98c7a636 Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Sat, 30 Aug 2025 18:09:15 +0800 Subject: [PATCH 7/8] edit more logics, like 20 empty lines to the gap. --- src/gamesbyexample/liars-pub.py | 34 +++++++++++---------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/src/gamesbyexample/liars-pub.py b/src/gamesbyexample/liars-pub.py index eece3a1..9646ae8 100644 --- a/src/gamesbyexample/liars-pub.py +++ b/src/gamesbyexample/liars-pub.py @@ -195,34 +195,21 @@ def check_win_condition(): return len(active_players) == 1, active_players[0] if len(active_players) == 1 else None def get_player_input(player, hand): - """获取玩家输入""" - input('Turn for %s. Press Enter to continue...'%player) + """获取玩家输入(直接输入牌,不限制数量)""" + input('Turn for %s. Press Enter to continue...' % player) print(f"\n{player}'s turn. Your cards: ") display_cards(hand) - - # 获取出牌数量 - while True: - try: - num_to_play = int(input("How many cards do you want to play? (1-2): ")) - if 1 <= num_to_play <= 2 and num_to_play <= len(hand): - break - else: - print("Invalid input. Please enter 1 or 2, and make sure you have enough cards.") - except ValueError: - print("Please enter a valid number.") - - # 获取要出的牌 + print("Select cards to play (enter the card letters, separated by spaces):") print("Available cards:", ", ".join(hand)) - + while True: try: - selected_cards = input().strip().upper().split() - # 验证输入 - if len(selected_cards) != num_to_play: - print(f"Please select exactly {num_to_play} card(s).") + selected_cards = list(input().strip().upper()) + if not selected_cards: + print("You must select at least one card.") continue - + # 检查所选牌是否在手牌中 valid_selection = True temp_hand = hand.copy() @@ -233,12 +220,12 @@ def get_player_input(player, hand): print(f"Card {card} is not in your hand or has already been selected.") valid_selection = False break - + if valid_selection: return selected_cards except Exception as e: print("Invalid input. Please try again.") - print('\n'*25,flush=True) + print('\n' * 50, flush=True) def main(): """主函数,运行骗子酒馆游戏""" @@ -290,6 +277,7 @@ def main(): player_hands[current_player].remove(card) # 玩家声明出牌 (总是声明为目标牌) + print('\n'*30, flush=True) print(f"{current_player} plays {num_to_play} card(s) and declares: 'These are all {target}s!'") # 记录最后动作 From 19e0647d1c9fa414c91089e00327c32f4335ffea Mon Sep 17 00:00:00 2001 From: jack-tendy-538 Date: Sun, 7 Sep 2025 18:26:31 +0800 Subject: [PATCH 8/8] Add files via upload --- src/gamesbyexample/window-notificator.py | 60 ++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/gamesbyexample/window-notificator.py diff --git a/src/gamesbyexample/window-notificator.py b/src/gamesbyexample/window-notificator.py new file mode 100644 index 0000000..c70620c --- /dev/null +++ b/src/gamesbyexample/window-notificator.py @@ -0,0 +1,60 @@ +import random +import time + +def genWindow(): + notification = input("What notification would you like to see? ") + while len(notification) > 87: + print("Notification too long! Please keep it under 87 characters.") + notification = input("What notification would you like to see? ") + msg_length= max(30, len(notification))+4 + window = [ + '+' + '-' * (msg_length - 2) + '+', + '|' + ' ' * (msg_length - 2) + '|', + '| ' + notification.ljust(msg_length - 2) + ' |', + "|" + '[ Close Ctrl+C ]'.rjust(msg_length - 2) + " |", + '+' + '-' * (msg_length - 2) + '+' + ] + return window, msg_length + +def genRandomBg(width, height): + material = ['.','*','-']+[' ']*97 + bg = [] + for i in range(height): + line = ''.join(random.choice(material) for _ in range(width)) + bg.append(line) + return bg + +def placeWindow(x ,y, window): + global pattern + for i, line in enumerate(window): + pattern[y+i] = pattern[y+i][:x] + line + pattern[y+i][x+len(line):] + +# constants +pause = 0.1 +HEIGHT = 30 +WIDTH = 93 +window, windowWidth = genWindow() +windowHeight = len(window) +go_down, go_right = True, True +x, y = 0, 0 +while True: + pattern = genRandomBg(WIDTH, HEIGHT) + placeWindow(x, y, window) + print('\n'.join(pattern),flush=True) + time.sleep(pause) + if go_right: + x += 1 + else: + x -= 1 + if go_down: + y += 1 + else: + y -= 1 + if x + windowWidth >= WIDTH: + go_right = False + if x <= 0: + go_right = True + if y + windowHeight >= HEIGHT: + go_down = False + if y <= 0: + go_down = True \ No newline at end of file