import random

# ==========================
# カード設定
# ==========================

CARD_LIST = (
    ["A"] * 4 +
    ["2"] * 4 +
    ["3"] * 4 +
    ["4"] * 4 +
    ["5"] * 4 +
    ["6"] * 4 +
    ["7"] * 4 +
    ["8"] * 4 +
    ["9"] * 4 +
    ["10"] * 4 +
    ["J"] * 4 +
    ["Q"] * 4 +
    ["K"] * 4 +
    ["Joker"]
)


def possible_values(card):

    if card == "A":
        return [1, 11]

    elif card == "2":
        return [2]

    elif card == "3":
        return [3]

    elif card == "4":
        return [4]

    elif card == "5":
        return ["skip"]

    elif card == "6":
        return [6]

    elif card == "7":
        return [7]

    elif card == "8":
        return ["pass"]

    elif card == "9":
        return ["reverse"]

    elif card == "10":
        return [10, -10]

    elif card == "J":
        return [10]

    elif card == "Q":
        return [20]

    elif card == "K":
        return [30]

    elif card == "Joker":
        return [50]


# ==========================
# プレイヤー
# ==========================

class Player:

    def __init__(self, name):

        self.name = name
        self.hand = []
        self.score = 0

    def draw(self, deck):

        if len(deck) == 0:
            deck.extend(CARD_LIST)
            random.shuffle(deck)

        self.hand.append(deck.pop())


# ==========================
# ゲーム
# ==========================

class Game:

    def __init__(self, players=3,first_player=0,card_count=None):

        self.deck = CARD_LIST.copy()
        random.shuffle(self.deck)

        self.players = [
            Player(f"P{i+1}")
            for i in range(players)
        ]

        self.total = 0
        self.turn = first_player
        self.direction = 1

        self.card_count = card_count

        # 初期手札2枚
        for p in self.players:
            p.draw(self.deck)
            p.draw(self.deck)

    def draw_card(self, player):

        player.draw(self.deck)


# ==========================
# AI
# ==========================

    def choose_card(self, player):

        best_card = None
        best_value = None
        best_total = -1

        over_card = None
        over_value = None
        smallest_over = float("inf")

        for card in player.hand:

            for value in possible_values(card):

                # 特殊カード
                if isinstance(value, str):

                    if value == "skip":
                        if self.total >= 80:
                            return card, value
                        continue

                    if value == "pass":
                        if self.total >= 80:
                            return card, value
                        continue

                    if value == "reverse":
                        if self.total >= 80:
                            return card, value
                        continue

                new_total = self.total + value

                if new_total <= 101:

                    if new_total > best_total:
                        best_total = new_total
                        best_card = card
                        best_value = value

                else:

                    over = new_total - 101

                    if over < smallest_over:
                        smallest_over = over
                        over_card = card
                        over_value = value

        if best_card is not None:
            return best_card, best_value

        if over_card is not None:
            return over_card, over_value

        # 特殊カードしかない場合
        card = player.hand[0]
        return card, possible_values(card)[0]

    # ==========================
    # 1ゲーム実行
    # ==========================

    def play(self):

        while True:

            player = self.players[self.turn]

            card, effect = self.choose_card(player)

            player.hand.remove(card)

            self.card_count[card] += 1
            
            if effect == "skip":

                self.draw_card(player)
                self.card_count[card] += 1
                
                self.turn = (
                    self.turn + 2 * self.direction
                ) % len(self.players)

                continue

            elif effect == "pass":

                self.draw_card(player)

            elif effect == "reverse":

                self.direction *= -1
                self.draw_card(player)

            else:

                self.total += effect
                self.draw_card(player)

            # 終了判定
            if self.total >= 101:

                if self.total == 101:
                    return player

                over = self.total - 101

                player.score -= over * (len(self.players) - 1)

                for p in self.players:
                    if p != player:
                        p.score += over

                return player

            self.turn = (
                self.turn + self.direction
            ) % len(self.players)

# ==========================
# シミュレーション
# ==========================

def simulate(n=100000, players=3):

    card_count = {}

    for card in CARD_LIST:
        card_count[card] = 0
    
    total_scores = [0] * players

    burst_games = 0
    exact_games = 0

    first_player = 0 

    for _ in range(n):

        game = Game(players,first_player,card_count)

        starter = game.play()

        if game.total == 101:
            exact_games += 1
        else:
            burst_games += 1

        first_player = game.players.index(starter)
        
        for i, p in enumerate(game.players):
            total_scores[i] += p.score

    print()
    print("========== 結果 ==========")
    print("試行回数 :", n)
    print()

    for i in range(players):
        print(
            f"P{i+1} 平均得点 : "
            f"{total_scores[i]/n:.4f}"
        )

    print()
    print("101ちょうど :", exact_games)
    print("バースト :", burst_games)
    print()
    print("カード使用回数")

    for card in sorted(card_count.keys()):
        print(f"{card:6} : {card_count[card]}")

simulate(10000)

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: