Exemple #1
0
 def test_no_marriage_available(self):
   self.assertIsNone(get_best_marriage(
     [
       PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
       PlayCardAction(PlayerId.ONE, Card.from_string("js")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
       PlayCardAction(PlayerId.ONE, Card.from_string("qc")),
     ], Suit.SPADES))
Exemple #2
0
 def test_save_marriages(self):
   self._run_test_cases_with_option("save_marriages", [False, True], [
     # Do not break a marriage to win a Jack.
     {
       "cards_in_hand": (["qd", "kd", "ad", "js", "qs"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("kd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("js")),
       ]
     },
   ])
Exemple #3
0
 def test_from_string(self):
   self.assertEqual(Card(Suit.HEARTS, CardValue.TEN), Card.from_string("th"))
   with self.assertRaisesRegex(KeyError, "z"):
     Card.from_string("tz")
   with self.assertRaisesRegex(KeyError, "z"):
     Card.from_string("zh")
   with self.assertRaisesRegex(AssertionError, "must be a two letter string"):
     Card.from_string("multiple_chars")
Exemple #4
0
 def test_can_close_talon(self):
   self._run_test_cases_with_option("can_close_talon", [False, True], [
     # The talon is already closed. Discard the smallest trump card.
     {
       "cards_in_hand": (["ts", "qs"], ["as", None]),
       "trump": Suit.SPADES,
       "trump_card": "ks",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qd")], [("tc", "ac"), ("jh", "jc")]),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
       ]
     },
     # There is a high chance the opponent has a Heart or a Club.
     {
       "cards_in_hand": (["qh", "ah", "ad", "kc", "kd"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "as",
       "talon": [None],
       "won_tricks": ([("qs", "ac"), ("ks", "jd")],
                      [("tc", "js"), ("jh", "jc")]),
       "marriage_suits": ([Suit.SPADES], []),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qh")),
         CloseTheTalonAction(PlayerId.ONE),
       ]
     },
     # There is a small chance to win if we close the talon.
     {
       "cards_in_hand": (["qh", "qd", "ac", "ks", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qd")),
       ]
     },
     # Make sure the player computes the winning probabilities as if suits must
     # be followed.
     {
       "cards_in_hand": (["qc", "ts", "ah", "as", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None],
       "won_tricks": ([("td", "kd"), ("qd", "jc")], [("jh", "kh")]),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qc")),
         CloseTheTalonAction(PlayerId.ONE),
       ]
     },
   ])
Exemple #5
0
def _game_view_from_dict(fields: Dict[str, Any]) -> GameState:
  cards_in_hand = fields["cards_in_hand"]
  fields["cards_in_hand"] = PlayerPair(card_list_from_string(cards_in_hand[0]),
                                       card_list_from_string(cards_in_hand[1]))
  trump_card = fields.get("trump_card", None)
  fields["trump_card"] = \
    Card.from_string(trump_card) if trump_card is not None else None
  fields["talon"] = card_list_from_string(fields.get("talon", []))
  won_tricks = fields.get("won_tricks", ([], []))
  fields["won_tricks"] = PlayerPair(
    [_trick_from_string_tuple(str_tuple) for str_tuple in won_tricks[0]],
    [_trick_from_string_tuple(str_tuple) for str_tuple in won_tricks[1]])
  marriage_suits = fields.get("marriage_suits", None)
  if marriage_suits is not None:
    fields["marriage_suits"] = PlayerPair(*marriage_suits)
  trick_points = fields.get("trick_points", None)
  if trick_points is not None:
    fields["trick_points"] = PlayerPair(*trick_points)
  else:
    trick_points = PlayerPair(0, 0)
    for player in PlayerId:
      if len(fields["won_tricks"][player]) > 0 and \
          fields.get("marriage_suits", None) is not None:
        for suit in fields["marriage_suits"][player]:
          trick_points[player] += 40 if suit == fields["trump"] else 20
      for trick in fields["won_tricks"][player]:
        trick_points[player] += trick.one.card_value + trick.two.card_value
    fields["trick_points"] = trick_points
  trick = fields.get("current_trick", None)
  if trick is not None:
    fields["current_trick"] = PlayerPair(
      Card.from_string(trick[0]) if trick[0] is not None else None,
      Card.from_string(trick[1]) if trick[1] is not None else None)
  game_view = GameState(**fields)
  logging.debug("HeuristicPlayerTest: Using game view: %s",
                pprint.pformat(str(game_view)))
  return game_view
Exemple #6
0
 def test_avoid_direct_loss(self):
   self._run_test_cases_with_option("avoid_direct_loss", [False, True], [
     # Play a trump card instead of discarding the smallest non trump card.
     {
       "cards_in_hand": (["jh", "td", "th", "kh", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None],
       "won_tricks": ([],
                      [("kd", "tc"), ("js", "qs"), ("ts", "as"),
                       ("jc", "ac")]),
       "current_trick": (None, "qc"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("td")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       ]
     },
     # Play the smallest card instead of discarding a card from an exhausted
     # suit.
     {
       "cards_in_hand": (["jh", "td", "th", "tc", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "as",
       "talon": [None],
       "won_tricks": ([],
                      [("jc", "qc"), ("kc", "ts"), ("ac", "js"),
                       ("jd", "kh")]),
       "marriage_suits": ([], [Suit.HEARTS]),
       "current_trick": (None, "ks"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("tc")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       ]
     },
     # There is no direct loss; discard a small card.
     {
       "cards_in_hand": (["jh", "td", "ts", "tc", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "as",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "kh"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       ]
     },
   ])
Exemple #7
0
 def test_trump_for_marriage(self):
   self._run_test_cases_with_option("trump_for_marriage", [False, True], [
     # Trump to take the lead and announce a non-trump marriage.
     {
       "cards_in_hand": (["ks", "qs", "th", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
         PlayCardAction(PlayerId.ONE, Card.from_string("th")),
       ]
     },
     # We have the trump marriage, but we cannot trump since we don't have a
     # third trump card to use.
     {
       "cards_in_hand": (["kh", "qh", "ts", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
         PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
       ]
     },
     # Use trump Ace to take the lead and announce the trump marriage.
     {
       "cards_in_hand": (["kh", "qh", "ts", "ac", "ah"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "th",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
         PlayCardAction(PlayerId.ONE, Card.from_string("ah")),
       ]
     },
   ])
Exemple #8
0
 def test_priority_discard(self):
   self._run_test_cases_with_option("priority_discard", [False, True], [
     # Discard a card from an exhausted suit.
     {
       "cards_in_hand": (["jd", "qd", "ac", "ks", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("qs", "js")], [("ts", "as")]),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("ks")),
       ]
     },
     # Discard a jack with ten protection.
     {
       "cards_in_hand": (["jd", "jc", "td", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jc")),
       ]
     },
     # Discard a jack with no ten protection.
     {
       "cards_in_hand": (["ks", "jd", "td", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("qs", "js")], [("ts", "th")]),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jd")),
       ]
     },
     # Discard a Queen/King without marriage chances.
     {
       "cards_in_hand": (["ks", "qd", "td", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("qs", "js")], [("ts", "th")]),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("ks")),
       ]
     },
     # Discard a Queen/King with marriage chances.
     {
       "cards_in_hand": (["ks", "qs", "kd", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
         PlayCardAction(PlayerId.ONE, Card.from_string("kd")),
       ]
     },
     # Discard a Queen/King for a marriage.
     {
       "cards_in_hand": (["ks", "qs", "ad", "ac", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
       ]
     },
     # Discard a non-trump card.
     {
       "cards_in_hand": (["jh", "qh", "th", "ac", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "ks"),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
         PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
       ]
     },
   ])
Exemple #9
0
 def test_generic_not_on_lead_follow_suit(self):
   self._run_test_cases([
     # Win with the Queen, keep the Ace for the not-yet-played Ten.
     {
       "cards_in_hand": (["qd", "ad", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qd"))
     },
     # If the Ten and King are already played, win with the Ace.
     {
       "cards_in_hand": (["qd", "ad", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([], [("kd", "td")]),
       "current_trick": (None, "jd"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ad"))
     },
     # Win with the Ten, even if the King is not yet played.
     {
       "cards_in_hand": (["qd", "td", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("td"))
     },
     # Give up the Ten if it's the only same-suit card we have and we must
     # follow suit.
     {
       "cards_in_hand": (["qh", "td", "jh", "js", "qs"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "ad"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("td"))
     },
     # Avoid breaking the marriage to win a Jack.
     {
       "cards_in_hand": (["qd", "kd", "ad", "js", "qs"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ad"))
     },
     # Discard the smallest card.
     {
       "cards_in_hand": (["qd", "jh", "qh", "th", "ah"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "js"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jh"))
     },
     # Use a trump-card even if that means breaking the marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jh"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("kc"))
     },
     # Use the trump Queen. Save the trump Ace for the trump Ten.
     {
       "cards_in_hand": (["qd", "jc", "qc", "js", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "tc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jh"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qc"))
     },
     # Use the trump Ace; don't save the trump Ace for the trump Ten, if that
     # means breaking the trump marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "ac", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jh"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     # Use the trump Jack; don't use the highest adjacent card if that means
     # breaking the trump marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "jc", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jh"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jc"))
     },
     # The talon is closed so we cannot exchange the trump card to get the
     # trump marriage. Use the trump Queen and save the Ace for the trump Ten.
     {
       "cards_in_hand": (["qd", "jc", "qc", "jd", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "kc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qc"))
     },
   ])
Exemple #10
0
 def test_non_trump_marriages_are_preferred_randomly(self):
   self.assertIn(get_best_marriage(
     [
       PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
       PlayCardAction(PlayerId.ONE, Card.from_string("js")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
       PlayCardAction(PlayerId.ONE, Card.from_string("qc")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("ks")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qs")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kc")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qc")),
     ], Suit.DIAMONDS),
     {
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("ks")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qs")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kc")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qc")),
     })
Exemple #11
0
def _trick_from_string_tuple(string_tuple: Tuple[str, str]) -> Trick:
  return PlayerPair(Card.from_string(string_tuple[0]),
                    Card.from_string(string_tuple[1]))
Exemple #12
0
 def test_generic_on_lead_follow_suit(self):
   self._run_test_cases([
     # Play a non-trump card with the maximum win probability.
     {
       "cards_in_hand": (["qd", "qs", "kh", "ah"], [None, None, None, "th"]),
       "trump": Suit.SPADES,
       "trump_card": "ks",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qc")], []),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ah")),
     },
     # Play a trump card with the maximum win probability.
     {
       "cards_in_hand": (["qd", "qs", "ks", "th"], [None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "jh",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qc")], []),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("th")),
     },
     # If we have a marriage pair among the cards with the max winning
     # probability, announce it with the king.
     {
       "cards_in_hand": (["qd", "qs", "ks", "ts"], [None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qc")], []),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": AnnounceMarriageAction(PlayerId.ONE,
                                                 Card.from_string("ks")),
     },
     # If we don't have any chance to win the next trick and we have a
     # marriage, announce it.
     {
       "cards_in_hand": (["qd", "qs", "ks", "ts"], ["as", "ad", None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qc")], []),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": AnnounceMarriageAction(PlayerId.ONE,
                                                 Card.from_string("ks")),
     },
     # Discard the smallest non-trump card.
     {
       "cards_in_hand": (["ts", "qs", "th", "jd"], ["as", "ah", "ad", None]),
       "trump": Suit.SPADES,
       "trump_card": "ks",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qd")], []),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jd")),
     },
     # Discard the smallest trump card.
     {
       "cards_in_hand": (["ts", "qs"], ["as", None]),
       "trump": Suit.SPADES,
       "trump_card": "ks",
       "talon": [None, None, None, None, None, None, None, None, None],
       "won_tricks": ([("qh", "qd")], [("tc", "ac"), ("jh", "jc")]),
       "player_that_closed_the_talon": PlayerId.ONE,
       "opponent_points_when_talon_was_closed": 0,
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
     },
   ])
Exemple #13
0
 def test_generic_on_lead_do_not_follow_suit(self):
   self._run_test_cases([
     # Exchanges trump when possible.
     {
       "cards_in_hand": (["qd", "kc", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": ExchangeTrumpCardAction(PlayerId.ONE)
     },
     # Play a high trump card if it will secure the win.
     {
       "cards_in_hand": (["tc", "ks", "ac", "jh", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([("qc", "ah")], []),
       "marriage_suits": ([Suit.CLUBS], []),
       "expected_action": {
         PlayCardAction(PlayerId.ONE, Card.from_string("ac")),
         PlayCardAction(PlayerId.ONE, Card.from_string("tc")),
       }
     },
     # Play a high non trump card if it will secure the lead.
     {
       "cards_in_hand": (["ks", "qd", "td", "jh", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None],
       "won_tricks": ([("qc", "ah"), ("kc", "jd")], [("tc", "ac")]),
       "marriage_suits": ([Suit.CLUBS], []),
       "expected_action": {
         PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
         PlayCardAction(PlayerId.ONE, Card.from_string("td")),
       }
     },
     # Play a high trump card if it will secure the lead. Take into account the
     # marriage in hand.
     {
       "cards_in_hand": (["kd", "qd", "ah", "jd", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "jh",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("qc", "as")], [("kc", "tc")]),
       "marriage_suits": ([Suit.CLUBS], []),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ah"))
     },
     # Announce the marriage with queen.
     {
       "cards_in_hand": (["qd", "kc", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.DIAMONDS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": AnnounceMarriageAction(PlayerId.ONE,
                                                 Card.from_string("qc"))
     },
     # Announce the marriage with king.
     {
       "cards_in_hand": (["qd", "kc", "jc", "ac", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.DIAMONDS,
       "trump_card": "ad",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([("tc", "js")], []),
       "expected_action": AnnounceMarriageAction(PlayerId.ONE,
                                                 Card.from_string("kc"))
     },
     # Discard the smallest non-trump card.
     {
       "cards_in_hand": (["qh", "qd", "ac", "qs", "tc"],
                         [None, None, None, None, None]),
       "trump": Suit.HEARTS,
       "trump_card": "ah",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": {
         PlayCardAction(PlayerId.ONE, Card.from_string("qd")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qs")),
       }
     },
   ])
Exemple #14
0
def card_list_from_string(string_list: List[str]) -> List[Card]:
    return [
        Card.from_string(token) if token is not None else None
        for token in string_list
    ]
Exemple #15
0
 def test_trump_control(self):
   self._run_test_cases_with_option("trump_control", [False, True], [
     # No trumps after one trick. Play a high card.
     {
       "cards_in_hand": (["jh", "jd", "th", "kc", "qd"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "as",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([("qc", "jc")], []),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("th")),
       ]
     },
     # There is no need to trump control; discard a small card.
     {
       "cards_in_hand": (["jh", "ts", "ks", "tc", "ad"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "as",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       ]
     },
     # The opponent has more trumps than us, but we cannot play a high card
     # since the opponent might trump it and win the game.
     {
       "cards_in_hand": (["qh", "td", "th", "tc", "ah"],
                         ["qs", None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None, None, None],
       "won_tricks": ([],
                      [("ad", "ks"), ("qc", "qd")]),
       "marriage_suits": ([], [Suit.SPADES]),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qh")),
       ]
     },
     # No trump control since there are no more trumps.
     {
       "cards_in_hand": (["qh", "td", "th", "ts", "as"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("ks", "ad"), ("qs", "qd")],
                      []),
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("qh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("qh")),
       ]
     },
     # No trump control since we have no high cards.
     {
       "cards_in_hand": (["qh", "jd", "jh", "ks", "jc"],
                         [None, None, None, None, None]),
       "trump": Suit.SPADES,
       "trump_card": "js",
       "talon": [None, None, None, None, None, None, None, None, None],
       "expected_action": [
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       ]
     },
   ])
Exemple #16
0
 def test_generic_not_on_lead_do_not_follow_suit(self):
   self._run_test_cases([
     # Win with the Queen, keep the Ace for the not-yet-played Ten.
     {
       "cards_in_hand": (["qd", "ad", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qd"))
     },
     # If the Ten and King are already played, win with the Ace.
     {
       "cards_in_hand": (["qd", "ad", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([], [("kd", "td")]),
       "current_trick": (None, "jd"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ad"))
     },
     # Win with the Ten, even if the King is not yet played.
     {
       "cards_in_hand": (["qd", "td", "jc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("td"))
     },
     # Don't give up the Ten even if it's the only same-suit card we have.
     {
       "cards_in_hand": (["qh", "td", "jh", "js", "qs"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "ad"),
       "expected_action": {
         PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
         PlayCardAction(PlayerId.ONE, Card.from_string("js")),
       }
     },
     # Break a marriage to win a Jack (options.save_marriage is False).
     {
       "cards_in_hand": (["qd", "kd", "ad", "js", "qs"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "jd"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("kd"))
     },
     # Opponent played a trump card that cannot be won; discard the smallest
     # card.
     {
       "cards_in_hand": (["qd", "kd", "ad", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "tc"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("js"))
     },
     # Win a Ten with the same suit Ace.
     {
       "cards_in_hand": (["qd", "ks", "ah", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ah"))
     },
     # Win a Ten with a trump-card if we don't have the same-suit Ace, even if
     # that means breaking the marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "js", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("kc"))
     },
     # Win a Ten with the trump Queen. Save the trump Ace for the trump Ten.
     {
       "cards_in_hand": (["qd", "jc", "qc", "js", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "tc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("qc"))
     },
     # Win a Ten with the trump Ace if we don't have the same-suit Ace; don't
     # save the trump Ace for the trump Ten, if that means breaking the trump
     # marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "ac", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     # Win a Ten with the trump Jack if we don't have the same-suit Ace; don't
     # use the highest adjacent card if that means breaking the trump marriage.
     {
       "cards_in_hand": (["qd", "ks", "kc", "jc", "qc"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "ac",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jc"))
     },
     # Win a Ten with the trump Ace. Don't save the trump Ace for the trump Ten
     # if we can exchange the trump card to get the trump marriage.
     {
       "cards_in_hand": (["qd", "jc", "qc", "jd", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "kc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     {
       "cards_in_hand": (["qd", "jc", "kc", "jd", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "qc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "th"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     # If this is the last chance to win a trick and be on-lead to exchange the
     # trump card and announce the trump marriage, use a trump regardless of
     # what the opponent played.
     {
       "cards_in_hand": (["qd", "jc", "qc", "ad", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "kc",
       "talon": [None, None, None],
       "won_tricks": ([("kd", "jd")], [("jh", "qh"), ("kh", "ah")]),
       "current_trick": (None, "js"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     # If it's not the last chance to win a trick and be on-lead to exchange
     # the trump card and announce the trump marriage, do not use a trump yet.
     {
       "cards_in_hand": (["qd", "jc", "qc", "jd", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "kc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "js"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jd"))
     },
     # Trump if that gets us the win right now.
     {
       "cards_in_hand": (["qd", "jh", "qh", "jd", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None],
       "won_tricks": ([("qc", "ad")], [("kc", "tc")]),
       "marriage_suits": ([Suit.CLUBS], []),
       "current_trick": (None, "js"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("ac"))
     },
     # Trump if that gets us the win after one more trick.
     {
       "cards_in_hand": (["qd", "jh", "qh", "tc", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None],
       "won_tricks": ([("qc", "jd")], []),
       "marriage_suits": ([Suit.CLUBS], []),
       "current_trick": (None, "js"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("tc"))
     },
     # Discard the smallest card.
     {
       "cards_in_hand": (["qd", "jh", "qh", "tc", "ac"],
                         [None, None, None, None, None]),
       "trump": Suit.CLUBS,
       "trump_card": "jc",
       "talon": [None, None, None, None, None, None, None, None, None],
       "current_trick": (None, "js"),
       "expected_action": PlayCardAction(PlayerId.ONE, Card.from_string("jh"))
     },
   ])
Exemple #17
0
 def test_trump_marriage_is_preferred(self):
   self.assertIn(get_best_marriage(
     [
       PlayCardAction(PlayerId.ONE, Card.from_string("jh")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ad")),
       PlayCardAction(PlayerId.ONE, Card.from_string("js")),
       PlayCardAction(PlayerId.ONE, Card.from_string("ts")),
       PlayCardAction(PlayerId.ONE, Card.from_string("qc")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qh")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("ks")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qs")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("kc")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qc")),
     ], Suit.SPADES),
     {
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("ks")),
       AnnounceMarriageAction(PlayerId.ONE, Card.from_string("qs")),
     })