Exemplo n.º 1
0
    def test_defence_against_honitsu_first_case(self):
        table = Table()

        tiles = self._string_to_136_array(sou='22',
                                          pin='222367899',
                                          man='45',
                                          honors='1')
        table.player.init_hand(tiles)

        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='567')))
        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='123')))
        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='345')))

        table.add_discarded_tile(1, self._string_to_136_tile(sou='6'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='6'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='8'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='9'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)

        result = table.player.discard_tile()

        # we can't discard pin and honor tiles against honitsu
        self.assertEqual(self._to_string([result]), '2s')
Exemplo n.º 2
0
    def test_find_suji_tiles_to_discard_for_one_player(self):
        table = Table()

        tiles = self._string_to_136_array(sou='2345678', pin='12789', man='55')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(man='2'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='8'), False)

        table.add_called_riichi(1)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '5m')
Exemplo n.º 3
0
    def test_temporary_safe_tiles(self):
        table = Table()

        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)

        self.assertEqual(table.get_player(1).temporary_safe_tiles, [])
        self.assertEqual(table.get_player(2).temporary_safe_tiles, [3])
        self.assertEqual(table.get_player(3).temporary_safe_tiles, [3])

        table.add_discarded_tile(2, self._string_to_136_tile(man='5'), False)

        self.assertEqual(table.get_player(1).temporary_safe_tiles, [4])
        self.assertEqual(table.get_player(2).temporary_safe_tiles, [])
        self.assertEqual(table.get_player(3).temporary_safe_tiles, [3, 4])

        table.add_discarded_tile(3, self._string_to_136_tile(man='6'), False)

        self.assertEqual(table.get_player(1).temporary_safe_tiles, [4, 5])
        self.assertEqual(table.get_player(2).temporary_safe_tiles, [5])
        self.assertEqual(table.get_player(3).temporary_safe_tiles, [])

        table.add_discarded_tile(1, self._string_to_136_tile(man='7'), False)

        self.assertEqual(table.get_player(1).temporary_safe_tiles, [])
        self.assertEqual(table.get_player(2).temporary_safe_tiles, [5, 6])
        self.assertEqual(table.get_player(3).temporary_safe_tiles, [6])
Exemplo n.º 4
0
    def test_find_common_suji_tiles_to_discard_for_multiple_players(self):
        table = Table()

        tiles = self._string_to_136_array(sou='2345678', pin='12789', man='55')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(pin='4'), False)
        table.add_discarded_tile(2, self._string_to_136_tile(pin='4'), False)

        table.add_called_riichi(1)
        table.add_called_riichi(2)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '1p')
Exemplo n.º 5
0
    def test_mark_dora_as_dangerous_tile_for_suji(self):
        table = Table()
        table.add_dora_indicator(self._string_to_136_tile(man='8'))

        tiles = self._string_to_136_array(man='112235', pin='4557788')
        table.player.init_hand(tiles)
        # 9 man is dora!
        table.player.draw_tile(self._string_to_136_tile(man='9'))

        table.add_discarded_tile(1, self._string_to_136_tile(man='6'), False)
        table.add_called_riichi(1)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '3m')
Exemplo n.º 6
0
    def test_try_to_discard_not_needed_tiles_first_in_defence_mode(self):
        table = Table()

        tiles = self._string_to_136_array(sou='2345678',
                                          pin='789',
                                          man='55',
                                          honors='12')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(man='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='1'),
                                 False)

        table.add_called_riichi(1)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '1z')
Exemplo n.º 7
0
    def test_add_safe_tile_after_discard(self):
        table = Table()
        table.add_called_riichi(3)

        table.add_discarded_tile(1, self._string_to_136_tile(man='3'), False)
        table.add_discarded_tile(0, self._string_to_136_tile(man='4'), False)

        self.assertEqual(len(table.get_player(1).discards), 1)
        self.assertEqual(len(table.get_player(2).discards), 0)
        self.assertEqual(len(table.get_player(3).discards), 0)

        self.assertEqual(len(table.get_player(1).safe_tiles), 1)
        self.assertEqual(len(table.get_player(2).safe_tiles), 0)
        self.assertEqual(len(table.get_player(3).safe_tiles), 2)

        # "2" is 3 man
        self.assertEqual(table.get_player(1).safe_tiles, [2])
        self.assertEqual(table.get_player(3).safe_tiles, [2, 3])
Exemplo n.º 8
0
    def test_dont_discard_safe_tiles_when_call_riichi(self):
        table = Table()
        table.count_of_remaining_tiles = 70
        table.player.scores = 2000

        tiles = self._string_to_136_array(sou='12356789', pin='22678')
        table.player.init_hand(tiles)
        table.player.draw_tile(self._string_to_136_tile(honors='1'))
        table.player.discard_tile()
        table.player.draw_tile(self._string_to_136_tile(honors='1'))

        table.add_discarded_tile(1, self._string_to_136_tile(sou='1'), False)
        table.add_called_riichi(1)

        result = table.player.discard_tile()

        self.assertEqual(table.player.can_call_riichi(), True)
        self.assertEqual(self._to_string([result]), '1z')
Exemplo n.º 9
0
    def test_try_to_discard_less_valuable_tiles_first_in_defence_mode(self):
        table = Table()

        tiles = self._string_to_136_array(sou='234678',
                                          pin='6789',
                                          man='55',
                                          honors='13')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(pin='7'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='2'), False)

        table.add_called_riichi(1)

        result = table.player.discard_tile()

        # discard of 2s will do less damage to our hand shape than 7p discard
        self.assertEqual(table.player.ai.in_defence, True)
        self.assertEqual(self._to_string([result]), '2s')
Exemplo n.º 10
0
    def test_dont_activate_strategy_if_we_dont_have_enough_tiles_in_the_wall(
            self):
        table = Table()
        player = table.player
        strategy = YakuhaiStrategy(BaseStrategy.YAKUHAI, player)

        tiles = self._string_to_136_array(sou='12355689',
                                          man='89',
                                          honors='44')
        player.init_hand(tiles)
        player.dealer_seat = 1
        self.assertEqual(strategy.should_activate_strategy(), True)

        table.add_discarded_tile(3, self._string_to_136_tile(honors='4'),
                                 False)
        table.add_discarded_tile(3, self._string_to_136_tile(honors='4'),
                                 False)

        # we can't complete yakuhai, because there is not enough honor tiles
        self.assertEqual(strategy.should_activate_strategy(), False)
Exemplo n.º 11
0
    def test_find_impossible_waits_and_honor_tiles(self):
        table = Table()

        tiles = self._string_to_136_array(honors='1133')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(honors='1'),
                                 False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='3'),
                                 False)

        table.add_called_riichi(2)

        table.player.ai.defence.hand_34 = self._to_34_array(table.player.tiles)
        table.player.ai.defence.closed_hand_34 = self._to_34_array(
            table.player.closed_hand)
        result = table.player.ai.defence.impossible_wait.find_tiles_to_discard(
            [])

        # dora is not safe against tanki wait, so let's hold it
        self.assertEqual([x.value for x in result], [EAST, WEST])
Exemplo n.º 12
0
    def test_find_common_safe_tile_to_discard(self):
        table = Table()

        tiles = self._string_to_136_array(sou='2456', pin='234478', man='2336')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(sou='6'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)

        table.add_discarded_tile(2, self._string_to_136_tile(pin='5'), False)
        table.add_discarded_tile(2, self._string_to_136_tile(sou='6'), False)

        table.add_called_riichi(1)
        table.add_called_riichi(2)

        # for this test we don't need temporary_safe_tiles
        table.get_player(1).temporary_safe_tiles = []
        table.get_player(2).temporary_safe_tiles = []

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '6s')
Exemplo n.º 13
0
    def test_find_dealer_tile_to_discard(self):
        dealer = 2
        dora = self._string_to_136_tile(honors='3')
        table = Table()
        table.init_round(0, 0, 0, dora, dealer, [])

        tiles = self._string_to_136_array(sou='2234678', pin='34', man='45789')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(man='4'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='5'), False)

        table.add_discarded_tile(2, self._string_to_136_tile(man='8'), False)
        table.add_discarded_tile(2, self._string_to_136_tile(man='9'), False)

        table.add_called_riichi(1)
        table.add_called_riichi(2)

        # for this test we don't need temporary_safe_tiles
        table.get_player(1).temporary_safe_tiles = []
        table.get_player(2).temporary_safe_tiles = []

        result = table.player.discard_tile()
        # second player is a dealer, let's fold against him
        self.assertEqual(self._to_string([result]), '9m')

        tiles = self._string_to_136_array(sou='234567',
                                          pin='348',
                                          man='234',
                                          honors='23')
        table.player.init_hand(tiles)

        result = table.player.discard_tile()
        # there is no safe tiles against dealer, so let's fold against other players
        self.assertEqual(table.player.ai.in_defence, True)
        self.assertEqual(self._to_string([result]), '4m')
Exemplo n.º 14
0
    def test_try_to_detect_honitsu_hand(self):
        table = Table()

        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='567')))
        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='123')))
        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(pin='345')))

        table.add_discarded_tile(1, self._string_to_136_tile(sou='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='8'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='9'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='1'), False)

        self.assertEqual(table.get_player(1).is_threatening, True)
        self.assertEqual(table.get_player(1).chosen_suit, is_pin)
Exemplo n.º 15
0
    def test_priority_of_players_safe_tiles(self):
        table = Table()

        tiles = self._string_to_136_array(man='789',
                                          pin='2789',
                                          sou='23789',
                                          honors='1')
        table.player.init_hand(tiles)
        table.player.draw_tile(self._string_to_136_tile(sou='1'))

        table.add_discarded_tile(1, self._string_to_136_tile(sou='7'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='1'),
                                 False)
        table.add_called_riichi(1)
        table.add_discarded_tile(2, self._string_to_136_tile(honors='1'),
                                 False)

        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '1z')
Exemplo n.º 16
0
    def test_discard_not_needed_winds(self):
        table = Table()
        player = table.player
        player.scores = 25000
        table.count_of_remaining_tiles = 100

        tiles = self._string_to_136_array(man='24',
                                          pin='4',
                                          sou='12344668',
                                          honors='36')
        player.init_hand(tiles)
        player.draw_tile(self._string_to_136_tile(sou='5'))

        table.add_discarded_tile(1, self._string_to_136_tile(honors='3'),
                                 False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='3'),
                                 False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='3'),
                                 False)

        tile_to_discard = player.discard_tile()

        # west was discarded three times, we don't need it
        self.assertEqual(self._to_string([tile_to_discard]), '3z')
Exemplo n.º 17
0
    def test_defence_against_honitsu_second_case(self):
        table = Table()

        tiles = self._string_to_136_array(sou='4',
                                          pin='223456',
                                          man='678',
                                          honors='66')
        table.player.init_hand(tiles)

        table.add_called_meld(
            1, self._make_meld(Meld.CHI, self._string_to_136_array(sou='789')))
        table.add_called_meld(
            1,
            self._make_meld(Meld.PON, self._string_to_136_array(honors='444')))
        table.add_called_meld(
            1,
            self._make_meld(Meld.PON, self._string_to_136_array(honors='222')))

        table.add_discarded_tile(1, self._string_to_136_tile(man='2'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(man='8'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='1'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='3'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='4'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='6'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(sou='7'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='9'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='5'),
                                 False)
        table.add_discarded_tile(1, self._string_to_136_tile(honors='7'),
                                 False)

        table.player.draw_tile(self._string_to_136_tile(sou='9'))
        result = table.player.discard_tile()

        self.assertEqual(self._to_string([result]), '3p')
Exemplo n.º 18
0
    def reproduce(self, dry_run=False):
        draw_tags = ['T', 'U', 'V', 'W']
        discard_tags = ['D', 'E', 'F', 'G']

        player_draw = draw_tags[self.player_position]

        player_draw_regex = re.compile('^<[{}]+\d*'.format(''.join(player_draw)))
        
        draw_regex = re.compile('^<[{}]+\d*'.format(''.join(draw_tags)))
        discard_regex = re.compile('^<[{}]+\d*'.format(''.join(discard_tags)))

        table = Table()
#        previous_tag = None
        for tag in self.round_content:
            if dry_run:
                print(tag)

            if not dry_run and tag == self.stop_tag:
                break

            if 'INIT' in tag:
                values = self.decoder.parse_initial_values(tag)

                shifted_scores = []
                for x in range(0, 4):
                    shifted_scores.append(values['scores'][self._normalize_position(x, self.player_position)])

                table.init_round(
                    values['round_number'],
                    values['count_of_honba_sticks'],
                    values['count_of_riichi_sticks'],
                    values['dora_indicator'],
                    self._normalize_position(self.player_position, values['dealer']),
                    shifted_scores,
                )

                hands = [
                    [int(x) for x in self.decoder.get_attribute_content(tag, 'hai0').split(',')],
                    [int(x) for x in self.decoder.get_attribute_content(tag, 'hai1').split(',')],
                    [int(x) for x in self.decoder.get_attribute_content(tag, 'hai2').split(',')],
                    [int(x) for x in self.decoder.get_attribute_content(tag, 'hai3').split(',')],
                ]
                 
                # DEL: we can't only initialize the main player, we must initialize
                # other players as well.
                #table.player.init_hand(hands[self.player_position])
                
                # ADD: initialize all players on the table
                table.players[0].init_hand(hands[self.player_position])
                table.players[1].init_hand(hands[(self.player_position+1)%4])
                table.players[2].init_hand(hands[(self.player_position+2)%4])
                table.players[3].init_hand(hands[(self.player_position+3)%4])
                
                # ADD: when restart a new game, we need to reinitialize the config
                self.extract_features.__init__()

            # We must deal with ALL players.
            #if player_draw_regex.match(tag) and 'UN' not in tag:
            if draw_regex.match(tag) and 'UN' not in tag:
                tile = self.decoder.parse_tile(tag)
                
                # CHG: we must deal with ALL players
                #table.player.draw_tile(tile)
                if "T" in tag:
                    table.players[0].draw_tile(tile)
                elif "U" in tag:
                    table.players[1].draw_tile(tile)
                elif "V" in tag:
                    table.players[2].draw_tile(tile)
                elif "W" in tag:
                    table.players[3].draw_tile(tile)
                    #print("After draw `W`:", table.players[3].tiles)
                
            if discard_regex.match(tag) and 'DORA' not in tag:
                tile = self.decoder.parse_tile(tag)
                player_sign = tag.upper()[1]
                
                # TODO: I don't know why the author wrote the code as below, the 
                # player_seat won't work if we use self._normalize_position. This 
                # might be a tricky part, and we need to review it later.
                #player_seat = self._normalize_position(self.player_position, discard_tags.index(player_sign))
                
                # Temporally solution to modify the player_seat
                player_seat = (discard_tags.index(player_sign) + self.player_position)%4
                #print("updated player seat:",player_seat)
                
                
                if player_seat == 0:
                    table.players[player_seat].discard_tile(DiscardOption(table.players[player_seat], tile // 4, 0, [], 0))
                else:
                    # ADD: we must take care of ALL players
                    tile_to_discard = tile
            
                    is_tsumogiri = tile_to_discard == table.players[player_seat].last_draw
                    # it is important to use table method,
                    # to recalculate revealed tiles and etc.
                    table.add_discarded_tile(player_seat, tile_to_discard, is_tsumogiri)
                    
                    #print("seat:",player_seat)
                    #print("tiles:", TilesConverter.to_one_line_string(table.players[player_seat].tiles), " discard?:", TilesConverter.to_one_line_string([tile_to_discard]))
                    table.players[player_seat].tiles.remove(tile_to_discard)
            
                    
                    # DEL
                    #table.add_discarded_tile(player_seat, tile, False)

            if '<N who=' in tag:
                meld = self.decoder.parse_meld(tag)
                #player_seat = self._normalize_position(self.player_position, meld.who)
                # Again, we change the player_seat here
                player_seat = (meld.who + self.player_position) % 4
                table.add_called_meld(player_seat, meld)

                #if player_seat == 0:
                # CHG: we need to handle ALL players here    
                if True:
                    # we had to delete called tile from hand
                    # to have correct tiles count in the hand
                    if meld.type != Meld.KAN and meld.type != Meld.CHANKAN:
                        table.players[player_seat].draw_tile(meld.called_tile)

            if '<REACH' in tag and 'step="1"' in tag:
                who_called_riichi = self._normalize_position(self.player_position,
                                                             self.decoder.parse_who_called_riichi(tag))
                table.add_called_riichi(who_called_riichi)
              
            # This part is to extract the features that will be used to train
            # our model.
            
#            if '<AGARI' in tag:
#                print(previous_tag)
#                print(tag)
#                print("~~~~~~~~~\n")
            
            if '<D' in tag:
                #features = self.extract_features.get_is_waiting_features(table)
                features = self.extract_features.get_waiting_tiles_features(table)
                if features is not None:
                    features_list = features.split(";")
                    assert len(features_list)==6, "<D> Features format incorrect!"
                    table_info = features_list[0]
                    player_info = features_list[1]
                    logger2.info(table_info + ";" + player_info)
            if '<E' in tag:
                #features = self.extract_features.get_is_waiting_features(table)
                features = self.extract_features.get_waiting_tiles_features(table)
                if features is not None:
                    features_list = features.split(";")
                    assert len(features_list)==6, "<E> Features format incorrect!"
                    table_info = features_list[0]
                    player_info = features_list[2]
                    logger2.info(table_info + ";" + player_info)
            if '<F' in tag:
                #features = self.extract_features.get_is_waiting_features(table)
                features = self.extract_features.get_waiting_tiles_features(table)
                if features is not None:
                    features_list = features.split(";")
                    assert len(features_list)==6, "<F> Features format incorrect!"
                    table_info = features_list[0]
                    player_info = features_list[3]
                    logger2.info(table_info + ";" + player_info)
            if '<G' in tag:
                #features = self.extract_features.get_is_waiting_features(table)
                features = self.extract_features.get_waiting_tiles_features(table)
                if features is not None:
                    features_list = features.split(";")
                    assert len(features_list)==6, "<G> Features format incorrect!"
                    table_info = features_list[0]
                    player_info = features_list[4]
                    logger2.info(table_info + ";" + player_info)
                    
#            previous_tag = tag


        if not dry_run:
            tile = self.decoder.parse_tile(self.stop_tag)
            print('Hand: {}'.format(table.player.format_hand_for_print(tile)))

            # to rebuild all caches
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            # real run, you can stop debugger here
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            print('Discard: {}'.format(TilesConverter.to_one_line_string([tile])))
    def reproduce(self, dry_run=False):
        draw_tags = ['T', 'U', 'V', 'W']
        discard_tags = ['D', 'E', 'F', 'G']

        player_draw = draw_tags[self.player_position]

        player_draw_regex = re.compile('^<[{}]+\d*'.format(
            ''.join(player_draw)))

        draw_regex = re.compile('^<[{}]+\d*'.format(''.join(draw_tags)))
        discard_regex = re.compile('^<[{}]+\d*'.format(''.join(discard_tags)))

        table = Table()
        previous_tag = ""
        score = 1
        is_valid_sample = False
        for n, tag in enumerate(self.round_content):
            if dry_run:
                print(tag)

            if not dry_run and tag == self.stop_tag:
                break

            if 'INIT' in tag:
                values = self.decoder.parse_initial_values(tag)

                shifted_scores = []
                for x in range(0, 4):
                    shifted_scores.append(
                        values['scores'][self._normalize_position(
                            x, self.player_position)])

                table.init_round(
                    values['round_number'],
                    values['count_of_honba_sticks'],
                    values['count_of_riichi_sticks'],
                    values['dora_indicator'],
                    self._normalize_position(self.player_position,
                                             values['dealer']),
                    shifted_scores,
                )

                hands = [
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai0').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai1').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai2').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai3').split(',')
                    ],
                ]

                # DEL: we can't only initialize the main player, we must initialize
                # other players as well.
                #table.player.init_hand(hands[self.player_position])

                # ADD: initialize all players on the table
                table.players[0].init_hand(hands[self.player_position])
                table.players[1].init_hand(hands[(self.player_position + 1) %
                                                 4])
                table.players[2].init_hand(hands[(self.player_position + 2) %
                                                 4])
                table.players[3].init_hand(hands[(self.player_position + 3) %
                                                 4])

                # ADD: when restart a new game, we need to reinitialize the config
                self.extract_features.__init__()

            # We must deal with ALL players.
            #if player_draw_regex.match(tag) and 'UN' not in tag:
            if draw_regex.match(tag) and 'UN' not in tag:
                tile = self.decoder.parse_tile(tag)

                # CHG: we must deal with ALL players
                #table.player.draw_tile(tile)
                if "T" in tag:
                    table.players[0].draw_tile(tile)
                elif "U" in tag:
                    table.players[1].draw_tile(tile)
                elif "V" in tag:
                    table.players[2].draw_tile(tile)
                elif "W" in tag:
                    table.players[3].draw_tile(tile)
                    #print("After draw `W`:", table.players[3].tiles)

            if discard_regex.match(tag) and 'DORA' not in tag:
                tile = self.decoder.parse_tile(tag)
                player_sign = tag.upper()[1]

                # TODO: I don't know why the author wrote the code as below, the
                # player_seat won't work if we use self._normalize_position. This
                # might be a tricky part, and we need to review it later.
                #player_seat = self._normalize_position(self.player_position, discard_tags.index(player_sign))

                # Temporally solution to modify the player_seat
                player_seat = (discard_tags.index(player_sign) +
                               self.player_position) % 4
                #print("updated player seat:",player_seat)

                if player_seat == 0:
                    table.players[player_seat].discard_tile(
                        DiscardOption(table.players[player_seat], tile // 4, 0,
                                      [], 0))
                else:
                    # ADD: we must take care of ALL players
                    tile_to_discard = tile

                    is_tsumogiri = tile_to_discard == table.players[
                        player_seat].last_draw
                    # it is important to use table method,
                    # to recalculate revealed tiles and etc.
                    table.add_discarded_tile(player_seat, tile_to_discard,
                                             is_tsumogiri)

                    #print("seat:",player_seat)
                    #print("tiles:", TilesConverter.to_one_line_string(table.players[player_seat].tiles), " discard?:", TilesConverter.to_one_line_string([tile_to_discard]))
                    table.players[player_seat].tiles.remove(tile_to_discard)

                    # DEL
                    #table.add_discarded_tile(player_seat, tile, False)

            if '<N who=' in tag:
                meld = self.decoder.parse_meld(tag)
                #player_seat = self._normalize_position(self.player_position, meld.who)
                # Again, we change the player_seat here
                player_seat = (meld.who + self.player_position) % 4
                table.add_called_meld(player_seat, meld)

                #if player_seat == 0:
                # CHG: we need to handle ALL players here
                if True:
                    # we had to delete called tile from hand
                    # to have correct tiles count in the hand
                    if meld.type != Meld.KAN and meld.type != Meld.CHANKAN:
                        table.players[player_seat].draw_tile(meld.called_tile)

            if '<REACH' in tag and 'step="1"' in tag:
                who_called_riichi = self._normalize_position(
                    self.player_position,
                    self.decoder.parse_who_called_riichi(tag))
                table.add_called_riichi(who_called_riichi)

            # This part is to extract the features that will be used to train
            # our model.
            try:
                next_tag = self.round_content[n + 1]
            except IndexError:
                next_tag = ""
            if '<AGARI' in next_tag:
                who_regex = re.compile("who=\"\d+\"")
                fromWho_regex = re.compile("fromWho=\"\d+\"")
                sc_regex = "sc=\"[+-]?\d+,[+-]?\d+,[+-]?\d+,[+-]?\d+,[+-]?\d+,[+-]?\d+,[+-]?\d+,[+-]?\d+\""
                score_regex = re.compile(sc_regex)
                who = int(
                    who_regex.search(next_tag).group(0).replace(
                        '"', '').split("=")[1])
                fromWho = int(
                    fromWho_regex.search(next_tag).group(0).replace(
                        '"', '').split("=")[1])
                scores = [
                    float(s)
                    for s in score_regex.search(next_tag).group(0).replace(
                        '"', '').split("=")[1].split(",")
                ]
                score = scores[fromWho * 2 + 1]
                player_seat, features = self.execute_extraction(tag, table)

                #                # tsumo is not a valid sample for our training.
                #                if (who!=fromWho): # not tsumo (lose the score to winner, score<0)
                #                    if (features is not None) and (player_seat is not None) and (score<0):
                #                        # The first element before ";" is table_info, therefore player_info starts
                #                        # from index 1, and we put who+1 here.
                #                        self.feature_to_logger(features, who+1, score)
                #                        score = 1

                # tsumo is a valid sample for our training
                if (who == fromWho):  # tsumo (win the score, score>0)
                    if (features
                            is not None) and (player_seat
                                              is not None) and (score > 0):
                        self.feature_to_logger(features, who + 1, score)
                        score = -1

            else:
                player_seat, features = self.execute_extraction(tag, table)

        if not dry_run:
            tile = self.decoder.parse_tile(self.stop_tag)
            print('Hand: {}'.format(table.player.format_hand_for_print(tile)))

            # to rebuild all caches
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            # real run, you can stop debugger here
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            print('Discard: {}'.format(
                TilesConverter.to_one_line_string([tile])))
Exemplo n.º 20
0
    def reproduce(self, dry_run=False):
        draw_tags = ['T', 'U', 'V', 'W']
        discard_tags = ['D', 'E', 'F', 'G']

        player_draw = draw_tags[self.player_position]

        player_draw_regex = re.compile('^<[{}]+\d*'.format(
            ''.join(player_draw)))
        discard_regex = re.compile('^<[{}]+\d*'.format(''.join(discard_tags)))

        table = Table()
        for tag in self.round_content:
            if dry_run:
                print(tag)

            if not dry_run and tag == self.stop_tag:
                break

            if 'INIT' in tag:
                values = self.decoder.parse_initial_values(tag)

                shifted_scores = []
                for x in range(0, 4):
                    shifted_scores.append(
                        values['scores'][self._normalize_position(
                            x, self.player_position)])

                table.init_round(
                    values['round_number'],
                    values['count_of_honba_sticks'],
                    values['count_of_riichi_sticks'],
                    values['dora_indicator'],
                    self._normalize_position(self.player_position,
                                             values['dealer']),
                    shifted_scores,
                )

                hands = [
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai0').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai1').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai2').split(',')
                    ],
                    [
                        int(x) for x in self.decoder.get_attribute_content(
                            tag, 'hai3').split(',')
                    ],
                ]

                table.player.init_hand(hands[self.player_position])

            if player_draw_regex.match(tag) and 'UN' not in tag:
                tile = self.decoder.parse_tile(tag)
                table.player.draw_tile(tile)

            if discard_regex.match(tag) and 'DORA' not in tag:
                tile = self.decoder.parse_tile(tag)
                player_sign = tag.upper()[1]
                player_seat = self._normalize_position(
                    self.player_position, discard_tags.index(player_sign))

                if player_seat == 0:
                    table.player.discard_tile(
                        DiscardOption(table.player, tile // 4, 0, [], 0))
                else:
                    table.add_discarded_tile(player_seat, tile, False)

            if '<N who=' in tag:
                meld = self.decoder.parse_meld(tag)
                player_seat = self._normalize_position(self.player_position,
                                                       meld.who)
                table.add_called_meld(player_seat, meld)

                if player_seat == 0:
                    # we had to delete called tile from hand
                    # to have correct tiles count in the hand
                    if meld.type != Meld.KAN and meld.type != Meld.CHANKAN:
                        table.player.draw_tile(meld.called_tile)

            if '<REACH' in tag and 'step="1"' in tag:
                who_called_riichi = self._normalize_position(
                    self.player_position,
                    self.decoder.parse_who_called_riichi(tag))
                table.add_called_riichi(who_called_riichi)

        if not dry_run:
            tile = self.decoder.parse_tile(self.stop_tag)
            print('Hand: {}'.format(table.player.format_hand_for_print(tile)))

            # to rebuild all caches
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            # real run, you can stop debugger here
            table.player.draw_tile(tile)
            tile = table.player.discard_tile()

            print('Discard: {}'.format(
                TilesConverter.to_one_line_string([tile])))
Exemplo n.º 21
0
    def test_find_impossible_waits_and_kabe_technique(self):
        table = Table()
        tiles = self._string_to_136_array(pin='11122777799')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(pin='2'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='2'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='9'), False)

        table.add_called_riichi(2)

        table.player.ai.defence.hand_34 = self._to_34_array(table.player.tiles)
        table.player.ai.defence.closed_hand_34 = self._to_34_array(
            table.player.closed_hand)
        result = table.player.ai.defence.kabe.find_tiles_to_discard([])

        self.assertEqual(self._to_string([x.value * 4 for x in result]), '19p')

        table = Table()
        tiles = self._string_to_136_array(pin='33337777')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)

        table.add_called_riichi(2)

        table.player.ai.defence.hand_34 = self._to_34_array(table.player.tiles)
        table.player.ai.defence.closed_hand_34 = self._to_34_array(
            table.player.closed_hand)
        result = table.player.ai.defence.kabe.find_tiles_to_discard([])

        self.assertEqual(self._to_string([x.value * 4 for x in result]), '5p')

        table = Table()
        tiles = self._string_to_136_array(pin='33334446666')
        table.player.init_hand(tiles)

        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)
        table.add_discarded_tile(1, self._string_to_136_tile(pin='5'), False)

        table.add_called_riichi(2)

        table.player.ai.defence.hand_34 = self._to_34_array(table.player.tiles)
        table.player.ai.defence.closed_hand_34 = self._to_34_array(
            table.player.closed_hand)
        result = table.player.ai.defence.kabe.find_tiles_to_discard([])

        self.assertEqual(self._to_string([x.value * 4 for x in result]), '45p')