def deal_cards_without_last_cards(self): undealed_cards = self.cards_blocks.pop() self.cards -= undealed_cards MessagePoster.post_hint(hint_type='person_dealed_cards', unprinted_cards=str(undealed_cards), output_name=self.output_name) return undealed_cards
def show_credit_board(self): ## 用户名左右的空格数 empty_space_length = 4 ## 最长用户名的长度, 供后面对齐时用 max_name_length = self.people.max_name_length ## 标题与内容的分割线 ## 3代表' | ', 5代表'xx分' title_line = f'{"-" * (max_name_length + empty_space_length + 3 + 5)}' ## 标题 title = '积分榜'.center(len(title_line)) title_info = [title, title_line] credit_info = [] person = self.people.head for i in range(3): credit_info.append( f'{person.name.center(max_name_length + empty_space_length)} | {person.credits}分' ) person = person.next ## 按现有积分降序 credit_info = sorted(credit_info, key=lambda x: int(re.findall('(\d+)分', x)[0]), reverse=True) credit_board = '\n'.join(title_info + credit_info) MessagePoster.post_hint(hint_type='show_credit_board', credit_board=credit_board)
def check_results(self): ## 把赢家找出来 person = self.people.head ## 宣布胜利者并计分 if person.is_real: if person.identity == 'landlord': MessagePoster.post_hint(hint_type='win_as_landlord') else: MessagePoster.post_hint(hint_type='win_as_peasant1') elif person.identity == 'landlord': MessagePoster.post_hint(hint_type='lose_as_peasant') elif (person.next.is_real and person.next.identity == 'peasant') or \ (person.next.next.is_real and person.next.next.identity == 'peasant'): MessagePoster.post_hint(hint_type='win_as_peasant2') else: MessagePoster.post_hint(hint_type='lose_as_landlord') ## 计分 if person.identity == 'landlord': person.change_credits(self.game_credits * 2) person.next.change_credits(-self.game_credits) person.next.next.change_credits(-self.game_credits) else: person.change_credits(self.game_credits) if person.next.identity == 'landlord': person.next.change_credits(-2 * self.game_credits) person.next.next.change_credits(self.game_credits) else: person.next.change_credits(self.game_credits) person.next.next.change_credits(-2 * self.game_credits)
def __init__(self): self.initialized = False MessagePoster.post_hint(hint_type='welcome') self.enter() self.game_credits = None self.all_cards = AllCards() self.initialized = True
def send_cards(self): """发牌""" MessagePoster.post_hint(hint_type='new_game') MessagePoster.post_hint(hint_type='start_sending_cards') person = self.people.head for i in range(3): unsent_cards = self.all_cards.give_cards(17) person.take_cards(unsent_cards) person = person.next
def deal_landlord_score(self, last_landlord_score): if self.landlord_score is None: self.landlord_score = min(self.cards.cal_confidence(), 3) if self.landlord_score > last_landlord_score: MessagePoster.post_hint(hint_type='person_gave_landlord_score', output_name=self.output_name, landlord_score=str(self.landlord_score)) return self.landlord_score else: MessagePoster.post_hint( hint_type='person_abandon_giving_landlord_score', output_name=self.output_name) return
def enter(self, default_player_credits=100): while True: user_name = MessageGetter.get_order(order_type='user_name') if isinstance(user_name, GameExiter): self.exit() continue break ## 数据文件不存在时, 直接新建数据 if os.path.exists(f'{user_name}.json'): try: with open(f'{user_name}.json') as f: user_profile = json.load(f) ## 当数据文件合法时, 询问玩家是否覆盖数据 ## 如果覆盖, 则重置积分 if user_profile['user_name'] == user_name and isinstance( user_profile['credits'], int): while True: overload_data_order = MessageGetter.get_order( order_type='overload_data') if isinstance(overload_data_order, GameExiter): self.exit() continue else: break if overload_data_order == 'y': credits = default_player_credits else: credits = user_profile['credits'] else: raise ValueError except Exception as e: MessagePoster.post_hint(hint_type='overload_broken_data') else: credits = default_player_credits player = Player(name=user_name, credits=credits) robot1 = Robot(name='robot1') robot2 = Robot(name='robot2') self.people = People(player, robot1, robot2)
def exit(self): confirm_exit = MessageGetter.get_order(order_type='confirm_exit') if confirm_exit == 'n': return if not self.initialized: exit() player = self.people.get_player() user_profile = {'user_name': player.name, 'credits': player.credits} save_data_order = MessageGetter.get_order(order_type='save_data') if save_data_order == 'y': with open(f'{player.name}.json', 'w') as f: json.dump(user_profile, f) ## 退出整个程序 MessagePoster.post_hint(hint_type='thank_you') exit()
def deal_landlord_score(self, last_landlord_score): while True: landlord_score = MessageGetter.get_order( order_type='landlord_score', min_landlord_score=str(last_landlord_score + 1)) ## 退出游戏 if isinstance(landlord_score, GameExiter): return GameExiter() ## 如果玩家本轮不叫地主, 则返回None if landlord_score == 'p': MessagePoster.post_hint( hint_type='person_abandon_giving_landlord_score', output_name=self.output_name) return ## 地主分的验证 landlord_score = int(landlord_score) if landlord_score > last_landlord_score: MessagePoster.post_hint(hint_type='person_gave_landlord_score', output_name=self.output_name, landlord_score=str(landlord_score)) return landlord_score else: MessagePoster.post_hint(hint_type='landlord_score_too_small')
def deal_cards(self): person = self.people.head last_cards = None last_person_identity = None pass_cnt = 0 ## 提示游戏正式开始 MessagePoster.post_hint(hint_type='formly_start_game') ## 开始出牌 while True: ## 新的一轮牌 if last_cards is None: MessagePoster.post_hint(hint_type='new_round') dealed_cards = person.deal_cards(last_cards, last_person_identity) if isinstance(dealed_cards, GameExiter): self.exit() continue elif dealed_cards is None: pass_cnt += 1 if pass_cnt == 2: last_cards = None last_person_identity = None else: last_cards = dealed_cards last_person_identity = person.identity pass_cnt = 0 ## 炸弹使积分翻倍 if dealed_cards.is_bumb(): MessagePoster.post_hint(hint_type='double_game_credits', output_name=person.output_name) self.double_game_credits() ## 牌空说明有人出完了牌 if person.cards.is_empty(): break person = person.next ## 将赢家设置为链表的头 self.people.set_head(person)
def deal_cards_with_last_cards(self, last_cards, last_person_identity): ## 不管10以上的同伙的牌 if self.identity == last_person_identity and last_cards.size >= Card( 'J').size: MessagePoster.post_hint(hint_type='person_abandon_dealing_cards', output_name=self.output_name) return for undealed_cards in self.cards_blocks[::-1]: if undealed_cards > last_cards: self.cards_blocks.remove(undealed_cards) self.cards -= undealed_cards MessagePoster.post_hint(hint_type='person_dealed_cards', output_name=self.output_name, unprinted_cards=str(undealed_cards)) return undealed_cards else: MessagePoster.post_hint(hint_type='person_abandon_dealing_cards', output_name=self.output_name) return
def deal_cards(self, last_cards, last_person_identity=None): ## 先给玩家看自己手中的牌 MessagePoster.post_hint(hint_type='player_show_cards', unshowed_cards=str(self.cards)) ## 让用户一直出牌, 直到牌大过上家或者放弃出牌 while True: raw_order = MessageGetter.get_order(order_type='deal_cards') ## 退出游戏 if isinstance(raw_order, GameExiter): return GameExiter() ## 如果玩家要不起/不要, 则返回None if raw_order == 'p': ## 有牌权出牌不能跳过 if last_cards is not None: MessagePoster.post_hint( hint_type='person_abandon_dealing_cards', output_name=self.output_name) return else: MessagePoster.post_hint( hint_type= 'player_can_not_skip_deal_cards_without_last_cards') continue undealed_cards = Cards([Card(pattern) for pattern in raw_order]) ## 牌的验证 ## 牌的子集验证 if not undealed_cards in self.cards: MessagePoster.post_hint( hint_type='invaild_cards_pattern_or_too_many_cards') continue meta_data = undealed_cards.cal_meta_data() ## 牌的元数据验证(实际是有效性验证) if meta_data is None: MessagePoster.post_hint(hint_type='invaild_cards_species') continue ## 出牌 ## 如果是有牌权出牌, 可以直接出 if last_cards is None: MessagePoster.post_hint(hint_type='person_dealed_cards', output_name=self.output_name, unprinted_cards=str(undealed_cards)) self.cards -= undealed_cards return undealed_cards ## 牌型相符且牌比上家大(考虑到炸弹类型) elif undealed_cards > last_cards: MessagePoster.post_hint(hint_type='person_dealed_cards', output_name=self.output_name, unprinted_cards=str(undealed_cards)) self.cards -= undealed_cards return undealed_cards ## 牌型不符或牌型一样但没有上家大 else: MessagePoster.post_hint(hint_type='cards_size_too_small') continue
def decide_landlord(self): ## 先给玩家看一下自己的牌 person = self.people.get_player() MessagePoster.post_hint(hint_type='player_show_cards', unshowed_cards=str(person.cards)) ## 叫地主的次数 decision_cnt = 0 ## 跳过的次数, 跳过2次后, 下一个人就是赢家 pass_cnt = 0 person = self.people.head last_landlord_score = 0 ## 两轮都没能确定地主后, 随机决定地主 while decision_cnt / 3 < 2: landlord_score = person.deal_landlord_score(last_landlord_score) if isinstance(landlord_score, GameExiter): self.exit() continue if landlord_score == 3: last_landlord_score = landlord_score break elif landlord_score is None: ## 只有有人叫过地主时, pass_cnt才有效 if last_landlord_score > 0: pass_cnt += 1 ## 此时下一个人是地主 if pass_cnt == 2: person = person.next break ## 此时意味着叫了地主, 但是没到3分 else: pass_cnt = 0 last_landlord_score = landlord_score person = person.next decision_cnt += 1 ## 随机决定地主 else: MessagePoster.post_hint( hint_type='system_will_decide_landlord_randomly') choice_steps = random.randint(0, 3) for i in range(choice_steps): person = person.next ## 如果没人叫过地主, 则设置地主分为1分 if last_landlord_score == 0: last_landlord_score = 1 ## 对每个人设置身份 person.set_identity('landlord') person.next.set_identity('peasant') person.next.next.set_identity('peasant') ## 宣布地主 MessagePoster.post_hint(hint_type='announce_landlord', landlord_name=person.output_name, peasant1_name=person.next.output_name, peasant2_name=person.next.next.output_name) ## 展示地主应得的3张底牌 MessagePoster.post_hint(hint_type='show_landlord_cards', landlord_cards=str(self.all_cards)) ## 把3张底牌给地主 self.send_landlord_cards(person) ## 如果地主是玩家, 给玩家看一下现有的牌 if person.is_real: MessagePoster.post_hint(hint_type='player_show_cards', unshowed_cards=str(person.cards)) ## 设置地主先出牌 self.people.set_head(person) ## 最终的地主分数就是该局的分数 self.game_credits = last_landlord_score ## 宣布本局的分数 MessagePoster.post_hint(hint_type='announce_game_credits', game_credits=str(self.game_credits))