def _choose_flag_to_deploy(self, state: GameState, card: PlayedCard, discardable=False) -> Optional[Flag]: candidates = [0] is_troop = isinstance(card, TroopCard) print("please select the flag to deploy:") for i, flag in enumerate(state.get_flags()): # iterate flags can be placed deployable = (self._can_play_troop_tactic_morales_for_flag(flag) if is_troop else self._can_play_tactic_envs_for_flag(flag)) stacked = flag.get_stacked_cards(self._id) opposite = flag.get_opposite_stacked_cards(self._id) stacked_envs = flag.get_stacked_envs(self._id) opposite_envs = flag.get_opposite_stacked_envs(self._id) formatted_line = (f"{repr(stacked_envs)} {repr(stacked)}" " vs " f"{repr(opposite)} {repr(opposite_envs)}") if deployable: print(f"[{i + 1}] -- {formatted_line}") candidates.append(i + 1) else: print(f"[x] -- {formatted_line}") if discardable: print("[0] -- discard from the game") else: print("[0] -- return to card selection") flag_index = await_user_num(candidates) return state.get_flags()[flag_index - 1] if flag_index > 0 else None
def aggregate_used_troops(state: GameState) -> List[TroopCard]: cards: List[TroopCard] = [] # aggregate from all flags for flag in state.get_flags(): stacks = chain.from_iterable([ flag.get_stacked_cards(PLAYER_A), flag.get_stacked_cards(PLAYER_B) ]) cards.extend([c for c in stacks if isinstance(c, TroopCard)]) # ... and discarded cards ops = chain.from_iterable( [state.get_operations(PLAYER_A), state.get_operations(PLAYER_B)]) discards = [t for t in [op.get_discarded_troop_card() for op in ops] if t] cards.extend(discards) return cards
def vshuman_main(arg: List[str]) -> None: game = Game(GameState.new(), (HumanPlayer(PLAYER_A), HumanPlayer(PLAYER_B))) while game.run() == PLAYER_UNRESOLVED: pass print(f"Player {game.run() + 1} win!") print(repr(game.get_state()))
def _play_scout(self, state: GameState, card: TacticGuileCard) -> Optional[GameState]: assert card.get_tactics() == TacticGuiles.SCOUT print("choose draw pattern?") print("[1] -- draw 3 cards from troops deck") print( "[2] -- draw 2 cards from troops deck and draw 1 card from tactics deck" ) print( "[3] -- draw 1 card from troops deck and draw 2 cards from tactics deck" ) print("[4] -- draw 3 cards from tactics deck") print("[0] -- return to select a card") user_in = await_user_num(range(5)) if user_in == 0: return None # copy to new state state = state.clone() draw_tactics_num = user_in - 1 peek_cards: List[Card] = [] peek_cards.extend(state.get_tactics_deck().peek(draw_tactics_num)) peek_cards.extend(state.get_troops_deck().peek(3 - draw_tactics_num)) print("scouted cards: ") copy_hands = self.get_hands(state).copy() # remove the used card copy_hands.remove(card) for i, c in enumerate(peek_cards): print(f"[{i}]: {repr(c)}") copy_hands.append(c) # sort my hands copy_hands.sort() # add to hand print("choose 2 cards return to decks:") for i, c in enumerate(copy_hands): print(f"[{i + 1}]: {repr(c)}") input_cand = list(range(1, len(copy_hands) + 1)) in_1 = await_user_num(input_cand) ret_card_1 = copy_hands[in_1 - 1] input_cand.remove(in_1) in_2 = await_user_num(input_cand) ret_card_2 = copy_hands[in_2 - 1] return self._play_tactic_guile_scout( state, card, (draw_tactics_num, 3 - draw_tactics_num), (ret_card_1, ret_card_2), )
def __init__(self, server_host, server_port): self.CLIENT = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.HOST = server_host self.PORT = server_port self.ADDR = (self.HOST, self.PORT) self.player_num = None gamestate = GameState()
def _draw_deck(self, state: GameState) -> Optional[Card]: troops_deck = state.get_troops_deck() tactics_deck = state.get_tactics_deck() draw_troops = troops_deck.is_remain() draw_tactics = tactics_deck.is_remain() if draw_troops and draw_tactics: print("draw card from?") print(f"[0] -- troops deck, remains {len(troops_deck)} cards") print(f"[1] -- tactics deck, remains {len(tactics_deck)} cards") if await_user_num([0, 1]) == 0: draw_tactics = False else: draw_troops = False if draw_troops: return troops_deck.draw() if draw_tactics: return tactics_deck.draw() # both decks are empty return None
def play(self, state: GameState) -> GameState: print(f"{self._get_user_repr()}: TURN START {'-'*60}") suppress_draw = False while True: card = self._choose_hand_to_play(state) if card is None: # pass print(" --> passed.") return state print(f"You chose: {repr(card)}") if isinstance(card, TroopAndTacticMoraleCard): flag = self._choose_flag_to_deploy(state, card) if flag is None: print(" --> re-select the card") continue state = self._play_troop_tactic_morales_for_flag( state, flag, card) break if isinstance(card, TacticEnvironmentCard): flag = self._choose_flag_to_deploy(state, card) if flag is None: print(" --> re-select the card") continue state = self._play_tactic_envs_for_flag(state, flag, card) break if isinstance(card, TacticGuileCard): new_state = self._play_tactic_guile(state, card) if new_state is None: print(" --> re-select the card") continue if card.get_tactic_guiles() == TacticGuiles.SCOUT: # card already drew suppress_draw = True state = new_state break raise ValueError(f"Unknown card: {card}") if not suppress_draw: card = self._draw_deck(state) if card is not None: state = state.clone() state.add_hand(self.get_id(), card) print(f"{self._get_user_repr()}: TURN END {'-'*60}") return state
def test_solve_failed_wedge_but_battalion_vs_battalion(): # noqa: D103 state = GameState.new() flag: Flag = state.get_flags()[0] flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 3)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 4)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 7)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 1)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 3)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 6)) assert _check_resolve(flag, state) == PLAYER_A
def test_solve_wild_wedge_vs_phalanx(): # noqa: D103 state = GameState.new() flag: Flag = state.get_flags()[0] flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 3)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 4)) flag.add_stack(PLAYER_A, CardGenerator.tactic(TacticMorales.LEADER_ALEXANDER)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 8)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.GREEN, 8)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.YELLOW, 8)) assert _check_resolve(flag, state) == PLAYER_A
def test_solve_same_wedge_reversed(): # noqa: D103 state = GameState.new() flag: Flag = state.get_flags()[0] flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 2)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 3)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 4)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 3)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 4)) flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 2)) assert _check_resolve(flag, state) == PLAYER_B
def test_solve_superwild_wedge_vs_wedge(): # noqa: D103 state = GameState.new() flag: Flag = state.get_flags()[0] flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 9)) flag.add_stack(PLAYER_A, CardGenerator.tactic(TacticMorales.COMPANION_CAVALRY)) flag.add_stack(PLAYER_A, CardGenerator.tactic(TacticMorales.LEADER_ALEXANDER)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 2)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 3)) flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 4)) assert _check_resolve(flag, state) == PLAYER_A
def resolve(state: GameState) -> None: used_cards = aggregate_used_troops(state) for flag in state.get_flags(): if flag.is_resolved(): # already resolved continue resolve = check_resolvable_for_single_flag(flag, used_cards) # resolve flag if resolve != PLAYER_UNRESOLVED: flag.resolve(resolve)
def test_resolve_unresolvable(): # noqa: D103 state = GameState.new() flag: Flag = state.get_flags()[0] assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 3)) assert flag.get_last_stacked_player() == PLAYER_A assert len(flag.get_stacked_cards(PLAYER_A)) == 1 assert len(flag.get_stacked_cards(PLAYER_B)) == 0 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 4)) assert flag.get_last_stacked_player() == PLAYER_A assert len(flag.get_stacked_cards(PLAYER_A)) == 2 assert len(flag.get_stacked_cards(PLAYER_B)) == 0 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_A, CardGenerator.troop(TroopColors.RED, 5)) assert flag.get_last_stacked_player() == PLAYER_A assert len(flag.get_stacked_cards(PLAYER_A)) == 3 assert len(flag.get_stacked_cards(PLAYER_B)) == 0 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 4)) assert flag.get_last_stacked_player() == PLAYER_B assert len(flag.get_stacked_cards(PLAYER_A)) == 3 assert len(flag.get_stacked_cards(PLAYER_B)) == 1 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 5)) assert flag.get_last_stacked_player() == PLAYER_B assert len(flag.get_stacked_cards(PLAYER_A)) == 3 assert len(flag.get_stacked_cards(PLAYER_B)) == 2 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.remove_stack_troops(PLAYER_A, TroopColors.RED, 3) assert flag.get_last_stacked_player() == PLAYER_B assert len(flag.get_stacked_cards(PLAYER_A)) == 2 assert len(flag.get_stacked_cards(PLAYER_B)) == 2 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED flag.add_stack(PLAYER_B, CardGenerator.troop(TroopColors.BLUE, 6)) assert flag.get_last_stacked_player() == PLAYER_B assert len(flag.get_stacked_cards(PLAYER_A)) == 2 assert len(flag.get_stacked_cards(PLAYER_B)) == 3 assert _check_resolve(flag, state) == PLAYER_UNRESOLVED
def _choose_deployed_troops( self, state: GameState, player: int, troops_only: bool = False ) -> Optional[Tuple[Flag, TroopAndTacticMoraleCard]]: flags = state.get_flags() while True: print("choose the flag: ") input_candidates = [0] for i, f in enumerate(flags): stacked_cards_of_flag = f.get_stacked_cards(player) stack_cards_repr = ", ".join( [repr(c) for c in stacked_cards_of_flag]) if f.is_resolved(): print(f"[-]: resolved, {stack_cards_repr}") else: input_candidates.append(i + 1) print(f"[{i + 1}]: {stack_cards_repr}") print("[0]: return to select the card to play") flag_index = await_user_num(input_candidates) if flag_index == 0: return None flag = flags[flag_index - 1] cards = flag.get_stacked_cards(player) print("choose the card: ") input_candidates = [0] for i, c in enumerate(cards): if troops_only and isinstance(c, TacticCard): print(f"[x]: {repr(c)}") else: print(f"[{i + 1}]: {repr(c)}") input_candidates.append(i + 1) print("[0]: return to select the flag") card_index = await_user_num(input_candidates) if card_index == 0: continue return flag, cards[card_index - 1]
def start_server(): """ Sets up server and begins listening for client connections. """ # Use the global variables global gamestate global client_count # Create a socket object SERVER = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Use localhost and grab port from commandline arg HOST = sys.argv[1] PORT = int(sys.argv[2]) # Attempt bind to (host, port) pair try: SERVER.bind((HOST, PORT)) except socket.error: print("Binding to " + HOST + ":" + str(PORT) + "failed.") SERVER.close() sys.exit() # Start listeing for connections, max of two SERVER.listen(2) print("SERVER listening on " + HOST + ":" + str(PORT)) # Main server loop while True: if client_count < 2: # Accept incoming connection print("Waiting for client {}...".format(client_count + 1)) connection, address = SERVER.accept() print("Established connection with " + address[0] + ":" + str(address[1])) # Increment global client counter client_count += 1 # Keep track of whose turn it is player_num = 1 if client_count == 1: # Create new gamestate object gamestate = GameState() else: # One client already connected so # this connection will be player 2 player_num = 2 # Create thread to handle client t = threading.Thread(target=client_thread, args=(connection, player_num)) t.start() if client_count < 2 and gamestate.ready(): # Game over, exit loop break print("\nServer closing...") SERVER.close()