-
Notifications
You must be signed in to change notification settings - Fork 0
/
shot_parser.py
173 lines (136 loc) · 5.3 KB
/
shot_parser.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from shot import Shot
import re
import png
MAP_WIDTH = 1024
MAP_HEIGHT = 768
SHOT_MARKER_RADIUS = 10
def get_category(pixel):
categories = {
"tee": [255, 50, 255],
"fairway": [0, 130, 0],
"rough": [0, 50, 0],
"sand": [255, 255, 0],
"green": [0, 255, 0],
"other": [255, 255, 255],
"pinestraw": [141, 83, 0]
}
for c in categories:
if abs(pixel[0] - categories[c][0]) + \
abs(pixel[1] - categories[c][1]) + \
abs(pixel[2] - categories[c][2]) == 0:
return c
return "unknown"
def get_shots_from_inner_html(inner_html, hole, categorize=False):
shots = {}
# Now let's get our info
# Find the hole par
r = re.search(
"<div class=\"parTxt\">Par<span id=\"holePar\" class=\"data holePar\">(\\d+)</span></div>",
inner_html)
if r:
par = int(r.group(1))
else:
print("Failed to find par")
print(inner_html)
# Find the hole length
r = re.search(
"<div class=\"yardTxt\">YDS<span id=\"holeYds\" class=\"data holeYds\">(\\d+)</span></div>",
inner_html)
if r:
hole_length = r.group(1) + " yards"
# Find the canvas dimensions
r = re.search(
"<canvas id=\"shotCanvas\\d+\" width=\"(\\d+)\" height=\"(\\d+)\" class=\"type1\">",
inner_html)
if r:
canvas_width = int(r.group(1))
canvas_height = int(r.group(2))
r = re.search("<div class=\"details\">\n.*?<div class=\"name\">(.+?)</div>", inner_html)
if r:
player = r.group(1)
else:
print("Couldn't find player")
# Remove some beginning and trailing garbage
inner_html = inner_html.split("<div class=\"tracker\"", 1)[1]
inner_html = inner_html.split("overlay error-message", 1)[0]
inner_html = inner_html.split(r"data-shot=", 1)[1]
# Find all the coordinates
for stuff in re.compile("marker(?: plus| hidden)? shot").split(inner_html):
r = re.search("\\d+", stuff)
if not r:
continue
shot = r.group(0)
if shot not in shots:
shots[shot] = Shot()
r = re.search("style=\"left: (\\d+)px; top: (\\d+)px", stuff)
if r:
shots[shot].x = int(MAP_WIDTH * (int(r.group(1)) + SHOT_MARKER_RADIUS) / canvas_width)
shots[shot].y = int(MAP_HEIGHT * (int(r.group(2)) + SHOT_MARKER_RADIUS) / canvas_height)
# Find all the distances
for stuff in inner_html.split("data-shot="):
r = re.search("\\d+", stuff)
if not r:
continue
shot = r.group(0)
if shot not in shots:
shots[shot] = Shot()
shots[shot].shot = int(shot)
shots[shot].hole = hole
shots[shot].par = par
shots[shot].player = player
# Find distance in yards, feet or inches
r = re.search(
"<div class=\"distance\">.*?<span>(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].shot_length = r.group(1) + " yards"
r = re.search(
"<div class=\"distance\">.*?<span class=\"feet\">(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].shot_length = r.group(1) + " feet"
r = re.search(
"<div class=\"distance\">.*?<span class=\"inch\">(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].shot_length = r.group(1) + " inches"
# Find distance to pin in yards, feet or inches
r = re.search(
"<div class=\"topin\">.*?<span>(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].distance_after = r.group(1) + " yards"
r = re.search(
"<div class=\"topin\">.*?<span class=\"feet\">(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].distance_after = r.group(1) + " feet"
r = re.search(
"<div class=\"topin\">.*?<span class=\"inch\">(\\d+)</span>.*?</div>", stuff)
if r:
shots[shot].distance_after = r.group(1) + " inches"
r = re.search(
"<div class=\"distance penalty\"><span class=\"penalty\">Penalty</span></div>", stuff)
if r:
shots[shot].type = "penalty"
else:
shots[shot].type = "normal"
# Turn dictionary into ordered list of shots
shots = [shots[shot] for shot in sorted(shots, key=int)]
# Set distance before:
shots[0].distance_before = hole_length
# Link up previous distances for other shots
for i in range(1, len(shots)):
shots[i].distance_before = shots[i-1].distance_after
if categorize:
# Read in the map
reader = png.Reader(filename="maps/H%02dW.png" % (hole))
w, _, pixels, metadata = reader.read_flat()
pixel_byte_width = 4 if metadata['alpha'] else 3
# Categorise the positions of the shots based on the map
for shot in shots:
pixel_position = shot.x + shot.y * w
pixel = pixels[pixel_position *
pixel_byte_width: (pixel_position + 1) * pixel_byte_width]
shot.category_after = get_category(pixel)
shots[0].category_before = "tee"
shots[len(shots) - 1].category_after = "hole"
# Link up previous category for other shots
for i in range(1, len(shots)):
shots[i].category_before = shots[i-1].category_after
return shots