forked from ApplySci/phoenix-logs
/
dora_dragon.py
137 lines (114 loc) · 5.59 KB
/
dora_dragon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from log_counter import LogCounter
from log_seat_and_placement import LogSeatAndPlacement
from analysis_utils import convertTile, GetPlacements, CheckSeat, convertHai, getTilesFromCall, GetNextRealTag, GetRoundNameWithoutRepeats
from shanten import calculateMinimumShanten
import math
dragons = [35, 36, 37]
dora_indication = [
6, 2, 3, 4, 5, 6, 7, 8, 9, 1,
16,12,13,14,15,16,17,18,19,11,
26,22,23,24,25,26,27,28,29,21,
30,32,33,34,31,36,37,35
]
discard_tags = ["D", "E", "F", "G"]
draw_tags = ["T", "U", "V", "W"]
class DoraDragon(LogCounter, LogSeatAndPlacement):
def __init__(self):
LogCounter.__init__(self)
LogSeatAndPlacement.__init__(self)
def ParseLog(self, log, log_id):
starts = log.findall("INIT")
ends = [ x for x in log.xpath("//*[self::AGARI or self::RYUUKYOKU]") if not CheckDoubleRon(x) ]
for i in range(len(starts)):
if ends[i].tag == "RYUUKYOKU":
continue
dora_ind = convertTile(ends[i].attrib["doraHai"].split(",")[0])
if dora_ind not in dragons:
continue
self.Count("Rounds With Dragon Dora")
self.Count("Dora Dragon In %s" % GetRoundNameWithoutRepeats(starts[i]))
dora = dora_indication[dora_ind]
hands = []
for h in range(4):
hands.append(convertHai(starts[i].attrib["hai%d" % h]))
element = starts[i].getnext()
discards = 0
last_shanten_logged = [-1, -1, -1, -1]
is_in_riichi = [False, False, False, False]
while element is not None:
if element.tag == "INIT":
self.Count("Dora Dragon Never Discarded")
break
first_character = element.tag[0]
if first_character in draw_tags:
tile = element.tag[1:]
try:
draw = convertTile(tile)
who = draw_tags.index(first_character)
hands[who][draw] += 1
except ValueError:
element = element.getnext()
continue
elif first_character in discard_tags:
tile = element.tag[1:]
try:
discard = convertTile(tile)
except ValueError:
element = element.getnext()
continue
discards += 1
who = discard_tags.index(first_character)
if discard == dora:
dealer = int(starts[i].attrib["oya"])
placements = GetPlacements(starts[i].attrib["ten"], dealer)
turn = math.ceil(discards / 4)
self.Count("Discarded On Turn %d While Riichi %s" % (turn, is_in_riichi[who]))
self.Count("Round Discarded %s" % GetRoundNameWithoutRepeats(starts[i]))
self.CountBySeatAndPlacement("First To Discard Dora Dragon", CheckSeat(who, dealer), placements[who])
shanten = calculateMinimumShanten(hands[who])
self.Count("Discarded At %d-Shanten" % shanten)
next_element = GetNextRealTag(element)
if next_element.tag == "N":
self.Count("Called On Turn %d" % turn)
caller = next_element.attrib["who"]
if ends[i].attrib["who"] == caller:
self.Count("Ended Up Winning After Turn %d Call" % turn)
if next_element.tag == "AGARI":
self.Count("Dealt in on Turn %d" % turn)
break
else:
hands[who][discard] -= 1
if hands[who][dora] == 1:
shanten = calculateMinimumShanten(hands[who], last_shanten_logged[who] - 1)
if last_shanten_logged[who] == -1 or shanten < last_shanten_logged[who]:
self.Count("Lone Dora Dragon Kept At %d-Shanten" % shanten)
last_shanten_logged[who] = shanten
elif first_character == "N":
tiles = getTilesFromCall(element.attrib["m"])
tiles_count = len(tiles)
who = int(element.attrib["who"])
if tiles_count == 1:
hands[who][tiles[0]] -= 1
elif tiles_count == 3:
hands[who][tiles[1]] -= 1
hands[who][tiles[2]] -= 1
# hack to make shanten accurate
hands[who][31] += 3
else:
hands[who][tiles[0]] = 0
# hack to make shanten accurate
hands[who][31] += 3
elif element.tag == "REACH" and element.attrib["step"] == "2":
who = int(element.attrib["who"])
is_in_riichi[who] = True
element = element.getnext()
def GetName(self):
return "Dora Dragon Event"
def PrintResults(self):
LogCounter.PrintResults(self)
LogSeatAndPlacement.PrintResults(self)
def CheckDoubleRon(element):
next_element = element.getnext()
if next_element is not None and next_element.tag == "AGARI":
return True
return False