def test_init_round(self): table = Table() round_number = 4 count_of_honba_sticks = 2 count_of_riichi_sticks = 3 dora_indicator = 126 dealer = 3 scores = [250, 250, 250, 250] table.init_round(round_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores) self.assertEqual(table.round_number, round_number) self.assertEqual(table.count_of_honba_sticks, count_of_honba_sticks) self.assertEqual(table.count_of_riichi_sticks, count_of_riichi_sticks) self.assertEqual(table.dora_indicators[0], dora_indicator) self.assertEqual(table.get_player(dealer).is_dealer, True) self.assertEqual(table.get_player(dealer).scores, 25000) dealer = 2 table.player.in_tempai = True table.player.in_riichi = True table.init_round(round_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores) # test that we reinit round properly self.assertEqual(table.get_player(3).is_dealer, False) self.assertEqual(table.player.in_tempai, False) self.assertEqual(table.player.in_riichi, False) self.assertEqual(table.get_player(dealer).is_dealer, True)
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')
def test_init_round(): table = Table() round_wind_number = 4 count_of_honba_sticks = 2 count_of_riichi_sticks = 3 dora_indicator = 126 dealer = 3 scores = [250, 250, 250, 250] table.init_round(round_wind_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores) assert table.round_wind_number == round_wind_number assert table.count_of_honba_sticks == count_of_honba_sticks assert table.count_of_riichi_sticks == count_of_riichi_sticks assert table.dora_indicators[0] == dora_indicator assert table.get_player(dealer).is_dealer is True assert table.get_player(dealer).scores == 25000 dealer = 2 table.player.in_tempai = True table.player.in_riichi = True table.init_round(round_wind_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores) # test that we reinit round properly assert table.get_player(3).is_dealer is False assert table.player.in_tempai is False assert table.player.in_riichi is False assert table.get_player(dealer).is_dealer is True
def test_set_names_and_ranks(): table = Table() table.init_round(0, 0, 0, 0, 0, []) values = [ { "name": "NoName", "rank": "新人" }, { "name": "o2o2", "rank": "3級" }, { "name": "shimmmmm", "rank": "三段" }, { "name": "川海老", "rank": "9級" }, ] table.set_players_names_and_ranks(values) assert table.get_player(0).name == "NoName" assert table.get_player(0).rank == "新人" assert table.get_player(3).name == "川海老" assert table.get_player(3).rank == "9級"
def _make_table(): table = Table() table.init_round(1, 0, 0, string_to_136_tile(honors="4"), 0, [250, 250, 250, 250]) # with that we don't have daburi anymore table.player.round_step = 1 return table
def test_set_scores(): table = Table() table.init_round(0, 0, 0, 0, 0, []) scores = [230, 110, 55, 405] table.set_players_scores(scores) assert table.get_player(0).scores == 23000 assert table.get_player(1).scores == 11000 assert table.get_player(2).scores == 5500 assert table.get_player(3).scores == 40500
def test_set_scores(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) scores = [230, 110, 55, 405] table.set_players_scores(scores) self.assertEqual(table.get_player(0).scores, 23000) self.assertEqual(table.get_player(1).scores, 11000) self.assertEqual(table.get_player(2).scores, 5500) self.assertEqual(table.get_player(3).scores, 40500)
def test_is_dora(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) table.dora_indicators = [self._string_to_136_tile(sou='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='2'))) table.dora_indicators = [self._string_to_136_tile(sou='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(sou='1'))) table.dora_indicators = [self._string_to_136_tile(pin='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(pin='1'))) table.dora_indicators = [self._string_to_136_tile(man='9')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='1'))) table.dora_indicators = [self._string_to_136_tile(man='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(man='6'))) table.dora_indicators = [self._string_to_136_tile(honors='1')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='2'))) table.dora_indicators = [self._string_to_136_tile(honors='2')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='3'))) table.dora_indicators = [self._string_to_136_tile(honors='3')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='4'))) table.dora_indicators = [self._string_to_136_tile(honors='4')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='1'))) table.dora_indicators = [self._string_to_136_tile(honors='5')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='6'))) table.dora_indicators = [self._string_to_136_tile(honors='6')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='7'))) table.dora_indicators = [self._string_to_136_tile(honors='7')] self.assertTrue(table.is_dora(self._string_to_136_tile(honors='5'))) table.dora_indicators = [self._string_to_136_tile(pin='1')] self.assertFalse(table.is_dora(self._string_to_136_tile(sou='2'))) table.has_open_tanyao = True # red five man self.assertTrue(table.is_dora(FIVE_RED_MAN)) # red five pin self.assertTrue(table.is_dora(FIVE_RED_PIN)) # red five sou self.assertTrue(table.is_dora(FIVE_RED_SOU))
def test_is_dora(): table = Table() table.init_round(0, 0, 0, 0, 0, []) table.dora_indicators = [string_to_136_tile(sou="1")] assert table.is_dora(string_to_136_tile(sou="2")) table.dora_indicators = [string_to_136_tile(sou="9")] assert table.is_dora(string_to_136_tile(sou="1")) table.dora_indicators = [string_to_136_tile(pin="9")] assert table.is_dora(string_to_136_tile(pin="1")) table.dora_indicators = [string_to_136_tile(man="9")] assert table.is_dora(string_to_136_tile(man="1")) table.dora_indicators = [string_to_136_tile(man="5")] assert table.is_dora(string_to_136_tile(man="6")) table.dora_indicators = [string_to_136_tile(honors="1")] assert table.is_dora(string_to_136_tile(honors="2")) table.dora_indicators = [string_to_136_tile(honors="2")] assert table.is_dora(string_to_136_tile(honors="3")) table.dora_indicators = [string_to_136_tile(honors="3")] assert table.is_dora(string_to_136_tile(honors="4")) table.dora_indicators = [string_to_136_tile(honors="4")] assert table.is_dora(string_to_136_tile(honors="1")) table.dora_indicators = [string_to_136_tile(honors="5")] assert table.is_dora(string_to_136_tile(honors="6")) table.dora_indicators = [string_to_136_tile(honors="6")] assert table.is_dora(string_to_136_tile(honors="7")) table.dora_indicators = [string_to_136_tile(honors="7")] assert table.is_dora(string_to_136_tile(honors="5")) table.dora_indicators = [string_to_136_tile(pin="1")] assert not table.is_dora(string_to_136_tile(sou="2")) table.has_open_tanyao = True # red five man assert table.is_dora(FIVE_RED_MAN) # red five pin assert table.is_dora(FIVE_RED_PIN) # red five sou assert table.is_dora(FIVE_RED_SOU)
def test_set_scores_and_uma(): table = Table() table.init_round(0, 0, 0, 0, 0, []) scores = [230, 110, 55, 405] uma = [-17, 3, 48, -34] table.set_players_scores(scores, uma) assert table.get_player(0).scores == 23000 assert table.get_player(0).uma == (-17) assert table.get_player(1).scores == 11000 assert table.get_player(1).uma == 3 assert table.get_player(2).scores == 5500 assert table.get_player(2).uma == 48 assert table.get_player(3).scores == 40500 assert table.get_player(3).uma == (-34)
def test_set_scores_and_uma(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) scores = [230, 110, 55, 405] uma = [-17, 3, 48, -34] table.set_players_scores(scores, uma) self.assertEqual(table.get_player(0).scores, 23000) self.assertEqual(table.get_player(0).uma, -17) self.assertEqual(table.get_player(1).scores, 11000) self.assertEqual(table.get_player(1).uma, 3) self.assertEqual(table.get_player(2).scores, 5500) self.assertEqual(table.get_player(2).uma, 48) self.assertEqual(table.get_player(3).scores, 40500) self.assertEqual(table.get_player(3).uma, -34)
def test_round_wind(): table = Table() table.init_round(0, 0, 0, 0, 0, []) assert table.round_wind_tile == EAST table.init_round(3, 0, 0, 0, 0, []) assert table.round_wind_tile == EAST table.init_round(7, 0, 0, 0, 0, []) assert table.round_wind_tile == SOUTH table.init_round(11, 0, 0, 0, 0, []) assert table.round_wind_tile == WEST table.init_round(12, 0, 0, 0, 0, []) assert table.round_wind_tile == NORTH
def test_set_names_and_ranks(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) values = [ {'name': 'NoName', 'rank': u'新人'}, {'name': 'o2o2', 'rank': u'3級'}, {'name': 'shimmmmm', 'rank': u'三段'}, {'name': u'川海老', 'rank': u'9級'} ] table.set_players_names_and_ranks(values) self.assertEqual(table.get_player(0).name, 'NoName') self.assertEqual(table.get_player(0).rank, u'新人') self.assertEqual(table.get_player(3).name, u'川海老') self.assertEqual(table.get_player(3).rank, u'9級')
def test_round_wind(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) self.assertEqual(table.round_wind_tile, EAST) table.init_round(3, 0, 0, 0, 0, []) self.assertEqual(table.round_wind_tile, EAST) table.init_round(7, 0, 0, 0, 0, []) self.assertEqual(table.round_wind_tile, SOUTH) table.init_round(11, 0, 0, 0, 0, []) self.assertEqual(table.round_wind_tile, WEST) table.init_round(12, 0, 0, 0, 0, []) self.assertEqual(table.round_wind_tile, NORTH)
def test_round_wind(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) self.assertEqual(table.round_wind, EAST) table.init_round(3, 0, 0, 0, 0, []) self.assertEqual(table.round_wind, EAST) table.init_round(7, 0, 0, 0, 0, []) self.assertEqual(table.round_wind, SOUTH) table.init_round(11, 0, 0, 0, 0, []) self.assertEqual(table.round_wind, WEST) table.init_round(12, 0, 0, 0, 0, []) self.assertEqual(table.round_wind, NORTH)
def test_init_round(self): table = Table() round_wind_number = 4 count_of_honba_sticks = 2 count_of_riichi_sticks = 3 dora_indicator = 126 dealer = 3 scores = [250, 250, 250, 250] table.init_round( round_wind_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores ) self.assertEqual(table.round_wind_number, round_wind_number) self.assertEqual(table.count_of_honba_sticks, count_of_honba_sticks) self.assertEqual(table.count_of_riichi_sticks, count_of_riichi_sticks) self.assertEqual(table.dora_indicators[0], dora_indicator) self.assertEqual(table.get_player(dealer).is_dealer, True) self.assertEqual(table.get_player(dealer).scores, 25000) dealer = 2 table.player.in_tempai = True table.player.in_riichi = True table.init_round( round_wind_number, count_of_honba_sticks, count_of_riichi_sticks, dora_indicator, dealer, scores ) # test that we reinit round properly self.assertEqual(table.get_player(3).is_dealer, False) self.assertEqual(table.player.in_tempai, False) self.assertEqual(table.player.in_riichi, False) self.assertEqual(table.get_player(dealer).is_dealer, True)
def test_find_tile_to_discard_when_no_safe_tile(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='2234555', pin='11', man='11113') table.player.init_hand(tiles) table.add_discarded_tile(1, self._string_to_136_tile(man='8'), False) table.add_discarded_tile(1, self._string_to_136_tile(man='9'), 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() # No safe tile to discard. So should discard 5s self.assertEqual(self._to_string([result]), '1m') tiles = self._string_to_136_array(sou='2234556', pin='11', man='34567') table.player.init_hand(tiles) result = table.player.discard_tile() # No safe tile to discard. So should discard 1p self.assertEqual(self._to_string([result]), '1p') tiles = self._string_to_136_array(sou='2345678', pin='19', man='34567') table.player.init_hand(tiles) result = table.player.discard_tile() # No safe tile to discard. So should discard 1p self.assertEqual(self._to_string([result]), '1p')
def test_set_scores_and_recalculate_player_position(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) self.assertEqual(table.get_player(0).first_seat, 0) self.assertEqual(table.get_player(1).first_seat, 1) self.assertEqual(table.get_player(2).first_seat, 2) self.assertEqual(table.get_player(3).first_seat, 3) scores = [230, 110, 55, 405] table.set_players_scores(scores) self.assertEqual(table.get_player(0).position, 2) self.assertEqual(table.get_player(1).position, 3) self.assertEqual(table.get_player(2).position, 4) self.assertEqual(table.get_player(3).position, 1) scores = [110, 110, 405, 405] table.set_players_scores(scores) self.assertEqual(table.get_player(0).position, 3) self.assertEqual(table.get_player(1).position, 4) self.assertEqual(table.get_player(2).position, 1) self.assertEqual(table.get_player(3).position, 2)
def test_set_scores_and_recalculate_player_position(): table = Table() table.init_round(0, 0, 0, 0, 0, []) assert table.get_player(0).first_seat == 0 assert table.get_player(1).first_seat == 1 assert table.get_player(2).first_seat == 2 assert table.get_player(3).first_seat == 3 scores = [230, 110, 55, 405] table.set_players_scores(scores) assert table.get_player(0).position == 2 assert table.get_player(1).position == 3 assert table.get_player(2).position == 4 assert table.get_player(3).position == 1 scores = [110, 110, 405, 405] table.set_players_scores(scores) assert table.get_player(0).position == 3 assert table.get_player(1).position == 4 assert table.get_player(2).position == 1 assert table.get_player(3).position == 2
def test_set_names_and_ranks(self): table = Table() table.init_round(0, 0, 0, 0, 0, []) values = [{ 'name': 'NoName', 'rank': u'新人' }, { 'name': 'o2o2', 'rank': u'3級' }, { 'name': 'shimmmmm', 'rank': u'三段' }, { 'name': u'川海老', 'rank': u'9級' }] table.set_players_names_and_ranks(values) self.assertEqual(table.get_player(0).name, 'NoName') self.assertEqual(table.get_player(0).rank, u'新人') self.assertEqual(table.get_player(3).name, u'川海老') self.assertEqual(table.get_player(3).rank, u'9級')
def test_players_wind(): table = Table() player = table.player dealer_seat = 0 table.init_round(0, 0, 0, 0, dealer_seat, []) assert player.player_wind == EAST assert table.get_player(1).player_wind == SOUTH dealer_seat = 1 table.init_round(0, 0, 0, 0, dealer_seat, []) assert player.player_wind == NORTH assert table.get_player(1).player_wind == EAST dealer_seat = 2 table.init_round(0, 0, 0, 0, dealer_seat, []) assert player.player_wind == WEST assert table.get_player(1).player_wind == NORTH dealer_seat = 3 table.init_round(0, 0, 0, 0, dealer_seat, []) assert player.player_wind == SOUTH assert table.get_player(1).player_wind == WEST
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 player_draw_regex.match(tag) and 'UN' not in tag: print('Player draw') tile = self.decoder.parse_tile(tag) table.player.draw_tile(tile) if dry_run: if self._is_draw(tag): print('<-', TilesConverter.to_one_line_string([self._parse_tile(tag)]), tag) elif self._is_discard(tag): print('->', TilesConverter.to_one_line_string([self._parse_tile(tag)]), tag) elif self._is_init_tag(tag): hands = { 0: [int(x) for x in self._get_attribute_content(tag, 'hai0').split(',')], 1: [int(x) for x in self._get_attribute_content(tag, 'hai1').split(',')], 2: [int(x) for x in self._get_attribute_content(tag, 'hai2').split(',')], 3: [int(x) for x in self._get_attribute_content(tag, 'hai3').split(',')], } print('Initial hand:', TilesConverter.to_one_line_string(hands[self.player_position])) else: 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_wind_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 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(tile) 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])))
def reproduce(self, dry_run=True, verbose=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(self.params) total = defaultdict(int) results = defaultdict(int) for i, r in enumerate(self.rounds): print("Round:", i) print() for tag in r: if dry_run: #print(tag) pass 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: # TODO: add player's state, river, melds, and reach timepoint current_hand = TilesConverter.to_one_line_string( table.player.tiles) choice = table.player.ai.discard_tile(None) table.player.discard_tile(tile) match = int(tile == choice) total["TOTAL"] += 1 results["TOTAL"] += match total[table.player.play_state] += 1 results[table.player.play_state] += match if verbose: print("Hand:", current_hand) print("AI's Choice:", TilesConverter.to_one_line_string([choice])) print("MP's Choice:", TilesConverter.to_one_line_string(([tile]))) print("AI's State:", table.player.play_state) print("Same:", tile == choice) print() 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) # TODO: add reach time point if dry_run: print(total, results) return total, results 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))) discard_regex = re.compile('^<[{}]+\d*'.format(''.join(discard_tags))) table = Table() for tag in self.round_content: if player_draw_regex.match(tag) and 'UN' not in tag: print('Player draw') tile = self.decoder.parse_tile(tag) table.player.draw_tile(tile) if dry_run: if self._is_draw(tag): print( '<-', TilesConverter.to_one_line_string( [self._parse_tile(tag)]), tag) elif self._is_discard(tag): print( '->', TilesConverter.to_one_line_string( [self._parse_tile(tag)]), tag) elif self._is_init_tag(tag): hands = { 0: [ int(x) for x in self._get_attribute_content( tag, 'hai0').split(',') ], 1: [ int(x) for x in self._get_attribute_content( tag, 'hai1').split(',') ], 2: [ int(x) for x in self._get_attribute_content( tag, 'hai2').split(',') ], 3: [ int(x) for x in self._get_attribute_content( tag, 'hai3').split(',') ], } print( 'Initial hand:', TilesConverter.to_one_line_string( hands[self.player_position])) else: 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_wind_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 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(tile) 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])))
def reproduce(self, player, wind, honba, needed_tile, action, tile_number_to_stop): player_position = self._find_player_position(player) round_content = self._find_needed_round(wind, honba) draw_tags = ["T", "U", "V", "W"] discard_tags = ["D", "E", "F", "G"] player_draw = draw_tags[player_position] player_draw_regex = re.compile(r"^<[{}]+\d*".format( "".join(player_draw))) discard_regex = re.compile(r"^<[{}]+\d*".format("".join(discard_tags))) draw_regex = re.compile(r"^<[{}]+\d*".format("".join(draw_tags))) last_draws = {0: None, 1: None, 2: None, 3: None} table = Table() # TODO get this info from log content table.has_aka_dora = True table.has_open_tanyao = True table.player.init_logger(self.logger) players = {} for round_item in self.rounds: for tag in round_item: if "<UN" in tag: players_temp = self.decoder.parse_names_and_ranks(tag) if players_temp: for x in players_temp: players[x["seat"]] = x draw_tile_seen_number = 0 enemy_discard_seen_number = 0 for tag in round_content: if player_draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) table.count_of_remaining_tiles -= 1 # is it time to stop reproducing? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile if action == "draw" and found_tile: draw_tile_seen_number += 1 if draw_tile_seen_number == tile_number_to_stop: self.logger.info("Stop on player draw") discard_result = None with_riichi = False table.player.draw_tile(tile) table.player.should_call_kan( tile, open_kan=False, from_riichi=table.player.in_riichi) if not table.player.in_riichi: discard_result = table.player.discard_tile() with_riichi = table.player.can_call_riichi() return discard_result, with_riichi table.player.draw_tile(tile) 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( player_position, x)]) table.init_round( values["round_wind_number"], values["count_of_honba_sticks"], values["count_of_riichi_sticks"], values["dora_indicator"], self._normalize_position(values["dealer"], player_position), 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[player_position]) table.player.name = players[player_position]["name"] self.logger.info("Init round info") self.logger.info(table.player.name) self.logger.info(f"Scores: {table.player.scores}") self.logger.info( f"Wind: {DISPLAY_WINDS[table.player.player_wind]}") if "DORA hai" in tag: table.add_dora_indicator( int(self._get_attribute_content(tag, "hai"))) if draw_regex.match(tag) and "UN" not in tag: tile = self.decoder.parse_tile(tag) player_sign = tag.upper()[1] player_seat = self._normalize_position( draw_tags.index(player_sign), player_position) last_draws[player_seat] = 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( discard_tags.index(player_sign), player_position) if player_seat == 0: table.player.discard_tile(tile, force_tsumogiri=True) else: # is it time to stop? found_tile = TilesConverter.to_one_line_string( [tile]) == needed_tile is_kamicha_discard = player_seat == 3 if action == "enemy_discard" and found_tile: enemy_discard_seen_number += 1 if enemy_discard_seen_number == tile_number_to_stop: self.logger.info("Stop on enemy discard") self._rebuild_bot_shanten_cache(table.player) table.player.should_call_kan(tile, open_kan=True, from_riichi=False) return table.player.try_to_call_meld( tile, is_kamicha_discard) is_tsumogiri = last_draws[player_seat] == tile table.add_discarded_tile(player_seat, tile, is_tsumogiri=is_tsumogiri) if "<N who=" in tag: meld = self.decoder.parse_meld(tag) player_seat = self._normalize_position(meld.who, player_position) table.add_called_meld(player_seat, meld) if player_seat == 0: if meld.type != MeldPrint.KAN and meld.type != MeldPrint.SHOUMINKAN: table.player.draw_tile(meld.called_tile) if "<REACH" in tag and 'step="1"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_one(who_called_riichi) if "<REACH" in tag and 'step="2"' in tag: who_called_riichi = self._normalize_position( self.decoder.parse_who_called_riichi(tag), player_position) table.add_called_riichi_step_two(who_called_riichi)