def test_must_follow_suit_must_use_higher_trump(self):
    """
    Player.ONE plays the trump Queen. Player.TWO has three trump cards.
    The valid cards are only the trump King and Ace.
    """
    game_state = get_game_state_with_empty_talon_for_tests()

    with GameStateValidator(game_state):
      ace_clubs = game_state.cards_in_hand.one[0]
      queen_clubs = game_state.cards_in_hand.two[3]
      game_state.cards_in_hand.two[3] = ace_clubs
      game_state.cards_in_hand.one[0] = queen_clubs

    action = PlayCardAction(PlayerId.ONE, queen_clubs)
    self.assertTrue(action.can_execute_on(game_state))
    game_state = action.execute(game_state)
    num_legal_cards = 0
    valid_cards = [Card(Suit.CLUBS, CardValue.KING),
                   Card(Suit.CLUBS, CardValue.ACE)]
    for card in game_state.cards_in_hand[PlayerId.TWO]:
      action = PlayCardAction(PlayerId.TWO, card)
      is_legal_card = action.can_execute_on(game_state)
      self.assertEqual(card in valid_cards, is_legal_card, msg=f"{card}")
      self.assertEqual(is_legal_card,
                       action.can_execute_on(game_state.next_player_view()))
      if is_legal_card:
        num_legal_cards += 1
    self.assertEqual(2, num_legal_cards)
 def test_play_trick_talon_closed_opponent_cannot_follow_suit_or_trump(self):
   game_state = get_game_state_for_tests()
   with GameStateValidator(game_state):
     trick = game_state.won_tricks.one.pop(0)
     game_state.talon.append(trick.one)
     game_state.talon.append(trick.two)
     game_state.trick_points.one -= trick.one.card_value
     game_state.trick_points.one -= trick.two.card_value
     trick = game_state.won_tricks.two.pop(-1)
     game_state.talon.append(trick.one)
     game_state.talon.append(trick.two)
     game_state.trick_points.two -= trick.one.card_value
     game_state.trick_points.two -= trick.two.card_value
     game_state.next_player = PlayerId.TWO
   game_state.close_talon()
   self.assertEqual([False, False, False, False, False],
                    [card.public for card in game_state.talon])
   action = PlayCardAction(PlayerId.TWO, Card(Suit.DIAMONDS, CardValue.QUEEN))
   self.assertTrue(action.can_execute_on(game_state))
   game_state = action.execute(game_state)
   self.assertEqual([False, False, False, False, False],
                    [card.public for card in game_state.talon])
   action = PlayCardAction(PlayerId.ONE, Card(Suit.HEARTS, CardValue.QUEEN))
   self.assertTrue(action.can_execute_on(game_state))
   game_state = action.execute(game_state)
   self.assertEqual([True, False, False, True, True],
                    [card.public for card in game_state.talon])
  def test_must_follow_suit_can_play_any_higher_card_same_suit(self):
    """
    Player.ONE has two cards of the same suit as the card played by Player.TWO,
    both higher. Player.ONE also has a trump card. Any of the two cards from the
    same suit as the card played by Player.TWO are valid.
    """
    game_state = get_game_state_for_tests()

    with GameStateValidator(game_state):
      queen_hearts = game_state.cards_in_hand.one[0]
      queen_clubs = game_state.cards_in_hand.two[4]
      game_state.cards_in_hand.two[4] = queen_hearts
      game_state.cards_in_hand.one[0] = queen_clubs
      game_state.close_talon()
      game_state.next_player = PlayerId.TWO

    self.assertTrue(game_state.must_follow_suit())
    jack_spades = Card(Suit.SPADES, CardValue.JACK)
    action = PlayCardAction(PlayerId.TWO, jack_spades)
    self.assertTrue(action.can_execute_on(game_state))
    game_state = action.execute(game_state)
    num_legal_cards = 0
    for card in game_state.cards_in_hand[PlayerId.ONE]:
      action = PlayCardAction(PlayerId.ONE, card)
      is_legal_card = action.can_execute_on(game_state)
      self.assertEqual(card.suit == Suit.SPADES, is_legal_card, msg=f"{card}")
      self.assertEqual(is_legal_card,
                       action.can_execute_on(game_state.next_player_view()))
      if is_legal_card:
        num_legal_cards += 1
    self.assertEqual(2, num_legal_cards)
 def test_must_follow_trump_can_discard_any_card(self):
   game_state = get_game_state_for_tests()
   with GameStateValidator(game_state):
     game_state.next_player = PlayerId.TWO
     game_state.close_talon()
   action = PlayCardAction(PlayerId.TWO,
                           game_state.cards_in_hand[PlayerId.TWO][0])
   game_state = action.execute(game_state)
   for card in game_state.cards_in_hand[PlayerId.ONE]:
     action = PlayCardAction(PlayerId.ONE, card)
     self.assertTrue(action.can_execute_on(game_state))
     self.assertTrue(action.can_execute_on(game_state.next_player_view()))
 def test_must_follow_suit_must_use_trump(self):
   """Player.TWO has no hearts, so they must use one of the trump cards."""
   game_state = get_game_state_for_tests()
   game_state.close_talon()
   self.assertTrue(game_state.must_follow_suit())
   action = PlayCardAction(PlayerId.ONE,
                           game_state.cards_in_hand[PlayerId.ONE][0])
   self.assertTrue(action.can_execute_on(game_state))
   game_state = action.execute(game_state)
   num_legal_cards = 0
   for card in game_state.cards_in_hand[PlayerId.TWO]:
     action = PlayCardAction(PlayerId.TWO, card)
     is_legal_card = action.can_execute_on(game_state)
     self.assertEqual(card.suit == game_state.trump, is_legal_card,
                      msg=f"{card}")
     self.assertEqual(is_legal_card,
                      action.can_execute_on(game_state.next_player_view()))
     if is_legal_card:
       num_legal_cards += 1
   self.assertEqual(3, num_legal_cards)
 def test_can_only_execute_on_players_turn(self):
   game_state = get_game_state_for_tests()
   card = game_state.cards_in_hand[PlayerId.ONE][0]
   action_one = PlayCardAction(PlayerId.ONE, card)
   self.assertTrue(action_one.can_execute_on(game_state))
   self.assertTrue(action_one.can_execute_on(game_state.next_player_view()))
   action_two = PlayCardAction(PlayerId.TWO,
                               game_state.cards_in_hand[PlayerId.TWO][0])
   self.assertFalse(action_two.can_execute_on(game_state))
   self.assertFalse(action_two.can_execute_on(game_state.next_player_view()))
   game_state = action_one.execute(game_state)
   self.assertFalse(action_one.can_execute_on(game_state))
   self.assertFalse(action_one.can_execute_on(game_state.next_player_view()))
   self.assertTrue(action_two.can_execute_on(game_state))
   self.assertTrue(action_two.can_execute_on(game_state.next_player_view()))
  def test_must_follow_suit_cannot_play_lower_card_same_suit(self):
    """
    Player.ONE has two cards of the same suit as the card played by Player.TWO,
    one lower and one higher. Player.ONE also has a trump card. The only valid
    card is the higher card having the same suit as the card played by
    Player.TWO.
    """
    game_state = get_game_state_for_tests()

    with GameStateValidator(game_state):
      ten_spades = game_state.cards_in_hand.one[3]
      jack_spades = game_state.cards_in_hand.two[3]
      game_state.cards_in_hand.two[3] = ten_spades
      game_state.cards_in_hand.one[3] = jack_spades

      queen_hearts = game_state.cards_in_hand.one[0]
      queen_clubs = game_state.cards_in_hand.two[4]
      game_state.cards_in_hand.two[4] = queen_hearts
      game_state.cards_in_hand.one[0] = queen_clubs

      game_state.close_talon()
      game_state.next_player = PlayerId.TWO

    self.assertTrue(game_state.must_follow_suit())
    action = PlayCardAction(PlayerId.TWO, ten_spades)
    self.assertTrue(action.can_execute_on(game_state))
    game_state = action.execute(game_state)
    ace_spades = Card(Suit.SPADES, CardValue.ACE)
    num_legal_cards = 0
    for card in game_state.cards_in_hand[PlayerId.ONE]:
      action = PlayCardAction(PlayerId.ONE, card)
      is_legal_card = action.can_execute_on(game_state)
      self.assertEqual(card == ace_spades, is_legal_card, msg=f"{card}")
      self.assertEqual(is_legal_card,
                       action.can_execute_on(game_state.next_player_view()))
      if is_legal_card:
        num_legal_cards += 1
    self.assertEqual(1, num_legal_cards)
 def test_play_trick_talon_closed_opponent_cannot_follow_suit(self):
   game_state = get_game_state_for_tests()
   with GameStateValidator(game_state):
     trick = game_state.won_tricks.two.pop(0)
     game_state.talon.append(trick.one)
     game_state.talon.append(trick.two)
     trick = game_state.won_tricks.two.pop(0)
     game_state.talon.append(trick.one)
     game_state.talon.append(trick.two)
     game_state.trick_points.two = 0
   game_state.close_talon()
   self.assertEqual([False, False, False, False, False],
                    [card.public for card in game_state.talon])
   action = PlayCardAction(PlayerId.ONE, Card(Suit.HEARTS, CardValue.TEN))
   self.assertTrue(action.can_execute_on(game_state))
   game_state = action.execute(game_state)
   self.assertEqual([False, False, False, False, False],
                    [card.public for card in game_state.talon])
   action = PlayCardAction(PlayerId.TWO, Card(Suit.CLUBS, CardValue.JACK))
   self.assertTrue(action.can_execute_on(game_state))
   game_state = action.execute(game_state)
   self.assertEqual([False, True, True, False, False],
                    [card.public for card in game_state.talon])
 def test_cannot_play_cards_not_in_hand(self):
   game_state = get_game_state_for_tests()
   for card in Card.get_all_cards():
     action = PlayCardAction(PlayerId.ONE, card)
     self.assertEqual(card in game_state.cards_in_hand[PlayerId.ONE],
                      action.can_execute_on(game_state))
     self.assertEqual(card in game_state.cards_in_hand[PlayerId.ONE],
                      action.can_execute_on(game_state.next_player_view()))
   action = PlayCardAction(PlayerId.ONE,
                           game_state.cards_in_hand[PlayerId.ONE][0])
   self.assertTrue(action.can_execute_on(game_state))
   self.assertTrue(action.can_execute_on(game_state.next_player_view()))
   game_state = action.execute(game_state)
   for card in Card.get_all_cards():
     action = PlayCardAction(PlayerId.TWO, card)
     self.assertEqual(card in game_state.cards_in_hand[PlayerId.TWO],
                      action.can_execute_on(game_state))
     self.assertEqual(card in game_state.cards_in_hand[PlayerId.TWO],
                      action.can_execute_on(game_state.next_player_view()))