def test_parse_players(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="0"/> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <RYUUKYOKU owari="0,0,0,0,0,0,0,0" /> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['game_type'], MahjongConstants.FOUR_PLAYERS) self.assertEqual(len(results['players']), 4) self.assertEqual(results['players'][0]['name'], 'NoName1') self.assertEqual(results['players'][1]['name'], 'NoName2') self.assertEqual(results['players'][2]['name'], 'NoName3') self.assertEqual(results['players'][3]['name'], 'NoName4') self.assertEqual(results['players'][0]['rate'], 1564.57) self.assertEqual(results['players'][1]['rate'], 1470.35) self.assertEqual(results['players'][2]['rate'], 1238.80) self.assertEqual(results['players'][3]['rate'], 1520.41) self.assertEqual(results['players'][0]['rank'], 2) self.assertEqual(results['players'][1]['rank'], 3) self.assertEqual(results['players'][2]['rank'], 10) self.assertEqual(results['players'][3]['rank'], 1)
def test_fix_double_ron_wrong_parsing(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%64%61%6B%65%31%6D%6A" n1="%68%75%73%6B%61%72" n2="%D0%B7%D0%B0%D1%87%D0%B5%D0%BC" n3="%E3%81%A1%E3%82%85%E3%82%93%E3%81%9F" dan="14,14,14,14" rate="1987.69,1871.62,1866.08,1920.37" sx="M,M,M,M"/> <INIT seed="6,0,0,0,2,14" ten="292,285,253,170" oya="2" hai0="80,114,117,16,130,25,42,71,54,97,27,119,32" hai1="33,15,41,38,46,31,78,83,82,96,52,51,7" hai2="4,72,93,131,66,61,109,26,53,57,18,17,73" hai3="35,107,100,24,81,84,34,56,40,90,79,118,43"/> <AGARI ba="0,1" hai="50,54,59,112,114" m="19471,14375,45067" machi="50" ten="30,3900,0" yaku="12,1,52,1,54,1" doraHai="14" who="0" fromWho="3" sc="292,49,285,0,243,0,170,-39" /> <AGARI ba="0,0" hai="4,8,12,17,18,19,50,53,57,61,66,69,72,73" machi="50" ten="40,12000,1" yaku="1,1,52,3,53,0" doraHai="14" doraHaiUra="132" who="2" fromWho="3" sc="341,0,285,0,243,120,131,-120" owari="1,2,3,4,5,6,7,8" ten="0,1,2" /> </mjloggm> """) results = TenhouLogParser().parse_log('2021030410gm-0029-0000-7530e444', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][0]['han'], 3) self.assertEqual(player['rounds'][0]['fu'], 30) self.assertEqual(player['rounds'][0]['win_scores'], 4900) player = next((i for i in results['players'] if i['seat'] == 2), None) self.assertEqual(player['rounds'][0]['han'], 4) self.assertEqual(player['rounds'][0]['fu'], 40) self.assertEqual(player['rounds'][0]['win_scores'], 12000) player = next((i for i in results['players'] if i['seat'] == 3), None) self.assertEqual(player['rounds'][0]['is_win'], False) self.assertEqual(player['rounds'][0]['han'], 4) self.assertEqual(player['rounds'][0]['fu'], 40) self.assertEqual(player['rounds'][0]['lose_scores'], 12000)
def test_parse_final_scores_and_end_of_the_round_with_retake(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="0"/> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <RYUUKYOKU ba="0,2" sc="214,-15,236,15,191,15,339,-15" hai1="13,19,22,50,52,54,57,62,97,100,104,128,131" hai2="5,7,9,11,12,15,45,46,58,59,93,94,102" owari="382,49.0,362,16.0,104,-40.0,152,-25.0" /> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(len(results['players']), 4) self.assertEqual(results['players'][0]['seat'], 0) self.assertEqual(results['players'][0]['name'], 'NoName1') self.assertEqual(results['players'][0]['position'], 1) self.assertEqual(results['players'][0]['scores'], 38200) self.assertEqual(results['players'][1]['seat'], 1) self.assertEqual(results['players'][1]['name'], 'NoName2') self.assertEqual(results['players'][1]['position'], 2) self.assertEqual(results['players'][1]['scores'], 36200) self.assertEqual(results['players'][2]['seat'], 3) self.assertEqual(results['players'][2]['name'], 'NoName4') self.assertEqual(results['players'][2]['position'], 3) self.assertEqual(results['players'][2]['scores'], 15200) self.assertEqual(results['players'][3]['seat'], 2) self.assertEqual(results['players'][3]['name'], 'NoName3') self.assertEqual(results['players'][3]['position'], 4) self.assertEqual(results['players'][3]['scores'], 10400)
def test_rounds_and_call_riichi(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <INIT seed="1,0"/> <REACH who="0" step="1"/><D47/><REACH who="0" ten="255,216,261,258" step="2"/> <AGARI who="2" fromWho="1" ten="0,1,2"/> <INIT seed="1,0"/> <T76/><D123/><U125/><REACH who="0" step="1"/><D47/> <AGARI who="2" fromWho="1" owari="1,2,3,4,5,6,7,8" ten="0,1,2"/> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][0]['is_riichi'], True) self.assertEqual(player['rounds'][1]['is_riichi'], True) player = next((i for i in results['players'] if i['seat'] == 1), None) self.assertEqual(player['rounds'][0]['is_riichi'], False) self.assertEqual(player['rounds'][1]['is_riichi'], False) player = next((i for i in results['players'] if i['seat'] == 2), None) self.assertEqual(player['rounds'][0]['is_riichi'], False) self.assertEqual(player['rounds'][1]['is_riichi'], False) player = next((i for i in results['players'] if i['seat'] == 3), None) self.assertEqual(player['rounds'][0]['is_riichi'], False) self.assertEqual(player['rounds'][1]['is_riichi'], False)
def test_rounds_and_honba(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <INIT seed="0,0"/> <T76/><D123/><U125/> <AGARI who="0" fromWho="1" ten="0,1,2" /> <INIT seed="0,1"/> <T76/><D123/><U125/> <AGARI who="0" fromWho="1" ten="0,1,2" /> <INIT seed="1,0"/> <T76/><D123/><U125/> <AGARI who="2" fromWho="1" owari="1,2,3,4,5,6,7,8" ten="0,1,2"/> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][0]['round_number'], 0) self.assertEqual(player['rounds'][0]['honba'], 0) self.assertEqual(player['rounds'][1]['round_number'], 0) self.assertEqual(player['rounds'][1]['honba'], 1) self.assertEqual(player['rounds'][2]['round_number'], 1) self.assertEqual(player['rounds'][2]['honba'], 0)
def test_rounds_and_retake(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <INIT seed="1,0"/> <T76/><D123/><U125/> <AGARI who="0" fromWho="0" ten="0,1,2" /> <INIT seed="1,0"/> <T76/><D123/><U125/> <RYUUKYOKU type="yao9" ba="0,0" sc="433,0,266,0,250,0,51,0" hai3="14,20,32,36,38,65,66,68,106,109,114,121,126,132" owari="1,2,3,4,5,6,7,8"/> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][1]['is_deal'], False) self.assertEqual(player['rounds'][1]['is_retake'], True) player = next((i for i in results['players'] if i['seat'] == 1), None) self.assertEqual(player['rounds'][1]['is_deal'], False) self.assertEqual(player['rounds'][1]['is_retake'], True) player = next((i for i in results['players'] if i['seat'] == 2), None) self.assertEqual(player['rounds'][1]['is_deal'], False) self.assertEqual(player['rounds'][1]['is_retake'], True) player = next((i for i in results['players'] if i['seat'] == 3), None) self.assertEqual(player['rounds'][1]['is_deal'], False) self.assertEqual(player['rounds'][1]['is_retake'], True)
def test_rounds_and_open_hand_and_closed_kan(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <INIT seed="1,0"/> <T76/><D123/><U125/><N who="0" m="33280" /><DORA hai="21"/> <AGARI who="2" fromWho="1" ten="0,1,2"/> <INIT seed="1,0"/> <T76/><D123/><U125/><N who="1" m="51314" /><T76/><DORA hai="21"/> <AGARI who="2" fromWho="1" owari="1,2,3,4,5,6,7,8" ten="0,1,2"/> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][0]['is_open_hand'], False) self.assertEqual(player['rounds'][1]['is_open_hand'], False) player = next((i for i in results['players'] if i['seat'] == 1), None) self.assertEqual(player['rounds'][0]['is_open_hand'], False) self.assertEqual(player['rounds'][1]['is_open_hand'], True)
def test_rounds_and_tsumo(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <INIT seed="1,0"/> <T76/><D123/><U125/> <AGARI who="0" fromWho="0" owari="1,2,3,4,5,6,7,8" ten="30,2000,0" sc="157,20,245,-5,376,-10,222,-5"/> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) player = next((i for i in results['players'] if i['seat'] == 0), None) self.assertEqual(player['rounds'][0]['is_win'], True) self.assertEqual(player['rounds'][0]['win_scores'], 2000) self.assertEqual(player['rounds'][0]['is_deal'], False) self.assertEqual(player['rounds'][0]['is_tsumo'], True) self.assertEqual(player['rounds'][0]['is_retake'], False) player = next((i for i in results['players'] if i['seat'] == 1), None) self.assertEqual(player['rounds'][0]['is_deal'], False) self.assertEqual(player['rounds'][0]['lose_scores'], 500) player = next((i for i in results['players'] if i['seat'] == 2), None) self.assertEqual(player['rounds'][0]['is_deal'], False) self.assertEqual(player['rounds'][0]['lose_scores'], 1000) player = next((i for i in results['players'] if i['seat'] == 3), None) self.assertEqual(player['rounds'][0]['is_deal'], False) self.assertEqual(player['rounds'][0]['lose_scores'], 500)
def test_parse_final_scores(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="0"/> <UN n0="%4E%6F%4E%61%6D%65%31" n1="%4E%6F%4E%61%6D%65%32" n2="%4E%6F%4E%61%6D%65%33" n3="%4E%6F%4E%61%6D%65%34" dan="2,3,10,1" rate="1564.57,1470.35,1238.80,1520.41" sx="M,M,M,M"/> <AGARI ba="1,3" hai="5,7,11,13,17,44,50,53,95,97,101" m="43019" machi="44" ten="30,3900,0" yaku="15,1,11,1,52,1" doraHai="9" who="0" fromWho="3" sc="310,72,362,0,104,0,194,-42" owari="382,49.0,362,16.0,104,-40.0,152,-25.0" /> </mjloggm> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(len(results['players']), 4) self.assertEqual(results['players'][0]['seat'], 0) self.assertEqual(results['players'][0]['name'], 'NoName1') self.assertEqual(results['players'][0]['position'], 1) self.assertEqual(results['players'][0]['scores'], 38200) self.assertEqual(results['players'][1]['seat'], 1) self.assertEqual(results['players'][1]['name'], 'NoName2') self.assertEqual(results['players'][1]['position'], 2) self.assertEqual(results['players'][1]['scores'], 36200) self.assertEqual(results['players'][2]['seat'], 3) self.assertEqual(results['players'][2]['name'], 'NoName4') self.assertEqual(results['players'][2]['position'], 3) self.assertEqual(results['players'][2]['scores'], 15200) self.assertEqual(results['players'][3]['seat'], 2) self.assertEqual(results['players'][3]['name'], 'NoName3') self.assertEqual(results['players'][3]['position'], 4) self.assertEqual(results['players'][3]['scores'], 10400)
def test_parse_lobby(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="0"/> <RYUUKYOKU owari="0,0,0,0" /> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['lobby'], 0) data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="1111"/> <RYUUKYOKU owari="0,0,0,0" /> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['lobby'], 1111)
def test_parse_game_type(self): data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="9" lobby="0"/> <RYUUKYOKU owari="0,0,0,0" /> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['game_rule'], MahjongConstants.HANCHAN_TANYAO_RED_FIVES) data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="25" lobby="0"/> <RYUUKYOKU owari="0,0,0,0" /> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['game_rule'], MahjongConstants.HANCHAN_TANYAO_RED_FIVES) data = self._prepare_data(""" <mjloggm ver="2.3"> <GO type="1" lobby="0"/> <RYUUKYOKU owari="0,0,0,0" /> """) results = TenhouLogParser().parse_log('2016051813gm-0001-0000-d455c767', data) self.assertEqual(results['game_rule'], MahjongConstants.TONPUSEN_TANYAO_RED_FIVES)
def _load_log_and_update_game(game, sent_new_rank_message=True): results = TenhouLogParser().parse_log(game.external_id, game.game_log_content) player_data = next((i for i in results["players"] if i["name"] == game.player.username), None) if not player_data: return JsonResponse({"success": False, "reason": 4}), None previous_game = ( Game.objects.filter(player=game.player).filter(status=Game.FINISHED).exclude(id=game.id).first() ) game.status = Game.FINISHED game.player_position = player_data["position"] game.scores = player_data["scores"] game.seat = player_data["seat"] game.rate = player_data["rate"] game.rank = player_data["rank"] game.game_rule = results["game_rule"] game.game_type = results["game_type"] game.game_date = results["game_date"] game.lobby = results["lobby"] game.game_room = results["game_room"] game.game_log_content = results["log_data"] game.save() if settings.TELEGRAM_TOKEN and previous_game and game.rank != previous_game.rank and sent_new_rank_message: send_telegram_new_rank_message( previous_game.get_rank_display(), game.get_rank_display(), game.rate, Game.objects.filter(status=Game.FINISHED, player=game.player).count(), Game.objects.filter(status=Game.FINISHED, player=game.player) .all() .aggregate(Avg("player_position"))["player_position__avg"], ) rounds = [] for i, round_data in enumerate(player_data["rounds"]): rounds.append( GameRound( game=game, is_win=round_data["is_win"], is_deal=round_data["is_deal"], is_retake=round_data["is_retake"], is_tsumo=round_data["is_tsumo"], is_riichi=round_data["is_riichi"], is_open_hand=round_data["is_open_hand"], is_damaten=round_data["is_damaten"], round_number=round_data["round_number"], honba=round_data["honba"], win_scores=round_data["win_scores"], lose_scores=round_data["lose_scores"], han=round_data.get("han", 0), fu=round_data.get("fu", 0), round_counter=i, ) ) GameRound.objects.bulk_create(rounds) if settings.TELEGRAM_TOKEN: try: send_telegram_finished_game_message(game, rounds) except Exception as e: print(e) return JsonResponse({"success": True}), player_data
def test_parse_game_date(self): results = TenhouLogParser().parse_log(log_id='2016051813gm-0001-0000-d455c767') self.assertEqual(results['game_date'], datetime.datetime(2016, 5, 18, 13, 0, tzinfo=timezone.utc))