6
\$\begingroup\$

In this challenge, you will be making a 3 bot to play the card game judgement!

Sandbox

Rules

Judgement is a hand based game similar to games like rummy. In each round, 7 cards are dealt to each player, a trump suit is chosen (trump suits are chosen sequentially from the list Spades/Hearts/Diamonds/Clubs/No Trump), and based on these cards, the trump suit, and the play order, each player must make a guess as to how many hands they will win.

The first player to play in a particular hand can play any card they want. From then on, any subsequent player must play a card of the same suit as the first player if they have it, otherwise, they can play any card.

Once every player has played a card, the winner of the hand is determined as follows:

  • If a trump card has been played, the highest trump card wins
  • Otherwise, the highest card in the suit played by the first player wins

(As in most card games, the ordering is 2,3,4,5,6,7,8,9,10,J,Q,K,A)

The winner of a given hand starts the next hand. Once everyone's cards are depleted, each player counts the number of hands they have won. If it is equal to their guess, they earn 10 + the number of guessed hands. Otherwise, they earn nothing.

The winner of the game is the player with the highest scores after several rounds.

Challenge

I've built the game controller here. Everything in this section is present in the link, but I'll include it here for completeness.

A submission must include 5 parts:


"name"

A name for the bot.


def make_bet(self, turn_order, trump):
    ...
    return hands_to_make

This function takes in turn_order, which is a list of the names of all bots in order of when they will play, and trump, which is a string representing the trump suit for the round. It must return hands_to_make, which is the number of hands the bot expects to win this round. self.handwill be automatically updated to contain your current hand.


play_card(self, current_board):
    ...
    return card_played

This function takes in the list of cards played so far this hand in the form ("bot_name", Card), and returns card_played, which is the card from your hand to play.


update_round(self, current_scores, rounds_left):
    ...
    return None

This function gets called right before every round (including at the very beginning for initializing you bot). It takes current_score which is a dictionary of bot_name: current_score, and rounds_left, which is the number of rounds left to be played.


update_play(self, final_board, winner):
    ...
    return None

This function gets called right after each hand. final_board is the list of cards played that hand in the form ("bot_name", Card), and winner is a string indicating which bot won the hand.


The classes have the following specs

Card:

  • self.suit accesses the suit (S,H,D, or C)
  • self.rank accesses the rank (int from 2 -> 14)
  • self.get_rank() accesses the rank in str form (2-10,J,Q,K,A)

Bot:

  • self.hand accesses the hand (List[Card])
  • self.name accesses the name of the bot. Alternatively, str(self) works as well.
  • self.all_bets accesses a dictionary of bets placed by all bots.
  • You can store other information you want to store by create self. class variables.

As a basic example, consider the following bot:

Basic Bot

def basic_make_bet(self, turn_order, trump):
    return len(self.hand)

def basic_play_card(self, current_board):
    if current_board:
        for card in self.hand:
            if card.suit == current_board[0].suit:
                return card
    return self.hand[0]

def basic_update_round(self, current_scores, rounds_left):
    pass

def basic_update_play(self, final_board, winner):
    pass

basic_bot = ("basic", basic_make_bet, basic_play_card, basic_update_round, basic_update_play)

The Colab link above contains an easy to use template for submissions, so I recommend using that! I will also try to update the Colab link with new bots as soon as they are posted.

Requirements

  • You can only use libraries available in Google Colab. These are the libraries present in the Anaconda distribution of Python 3.
  • self.hand, the variable to access to see one's hand, must be treated as read only. Modifying the variable will mess up the game, so please avoid this.
  • Bots must run in a reasonable amount of time. I'm not going to provide any strict bounds but I'll remove any serious offenders.
  • The competition will be run June 6th, and the winner will receive a bounty + a check mark.
  • To judge the bots, I'll pick random groupings of up to 7 bots and play the game thousands of times, and evaluate the average score of the bots per game.

Current Averages

Each bot has played a total of 100 rounds. This table should be updated semi-regularly. (PlanBot is currently too slow to run 10000 rounds)

Bot Average
PlanBot 6.71
Conservative 6.30
BasicCardStrat 4.77
Half 4.28
Random 4.15
sans. 3.19
Basic 0.00
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Can we get access to other bots' bets? That's very important for many intelligent strategies. \$\endgroup\$ Commented May 13, 2021 at 15:13
  • 1
    \$\begingroup\$ @Spitemaster Fixed, check revised question/code. \$\endgroup\$ Commented May 13, 2021 at 15:14
  • \$\begingroup\$ @AaronMiller Thank you for the edit! Looks really nice. \$\endgroup\$ Commented May 13, 2021 at 17:56
  • \$\begingroup\$ I know a variant of this under the name "Estimation". In the variant, a different number of cards are dealt on each round. You get one point per trick plus a bonus of 10 if you correctly estimated the number of tricks that you would win. \$\endgroup\$
    – Neil
    Commented May 13, 2021 at 18:47
  • \$\begingroup\$ @Neil I was actually planning on doing a different number of cards per round, but in Sandbox, this variant was complicated enough, so I left it. \$\endgroup\$ Commented May 13, 2021 at 18:48

6 Answers 6

2
+100
\$\begingroup\$

PlanBot

Plans one step ahead and then simulates a random game. Tries to sabotage its opponents once it goes bust.

    import random
    
    def valid_plays(hand, suit):
        if suit is None:
            return list(range(len(hand)))
        follows_suit = [i for i, card in enumerate(hand) if card.suit == suit]
        if follows_suit:
            return follows_suit
        return list(range(len(hand)))
    
    def pick_random(hand, suit):
        if suit is None:
            return random.randrange(len(hand))
        follows_suit = [i for i, card in enumerate(hand) if card.suit == suit]
        if follows_suit:
            return random.choice(follows_suit)
        return random.randrange(len(hand))
    
    def simulate_random_game(hands, trump, starting_player, current_trick):
        tricks_won = [0] * len(hands)
        current_trick = list(current_trick)
        current_suit = current_trick[0].suit if current_trick else None
        while hands[starting_player]:
            i = 0
            while len(current_trick) < len(hands):
                player = (starting_player + i) % len(hands)
                hand = hands[player]
                card_index = pick_random(hand, current_suit)
                card = hand[card_index]
                current_suit = current_suit or card.suit
                hand[card_index] = hand[-1]
                hand.pop()
                current_trick.append(card)
                i += 1
            winner_offset = max(enumerate(current_trick), key=lambda t: (t[1].suit == trump, t[1].suit == current_trick[0].suit, t[1].rank))[0]
            current_suit = None
            starting_player = (starting_player + winner_offset) % len(hands)
            tricks_won[starting_player] += 1
            current_trick.clear()
        return tricks_won
    
    def dirichlet_score(counts):
        sampled_counts = [random.gammavariate(n, 1) for n in counts]
        return max(sum(i * n for i, n in enumerate(counts_prime)) / sum(counts_prime) for counts_prime in (counts, sampled_counts))
    
    INITIAL_DECK = Deck().cards
    
    def as_tuple(card):
        return (card.suit, card.rank)
    
    def deal(out, initial_dead_cards, hand_sizes):
        num_attempts = 4
        order = sorted(range(len(hand_sizes)), key=lambda i: len(out[i]), reverse=True)
        for attempt in range(num_attempts):
            result = [[] for _ in hand_sizes]
            failed = False
            deck = INITIAL_DECK
            dead_cards = set(initial_dead_cards)
            for i in order:
                o = out[i]
                n = hand_sizes[i]
                if not n:
                    result[i] = []
                    continue
                deck = [card for card in deck if as_tuple(card) not in dead_cards]
                if o and attempt != (num_attempts - 1):
                    possible_cards = [card for card in deck if card.suit not in o]
                else:
                    possible_cards = deck
                if len(possible_cards) < n:
                    failed = True
                    break
                hand = random.sample(possible_cards, n)
                result[i] = hand
                dead_cards |= {as_tuple(card) for card in hand}
            if failed:
                continue
            return result
    
    def plan_make_bet(self, turn_order, trump):
        scores = [0 for _ in range(8)]
        self.tricks_won = {bot.name: 0 for bot in turn_order}
        self.turn_order = [bot.name for bot in turn_order]
        self.my_index = next(i for i, bot in enumerate(turn_order) if bot == self)
        self.hand_sizes = {bot.name: 7 for bot in turn_order}
        self.trump = trump
        hand_sizes = [7 * (i != self.my_index) for i, _ in enumerate(turn_order)]
        self.dead_cards = {as_tuple(card) for card in self.hand}
        self.out = {bot.name: set() for bot in turn_order}
        for _ in range(1500):
            hands = deal([[] for _ in turn_order], self.dead_cards, hand_sizes)
            hands[self.my_index] = list(self.hand)
            tricks_won = simulate_random_game(hands, trump, 0, [])[self.my_index]
            scores[tricks_won] += 1
        bet = max(enumerate(scores), key=lambda t: (10 + t[0]) * t[1])[0]
        self.bet = bet
        return self.bet
    
    def plan_play_card(self, current_trick):
        hand_sizes = dict(self.hand_sizes)
        for bot, card in current_trick:
            self.dead_cards.add(as_tuple(card))
            hand_sizes[bot] -= 1
        hand_sizes[self.name] = 0
        current_suit = current_trick[0][1].suit if current_trick else None
        for bot, card in current_trick[1:]:
            if card.suit != current_suit:
                self.out[bot].add(current_suit)
        out = [self.out[bot] for bot in self.turn_order]
        plays = list(valid_plays(self.hand, current_suit))
        bust = ((self.tricks_won[self.name] + len(self.hand)) < self.bet) or (self.tricks_won[self.name] > self.bet)
        if len(plays) == 1:
            return self.hand[plays[0]]
        if bust:
            a = 1. / (len(self.turn_order) - 1)
            outcomes = [[a] * (len(self.turn_order) - 1) for _ in plays]
        else:
            outcomes = [[1, 1] for _ in plays]
        hand_sizes = [hand_sizes[bot] for bot in self.turn_order]
        current_trick = [card for _, card in current_trick]
        all_bets = {k.name: v for k, v in self.all_bets.items()}
        for _ in range(1500):
            current_trick_copy = list(current_trick)
            hands = deal(out, self.dead_cards, hand_sizes)
            my_hand = hands[self.my_index] = list(self.hand)
            scores = [dirichlet_score(counts) for counts in outcomes]
            chosen_play = scores.index(max(scores))
            current_trick_copy.append(my_hand[chosen_play])
            my_hand[chosen_play] = my_hand[-1]
            my_hand.pop()
            tricks_won = simulate_random_game(hands, self.trump, (self.my_index + 1) % len(hands), current_trick_copy)
            if bust:
                outcome = -(1 + sum(self.tricks_won[bot] + trick_count == all_bets[bot] for bot, trick_count in zip(self.turn_order, tricks_won)))
            else:
                outcome = (self.tricks_won[self.name] + tricks_won[self.my_index]) == self.bet
            outcomes[chosen_play][outcome] += 1
        best_play = max(enumerate(plays), key=lambda t: sum(outcomes[t[0]]))[1]
        return self.hand[best_play]
    
    def plan_update_round(self, current_scores, rounds_left):
        pass
    
    def plan_update_play(self, final_trick, winner):
        for bot in self.hand_sizes:
            self.hand_sizes[bot] -= 1
        lead_suit = final_trick[0][1].suit
        for bot, card in final_trick[1:]:
            self.dead_cards.add(as_tuple(card))
            if card.suit != lead_suit:
                self.out[bot].add(lead_suit)
        winner = max(final_trick, key=lambda t: (t[1].suit == self.trump, t[1].suit == final_trick[0][1].suit, t[1].rank))[0]
        self.tricks_won[winner] += 1
    
    plan_bot = ("PlanBot", plan_make_bet, plan_play_card, plan_update_round, plan_update_play)
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Added! However, this bot is currently taking around 2 seconds a round, which is on the border of being too slow. If you could try to make some small optimizations, that would be much appreciated. \$\endgroup\$ Commented May 16, 2021 at 17:24
  • \$\begingroup\$ @Don_Thousand OK I'll try later. Are you using PyPy? \$\endgroup\$ Commented May 17, 2021 at 8:38
  • \$\begingroup\$ sadly, colab doesn't have it. \$\endgroup\$ Commented May 17, 2021 at 13:52
  • \$\begingroup\$ @user1502040 you could maybe try rewriting some bits in numpy to speed it up \$\endgroup\$ Commented May 17, 2021 at 17:27
2
\$\begingroup\$

Conservative Bot

This bot always bets 0, and tries its best to get rid of the biggest cards it has.


def conservative_make_bet(self, turn_order, trump):
    self.trump = trump
    return 0
def conservative_play_card(self,current_board):
    suit_count = {s:len([c for c in self.hand if c.suit == s]) for s in ["S","H","D","C"]}
    if current_board == []:
        if all(card.suit == self.trump for card in self.hand):
            return min(self.hand, key=lambda c: c.rank)
        return min([c for c in self.hand if c.suit != self.trump], key = lambda c: c.rank)
    trump_on_board = any(c[1].suit == self.trump for c in current_board)
    valid_cards = [c for c in self.hand if c.suit == current_board[0][1].suit]
    if valid_cards:
        if trump_on_board:
            return max(valid_cards, key = lambda c: c.rank)
        winning_card = max([c for c in current_board if c[1].suit == current_board[0][1].suit], key = lambda c: c[1].rank)
        losing_cards = [c for c in valid_cards if c.rank < winning_card[1].rank]
        if losing_cards:
            return max(losing_cards, key = lambda c: c.rank)
        return min(valid_cards, key = lambda c: c.rank)
    if trump_on_board:
        winning_card = max([c for c in current_board if c[1].suit == self.trump], key = lambda c: c[1].rank)
        small_trumps = [c for c in self.hand if c.rank < winning_card[1].rank and c.suit == self.trump]
        if any(card.suit != self.trump for card in self.hand) and not small_trumps:
            return max([c for c in self.hand if c.suit != self.trump], key = lambda c: c.rank * 8 + suit_count[c.suit])
        if small_trumps:
            return max(small_trumps, key = lambda c: c.rank)
        return min(self.hand, key = lambda c: c.rank)
    if all(card.suit == self.trump for card in self.hand):
        return min(self.hand, key = lambda c: c.rank)
    return max([c for c in self.hand if c.suit != self.trump], key = lambda c: c.rank * 8 + suit_count[c.suit])
def conservative_update_round(self, current_scores, rounds_left):
    pass
def conservative_update_play(self, final_board, winner):
    pass

conservative_bot = ("Conservative", conservative_make_bet,conservative_play_card,conservative_update_round,conservative_update_play)

\$\endgroup\$
2
\$\begingroup\$

Half

def half_make_bet(self, _, trump):
    self.trump = trump
    self.wins = 0
    self.bet = len([i for i in self.hand if i.rank > 8]) // 2
    return self.bet

def half_play_card(self, current_board):
    if not current_board:
        return min(self.hand,key=lambda card: card.rank)
    valid = [i for i in self.hand if i.suit == current_board[0][1].suit]
    if valid:
        return max(valid,key = lambda i: i.rank)
    if self.wins > self.bet:
        return self.hand[0]
    if self.bet - self.wins >= len([i for i in self.hand if i.rank > 8 or i.suit == self.trump]):
        return max(self.hand, key = lambda i: i.rank + 1000 * (i.suit == self.trump))
    return min(self.hand, key = lambda i: i.rank + 1000 * (i.suit == self.trump))

def half_update_round(self, a, b):
    pass

def half_update_play(self, a, w):
    self.wins += w == self.name

half_bot = ("Half", half_make_bet, half_play_card, half_update_round, half_update_play)
\$\endgroup\$
3
  • 1
    \$\begingroup\$ @DonThousand "other than the template and Bot classes." That's exactly the problem. People shouldn't have to go digging around your source code to understand the problem. Write your problem spec like docs - what type is each function? What arguments does each function take? etc. \$\endgroup\$ Commented May 13, 2021 at 12:49
  • 1
    \$\begingroup\$ @DonThousand If only Python had interfaces... That's why JS is better for challenges like this - object literals are the way to go. Anyway, you should probably write the problem spec again including docs for the Bot and Card classes. \$\endgroup\$ Commented May 13, 2021 at 12:59
  • 2
    \$\begingroup\$ You don't update self.wins in your update_play function, so Half always tries to win. \$\endgroup\$ Commented May 13, 2021 at 14:50
1
\$\begingroup\$

sans.

sans has arrived to pass Judgement. However, being sans, he aims low and plays lazily.

def sans_make_bet(self,turn_order,trump):
    return 1

def sans_play_card(self,current_board):
    if current_board:
        for card in self.hand:
            if card.suit == current_board[0][1].suit:
                return card
    return self.hand[-1]

def sans_update_round(self, current_scores, rounds_left):
    pass
def sans_update_play(self, final_board, winner):
    pass

sans = ("sans.", sans_make_bet, sans_play_card, sans_update_round, sans_update_play)
\$\endgroup\$
5
  • \$\begingroup\$ Added to the controller! \$\endgroup\$ Commented May 13, 2021 at 20:34
  • \$\begingroup\$ @DonThousand I think you forgot to add it to bot_info_list in the Main Program section of the controller. \$\endgroup\$ Commented May 14, 2021 at 0:11
  • \$\begingroup\$ I thought I did? Let me fix that \$\endgroup\$ Commented May 14, 2021 at 0:59
  • \$\begingroup\$ You should call this Crab \$\endgroup\$
    – emanresu A
    Commented May 14, 2021 at 4:28
  • \$\begingroup\$ @Ausername Initially, I was going to call it crab, but I decided that crab is more about making things worse for everybody by picking low numbers, but this doesn't really affect anybody else. Plus, sans? Judgement? It's just perfect. \$\endgroup\$ Commented May 14, 2021 at 12:14
1
\$\begingroup\$

BasicCardStrat

def bcs_make_bet(self, turn_order, trump):
    self.wins = 0
    self.trump = trump
    self.played = []
    winners_by_suit = {"C": 14, "D": 14, "H": 14, "S": 14}
    for card in self.hand:
        if winners_by_suit[card.suit] == card.rank:
            winners_by_suit[card.suit] -= 1
    winner_count = 56 - winners_by_suit["C"] - winners_by_suit["D"] - winners_by_suit["H"] - winners_by_suit["S"]
    threshold = 3 + len(turn_order)
    face_count = sum(1 for x in self.hand if x.rank > threshold) - winner_count
    trump_count = sum(1 for x in self.hand if x.rank <= threshold and x.suit == self.trump)
    self.bet = int(winner_count * 0.75 + face_count * 0.33 + trump_count * 0.5)
    return self.bet

def bcs_play_card(self, current_board):
    # Check if we're winning more than projected
    winners_by_suit = {"C": 14, "D": 14, "H": 14, "S": 14}
    for card in self.hand:
        if winners_by_suit[card.suit] == card.rank:
            winners_by_suit[card.suit] -= 1
    winner_count = 52 - winners_by_suit["C"] - winners_by_suit["D"] - winners_by_suit["H"] - winners_by_suit["S"]
    face_count = sum(1 for x in self.hand if x.rank > 10) - winner_count
    trump_count = sum(1 for x in self.hand if x.rank <= 10 and x.suit == self.trump)
    ahead = int(winner_count * 0.75 + face_count * 0.33 + trump_count * 0.5) + self.wins - self.bet
    
    # Determine which cards are guaranteed winners (barring trump)
    winners_by_suit = {"C": 14, "D": 14, "H": 14, "S": 14}
    played_by_suit = {"C": 0, "D": 0, "H": 0, "S": 0}
    all_played = sorted(self.played, key=lambda x: -x.rank)
    for card in all_played:
        played_by_suit[card.suit] += 1
        if winners_by_suit[card.suit] == card.rank:
            winners_by_suit[card.suit] -= 1
    if not current_board:
        winners = [x for x in self.hand if winners_by_suit[x.suit] == x.rank]
        if len(winners):
            return next((x for x in winners if x.suit == self.trump), winners[0])
        if ahead > 0:
            return max(self.hand, key=lambda x: x.rank - (15 if x.suit == self.trump else 0))
        # Get rid of others' trump
        trump_cards = [x for x in self.hand if x.suit == self.trump]
        if trump_cards:
            return min(trump_cards, key=lambda x: x.rank)
        return min(self.hand, key=lambda x: x.rank + played_by_suit[x.suit])
    lead_suit = current_board[0][1].suit
    valid = [x for x in self.hand if x.suit == lead_suit]
    is_trumped = lead_suit != self.trump and any(x[1].suit == self.trump for x in current_board)
    current_winner = max([x.rank for (_,x) in current_board if (x.suit == lead_suit and not is_trumped) or (x.suit == self.trump)])

    # If I have more winners than tricks I want to take, try to slough one
    if ahead > 0:
        if valid:
            if is_trumped:
                current_winner = 15
            return max(valid, key=lambda x: -x.rank if x.rank > current_winner else x.rank)
        if is_trumped:
            trump_cards = [x for x in self.hand if x.suit == self.trump and x.rank < current_winner]
            if trump_cards:
                return max(trump_cards, key=lambda x: x.rank)
        return max(self.hand, key=lambda x: x.rank - (15 if x.suit == self.trump else 0))

    if not is_trumped:
        if valid:
            # If I want to win and I have a winner for this suit, play it.
            winner = next((x for x in valid if winners_by_suit[x.suit] == x.rank), None)
            if winner:
                return winner
            # Play my lowest winning card
            winners = [x for x in valid if (x.rank > current_winner)]   
            if len(winners):
                return min(winners, key=lambda x: x.rank)
            return min(valid, key=lambda x: x.rank)
        winners = [x for x in self.hand if x.suit == self.trump]
        if len(winners):
            return min(winners, key=lambda x: x.rank)
    if is_trumped:
        # Have to follow suit if possible
        if len(valid):
            return min(valid, key=lambda x: x.rank)
        winners = [x for x in self.hand if x.rank > current_winner and x.suit == self.trump]
        if len(winners):
            return min(winners, key=lambda x: x.rank)

    # Finally, play my worst card
    if valid:
        return min(valid, key=lambda x: x.rank)
    return min(self.hand, key=lambda x: x.rank + (15 if x.suit == self.trump else 0))

def bcs_update_round(self, a, b):
    pass

def bcs_update_play(self, final_board, winner):
    self.played += [x[1] for x in final_board]
    if self.name == winner:
        self.wins += 1

bcs_bot = ("BasicCardStrat", bcs_make_bet, bcs_play_card, bcs_update_round, bcs_update_play)

Some very simple card game strategy. Play winners, try to win with trump, slough when needed. Feel free to adapt this into other bots.

\$\endgroup\$
9
  • \$\begingroup\$ if winner := next((x for x in self.hand if x.rank > current_winner and x.suit == self.trump), None): return min(winner, key=lambda x: x.rank) \$\endgroup\$ Commented May 13, 2021 at 18:40
  • \$\begingroup\$ What is the expected functionality here? winner is a Card, which is not iterable. \$\endgroup\$ Commented May 13, 2021 at 18:41
  • \$\begingroup\$ @DonThousand Oops, winner should be a list instead of getting the next one, so that it's sortable. I think I fixed all of them. \$\endgroup\$ Commented May 13, 2021 at 18:56
  • \$\begingroup\$ I've been working on fixing your code for a bit now, and it's still not working. How about you save a version of the controller locally, and fix up the code until it works? \$\endgroup\$ Commented May 13, 2021 at 19:02
  • \$\begingroup\$ @DonThousand Will do; it'll be a bit. \$\endgroup\$ Commented May 13, 2021 at 19:05
0
\$\begingroup\$

Random Bot

Simulates a random game and guesses the number of hands it wins in that random game. It always chooses a random card.

from random import sample


def make_random_bot():

  def pick_random(hand, suit):
    if suit is None:
      return sample(hand, 1)[0]
    shuffled = sample(hand, len(hand))
    for card in shuffled:
      if card.suit == suit:
        return card
    return shuffled[0]

  def simulate_random_game(hands, trump):
    hands = [[c for c in hand] for hand in hands]
    hands_won = [0] * len(hands)

    last_won = 0
    for h in range(7):
      last_suit = None
      cards = []
      for i in range(len(hands)):
        player = (i + last_won) % len(hands)
        card = pick_random(hands[player], last_suit)
        last_suit = card.suit
        hands[player].remove(card)
        cards.append(card)
      winner_i = max(range(i), key=lambda i: (cards[i].suit == trump, cards[i].suit == cards[0].suit, cards[i].rank))
      last_won = (winner_i + last_won) % len(hands)
      hands_won[last_won] += 1
    return hands_won

  def make_bet(self,turn_order,trump):
    cards = list(set(Deck().cards) - set(self.hand))

    other_cards = sample(cards, k=7*(len(turn_order) - 1))
    hands = []
    i = 0
    for bot in turn_order:
      if bot == self:
        hands.append(self.hand)
      else:
        hands.append(other_cards[i * 7: (i+1)*7])
        i += 1
    result = simulate_random_game(hands, trump)

    return result[turn_order.index(self)]

  def play_card(self,current_board):

    hand = sample(self.hand, k=len(self.hand))
    
    if current_board:
        for card in hand:
            if card.suit == current_board[0][1].suit:
                return card

    return hand[0]

  def nop(self, a, b):
    pass

  return ('Random', make_bet, play_card, nop, nop)

random_bot = make_random_bot()
```
\$\endgroup\$
3
  • \$\begingroup\$ Added to controller! \$\endgroup\$ Commented May 15, 2021 at 3:54
  • \$\begingroup\$ @TheNumberOne I think you have a bug in simulate_random_game where you reset the current suit after every card played instead of just at the start of the trick. \$\endgroup\$ Commented May 16, 2021 at 10:48
  • \$\begingroup\$ Thank you @user1502040 ^-^ \$\endgroup\$ Commented May 17, 2021 at 16:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.