Exemplo n.º 1
0
def test_hand():
    mj_set = MjSet()
    mj_set.shuffle()
    # ai = PlayerAiPro("bot02")
    ai = PlayerAiAdv("bot02")
    for _ in range(13):
        ai.draw(mj_set)
    ai.sort_concealed()
    print("concealed: " + Rule.convert_tiles_to_str(ai.concealed))
    mj_set.shuffle()
    for _ in range(100):
        tile = ai.draw(mj_set)
        print(f"draw: {tile}")
        if Rule.is_mahjong(ai.concealed):
            print("Mahjong!!!")
            break
        tile = ai.decide_discard()
        print(f"discard: {tile}")
        ai.discard(tile)
        ai.sort_concealed()

    print("concealed: " + Rule.convert_tiles_to_str(ai.concealed))
    print("discarded: " + Rule.convert_tiles_to_str(ai.discarded))
    print(f"strategies: {ai.strategies}")
    print(f"strategies_time: {ai.strategies_time}")
    print("draw count: " + str(ai.draw_count))
Exemplo n.º 2
0
def test_decide_discard_by_value():
    mj_set = MjSet()
    ai = PlayerAiAdv("bot02")
    for _ in range(3):
        ai.draw(mj_set)
    mj_set.shuffle()
    for _ in range(11):
        ai.draw(mj_set)
    ai.decide_discard_by_value(wall=mj_set)
Exemplo n.º 3
0
def test_decide_discard_by_remove_melds():
    mj_set = MjSet()
    ai = PlayerAiPro("bot01")
    for _ in range(3):
        ai.draw(mj_set)
    mj_set.shuffle()
    for _ in range(11):
        ai.draw(mj_set)
    ai.decide_discard_by_remove_melds()
Exemplo n.º 4
0
def test_convert():
    mj_set = MjSet()
    mj_set.shuffle()
    concealed = []
    for _ in range(13):
        concealed.append(mj_set.draw())
    print(Rule.convert_tiles_to_str(concealed))
    arr = Rule.convert_tiles_to_arr(concealed)
    print(arr)
    tiles = Rule.convert_arr_to_tiles(arr)
    print(Rule.convert_tiles_to_str(tiles))
Exemplo n.º 5
0
def test_decide_discard_by_left_meld_and_eye():
    mj_set = MjSet()
    ai = PlayerAiAdv("bot02")
    for _ in range(3):
        ai.draw(mj_set)
    mj_set.shuffle()
    for _ in range(11):
        ai.draw(mj_set)
    ai.sort_concealed()
    print("ai.concealed_str =", ai.concealed_str)
    result = ai.decide_discard_by_left_meld_and_eye()
    for x in result:
        print(x,
              Rule.convert_tiles_to_str(Rule.convert_arr_to_tiles(result[x])))
Exemplo n.º 6
0
    def test_player_ai_base(self):
        mj_set = MjSet()
        ai = PlayerAi("貂蝉")
        for _ in range(13):
            ai.draw(mj_set)
        self.assertEqual(len(ai.concealed), 13)

        mj_set.shuffle()
        for _ in range(10):
            ai.draw(mj_set)
            tile = ai.decide_discard()
            self.assertIsNotNone(tile)
            ai.discard(tile)

        self.assertEqual(len(ai.concealed), 13)
        self.assertEqual(len(ai.discarded), 10)
Exemplo n.º 7
0
    def test_ai_mahjong(self):
        mj_set = MjSet()
        ai = PlayerAi("西施")
        mj_set.shuffle()
        for _ in range(13):
            ai.draw(mj_set)
        ai.sort_concealed()

        mj_set.shuffle()
        mahjong = False
        for _ in range(100):
            tile = ai.draw(mj_set)
            if Rule.is_mahjong(ai.concealed):
                mahjong = True
                break
            tile = ai.decide_discard()
            ai.discard(tile)
            ai.sort_concealed()

        # self.assertTrue(mahjong)
        self.assertGreater(len(ai.concealed), 0)
Exemplo n.º 8
0
class Hand(object):
    __slots__ = ("_state_machine", "_machine", "_states", "_transitions",
                 "_mj_set", "_players", "_prevailing_wind", "_dealer",
                 '_positions', '_winner', 'firer', 'out_of_tiles',
                 'robbing_a_kong', 'mahjong_on_kong')

    def __init__(self,
                 players: list = None,
                 prevailing_wind: str = '东',
                 flower=False):
        if not players:
            raise ValueError("mahjong needs player!")
        self._mj_set = MjSet(flower)
        self.out_of_tiles = False
        self.robbing_a_kong = False
        self.mahjong_on_kong = False
        self._players = players
        self._positions = dict()
        for index, player in enumerate(self._players):
            wind = Suit.get_wind_by_index(index)
            player.position = wind
            self._positions[wind] = player
        self._dealer: Player = self._players[0]
        self._prevailing_wind = prevailing_wind
        self._winner = None
        self.firer = None

        # state machine
        self._state_machine = HandStateMachine()
        self._states = ["begin", "prepared", "playing", "scoring", "end"]
        self._transitions = [
            {
                'trigger': 'prepare',
                'source': 'begin',
                'dest': 'prepared'
            },  # 准备
            {
                'trigger': 'deal',
                'source': 'prepared',
                'dest': 'playing'
            },  # 拿四张
            {
                'trigger': 'mahjong',
                'source': 'playing',
                'dest': 'scoring'
            },  # 胡牌
            {
                'trigger': 'withdraw',
                'source': 'playing',
                'dest': 'scoring'
            },  # 流局
            {
                'trigger': 'score',
                'source': 'scoring',
                'dest': 'end'
            },  # 算分
        ]
        Machine(model=self._state_machine,
                states=self._states,
                transitions=self._transitions,
                initial='begin')
        # print(self.state)

    def __str__(self):
        return '\r\n'.join([f'{x.position}:{x}' for x in self._players])

    @property
    def state(self):
        return self._state_machine.state

    @property
    def players(self):
        return self._players

    @property
    def mj_set(self):
        return self._mj_set

    @property
    def dealer(self):
        return self._dealer

    @property
    def winner(self):
        return self._winner

    @property
    def positions(self):
        return self._positions

    def _shuffle(self):
        self._mj_set.shuffle()

    def _reset_players(self):
        for player in self._players:
            player.reset()

    def _get_next_player(self, current):
        bingo = False
        for player in cycle(self.players):
            if bingo:
                return player
            if current == player:
                bingo = True
        raise LookupError(f"can not find next player for {current}")

    def prepare(self):
        self._reset_players()
        self._state_machine.prepare()
        self._shuffle()

    def deal(self):
        for _ in range(max(MjMath.concealed_count) // 4):
            for player in self._players:
                player.draw_stack(self._mj_set)

        for player in self.players:
            player.draw(self._mj_set)
            player.sort_concealed()

        self._state_machine.deal()

    def play(self):

        current = self._dealer  # the current player
        player = current
        before = None  # the previous player
        current_discard = None  # discard tile by previous player

        for player in self._players:
            print(f'{player.position}: {player}')
        print("=" * 40)

        have_winner = False
        while not have_winner:

            if current_discard:
                wind = current.position
                player = current
                for index in range(3):
                    # test for hu by other
                    test = player.concealed[:]
                    test.append(current_discard)
                    if Rule.is_mahjong(test):
                        player.concealed.append(current_discard)
                        print(f"winner is {player}, by {before}")
                        self._winner = player
                        self._state_machine.mahjong()
                        have_winner = True
                        break
                    wind = Suit.get_next_wind(wind)
                    player = self.positions[wind]

            if have_winner:
                break

            # interrupted by exposed kong / pong / chow
            interrupted = False
            if current_discard:

                # Melding another for current, +1, +2 players
                player = None

                # try kong ( must have tiles ):
                if self.mj_set.tiles:
                    wind = current.position
                    player = current
                    for index in range(3):
                        if player.try_exposed_kong(tile=current_discard,
                                                   owner=before,
                                                   mj_set=self._mj_set):
                            interrupted = True
                            break
                        wind = Suit.get_next_wind(wind)
                        player = self.positions[wind]

                # try pong:
                if not interrupted:
                    wind = current.position
                    player = current
                    for index in range(3):
                        if player.try_exposed_pong(tile=current_discard,
                                                   owner=before):
                            interrupted = True
                            break
                        wind = Suit.get_next_wind(wind)
                        player = self.positions[wind]

                # try chow:
                if not interrupted:
                    wind = current.position
                    player = current
                    if player.try_exposed_chow(current_discard, before):
                        interrupted = True

                if not interrupted:
                    before.put_on_desk(current_discard)
            # end if current_discard:

            if interrupted:
                current = player
            else:
                # test for out of tiles
                if not self.mj_set.tiles:
                    print("out of tiles!")
                    self._winner = None
                    self._state_machine.withdraw()
                    break

                # draw
                current.draw(self._mj_set)
                # test for hu by self
                if Rule.is_mahjong(current.concealed):
                    print(f"winner is {current}, by self!")
                    self._winner = current
                    self._state_machine.mahjong()
                    break

                # self kong
                current.try_conceal_kong(self.mj_set)

            if isinstance(current, PlayerAiAdv):
                wall = self._mj_set.tiles
                tile = current.decide_discard(players_count=len(self.players),
                                              wall=wall)
            else:
                tile = current.decide_discard()
            print(current, 'discard:', tile)
            current.discard(tile)
            current.sort_concealed()
            current_discard = tile

            # (f'{current} discard {tile}')
            # (Rule.convert_tiles_to_str(current.concealed))

            # next player
            next = self._get_next_player(current)
            before = current
            current = next
        # end while

        print("tiles left :", len(self.mj_set.tiles))
        for player in self.players:
            if player == self.winner:
                print(f"winner {player}: ",
                      Rule.convert_tiles_to_str(player.concealed))
            else:
                print(f"{player}: ",
                      Rule.convert_tiles_to_str(player.concealed))

        left = Rule.convert_tiles_to_arr(self.mj_set.tiles)
        left.sort()
        print(self.players[0].strategies)
        print(self.players[0].strategies_time)

    # end def play()

    def score(self):
        # score the play result
        self._state_machine.score()
        pass