Skip to content

Commit 05bd7f6

Browse files
committed
Change RefereeCommand and Stage to enum class
1 parent 6542f73 commit 05bd7f6

File tree

6 files changed

+173
-167
lines changed

6 files changed

+173
-167
lines changed

entities/game/game.py

Lines changed: 74 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
from entities.game.field import Field
33
from entities.data.vision import FrameData, RobotData, BallData
44
from entities.data.referee import RefereeData
5+
from entities.game.game_object import Ball, Colour, GameObject, Robot
56
from entities.game.team_info import TeamInfo
67
from entities.referee.referee_command import RefereeCommand
78
from entities.referee.stage import Stage
8-
from enum import Enum
9-
from entities.game.game_object import Ball, Colour, GameObject, Robot
109

1110

1211
class Game:
@@ -21,28 +20,6 @@ def __init__(self):
2120
self._records = []
2221
self._referee_records: List[RefereeData] = []
2322

24-
def add_new_state(self, frame_data: FrameData) -> None:
25-
if isinstance(frame_data, FrameData):
26-
self._records.append(frame_data)
27-
else:
28-
raise ValueError("Invalid frame data.")
29-
30-
def get_robots_pos(self, is_yellow: bool) -> List[RobotData]:
31-
if not self._records:
32-
return None
33-
record = self._records[-1]
34-
return record.yellow_robots if is_yellow else record.blue_robots
35-
36-
def get_ball_pos(self) -> BallData:
37-
if not self._records:
38-
return None
39-
return self._records[-1].ball
40-
41-
def get_latest_frame(self) -> FrameData:
42-
if not self._records:
43-
return None
44-
return self._records[-1]
45-
4623
@property
4724
def field(self) -> Field:
4825
return self._field
@@ -53,8 +30,6 @@ def current_state(self) -> FrameData:
5330

5431
@property
5532
def records(self) -> list[FrameData]:
56-
if not self._records:
57-
return None
5833
return self._records
5934

6035
@property
@@ -89,7 +64,6 @@ def get_robots_pos(self, is_yellow: bool) -> List[RobotData]:
8964
record = self._records[-1] # TODO: unsafe, it can be empty list
9065
return record.yellow_robots if is_yellow else record.blue_robots
9166

92-
@property
9367
def source_identifier(self) -> Optional[str]:
9468
"""Get the source identifier."""
9569
if self._referee_records:
@@ -198,94 +172,91 @@ def current_action_time_remaining(self) -> Optional[int]:
198172
return self._referee_records[-1].current_action_time_remaining
199173
return None
200174

175+
@property
201176
def is_halt(self) -> bool:
202177
"""Check if the command is HALT."""
203-
return self.referee_data_handler.last_command == RefereeCommand.HALT
178+
return self.last_command == RefereeCommand.HALT
204179

180+
@property
205181
def is_stop(self) -> bool:
206182
"""Check if the command is STOP."""
207-
return self.referee_data_handler.last_command == RefereeCommand.STOP
183+
return self.last_command == RefereeCommand.STOP
208184

185+
@property
209186
def is_normal_start(self) -> bool:
210187
"""Check if the command is NORMAL_START."""
211-
return self.referee_data_handler.last_command == RefereeCommand.NORMAL_START
188+
return self.last_command == RefereeCommand.NORMAL_START
212189

190+
@property
213191
def is_force_start(self) -> bool:
214192
"""Check if the command is FORCE_START."""
215-
return self.referee_data_handler.last_command == RefereeCommand.FORCE_START
193+
return self.last_command == RefereeCommand.FORCE_START
216194

195+
@property
217196
def is_prepare_kickoff_yellow(self) -> bool:
218197
"""Check if the command is PREPARE_KICKOFF_YELLOW."""
219-
return (
220-
self.referee_data_handler.last_command
221-
== RefereeCommand.PREPARE_KICKOFF_YELLOW
222-
)
198+
return self.last_command == RefereeCommand.PREPARE_KICKOFF_YELLOW
223199

200+
@property
224201
def is_prepare_kickoff_blue(self) -> bool:
225202
"""Check if the command is PREPARE_KICKOFF_BLUE."""
226-
return (
227-
self.referee_data_handler.last_command
228-
== RefereeCommand.PREPARE_KICKOFF_BLUE
229-
)
203+
return self.last_command == RefereeCommand.PREPARE_KICKOFF_BLUE
230204

205+
@property
231206
def is_prepare_penalty_yellow(self) -> bool:
232207
"""Check if the command is PREPARE_PENALTY_YELLOW."""
233-
return (
234-
self.referee_data_handler.last_command
235-
== RefereeCommand.PREPARE_PENALTY_YELLOW
236-
)
208+
return self.last_command == RefereeCommand.PREPARE_PENALTY_YELLOW
237209

210+
@property
238211
def is_prepare_penalty_blue(self) -> bool:
239212
"""Check if the command is PREPARE_PENALTY_BLUE."""
240-
return (
241-
self.referee_data_handler.last_command
242-
== RefereeCommand.PREPARE_PENALTY_BLUE
243-
)
213+
return self.last_command == RefereeCommand.PREPARE_PENALTY_BLUE
244214

215+
@property
245216
def is_direct_free_yellow(self) -> bool:
246217
"""Check if the command is DIRECT_FREE_YELLOW."""
247-
return (
248-
self.referee_data_handler.last_command == RefereeCommand.DIRECT_FREE_YELLOW
249-
)
218+
return self.last_command == RefereeCommand.DIRECT_FREE_YELLOW
250219

220+
@property
251221
def is_direct_free_blue(self) -> bool:
252222
"""Check if the command is DIRECT_FREE_BLUE."""
253-
return self.referee_data_handler.last_command == RefereeCommand.DIRECT_FREE_BLUE
223+
return self.last_command == RefereeCommand.DIRECT_FREE_BLUE
254224

225+
@property
255226
def is_timeout_yellow(self) -> bool:
256227
"""Check if the command is TIMEOUT_YELLOW."""
257-
return self.referee_data_handler.last_command == RefereeCommand.TIMEOUT_YELLOW
228+
return self.last_command == RefereeCommand.TIMEOUT_YELLOW
258229

230+
@property
259231
def is_timeout_blue(self) -> bool:
260232
"""Check if the command is TIMEOUT_BLUE."""
261-
return self.referee_data_handler.last_command == RefereeCommand.TIMEOUT_BLUE
233+
return self.last_command == RefereeCommand.TIMEOUT_BLUE
262234

235+
@property
263236
def is_ball_placement_yellow(self) -> bool:
264237
"""Check if the command is BALL_PLACEMENT_YELLOW."""
265-
return (
266-
self.referee_data_handler.last_command
267-
== RefereeCommand.BALL_PLACEMENT_YELLOW
268-
)
238+
return self.last_command == RefereeCommand.BALL_PLACEMENT_YELLOW
269239

240+
@property
270241
def is_ball_placement_blue(self) -> bool:
271242
"""Check if the command is BALL_PLACEMENT_BLUE."""
272-
return (
273-
self.referee_data_handler.last_command == RefereeCommand.BALL_PLACEMENT_BLUE
274-
)
243+
return self.last_command == RefereeCommand.BALL_PLACEMENT_BLUE
275244

276245
def get_object_velocity(self, object: GameObject):
277246
return self._get_object_velocity_at_frame(len(self._records) - 1, object)
278247

279248
def _get_object_position_at_frame(self, frame: int, object: GameObject):
280249
if object == Ball:
281-
return self._records[frame].ball[0] # TODO don't always take first ball pos
250+
return self._records[frame].ball[0] # TODO don't always take first ball pos
282251
elif isinstance(object, Robot):
283252
if object.colour == Colour.YELLOW:
284253
return self._records[frame].yellow_robots[object.id]
285254
else:
286255
return self._records[frame].blue_robots[object.id]
287256

288-
def _get_object_velocity_at_frame(self, frame: int, object: GameObject) -> Optional[tuple]:
257+
def _get_object_velocity_at_frame(
258+
self, frame: int, object: GameObject
259+
) -> Optional[tuple]:
289260
"""
290261
Calculates the object's velocity based on position changes over time,
291262
at frame f.
@@ -298,28 +269,28 @@ def _get_object_velocity_at_frame(self, frame: int, object: GameObject) -> Optio
298269
# Cannot provide velocity at frame that does not exist
299270
print(frame)
300271
return None
301-
272+
302273
# Otherwise get the previous and current frames
303274
previous_frame = self._records[frame - 1]
304275
current_frame = self._records[frame]
305-
276+
306277
previous_pos = self._get_object_position_at_frame(frame - 1, object)
307278
current_pos = self._get_object_position_at_frame(frame, object)
308279

309280
previous_time_received = previous_frame.ts
310281
time_received = current_frame.ts
311282

312-
# Latest frame should always be ahead of last one
283+
# Latest frame should always be ahead of last one
313284
if time_received < previous_time_received:
314285
# TODO log a warning
315286
print("Timestamps out of order for vision data ")
316-
return None
317-
287+
return None
288+
318289
dt_secs = time_received - previous_time_received
319-
290+
320291
vx = (current_pos.x - previous_pos.x) / dt_secs
321292
vy = (current_pos.y - previous_pos.y) / dt_secs
322-
293+
323294
return (vx, vy)
324295

325296
def get_object_acceleration(self, object: GameObject) -> Optional[tuple]:
@@ -328,82 +299,92 @@ def get_object_acceleration(self, object: GameObject) -> Optional[tuple]:
328299
WINDOW = 5
329300
N_WINDOWS = 6
330301
iter = 0
331-
302+
332303
if len(self._records) < WINDOW * N_WINDOWS + 1:
333304
return None
334-
305+
335306
for i in range(N_WINDOWS):
336307
averageVelocity = [0, 0]
337308
windowStart = 1 + i * WINDOW
338-
windowEnd = windowStart + WINDOW # Excluded
309+
windowEnd = windowStart + WINDOW # Excluded
339310
windowMiddle = (windowStart + windowEnd) // 2
340311

341312
for j in range(windowStart, windowEnd):
342-
curr_vel = self._get_object_velocity_at_frame(len(self._records) - j, object)
313+
curr_vel = self._get_object_velocity_at_frame(
314+
len(self._records) - j, object
315+
)
343316
averageVelocity[0] += curr_vel[0]
344317
averageVelocity[1] += curr_vel[1]
345-
318+
346319
averageVelocity[0] /= WINDOW
347320
averageVelocity[1] /= WINDOW
348321

349322
if i != 0:
350-
dt = self._records[-windowMiddle + WINDOW].ts - self._records[- windowMiddle].ts
351-
accX = (futureAverageVelocity[0] - averageVelocity[0]) / dt # TODO vec
323+
dt = (
324+
self._records[-windowMiddle + WINDOW].ts
325+
- self._records[-windowMiddle].ts
326+
)
327+
accX = (futureAverageVelocity[0] - averageVelocity[0]) / dt # TODO vec
352328
accY = (futureAverageVelocity[1] - averageVelocity[1]) / dt
353329
totalX += accX
354330
totalY += accY
355-
iter += 1
331+
iter += 1
356332

357333
futureAverageVelocity = tuple(averageVelocity)
358-
359-
334+
360335
return (totalX / iter, totalY / iter)
361336

362337
def predict_object_pos_after(self, t: float, object: GameObject) -> Optional[tuple]:
363338
# If t is after the object has stopped we return the position at which object stopped.
364-
339+
365340
acc = self.get_object_acceleration(object)
366-
341+
367342
if acc is None:
368343
return None
369-
344+
370345
ax, ay = acc
371346
ux, uy = self.get_object_velocity(object)
372347

373-
374348
if object is Ball:
375349
ball = self.get_ball_pos()
376350
start_x, start_y = ball[0].x, ball[0].y
377351
else:
378352
posn = self._get_object_position_at_frame(len(self._records) - 1, object)
379353
start_x, start_y = posn.x, posn.y
380354

381-
if ax == 0: # Due to friction, if acc = 0 then stopped.
382-
sx = 0 # TODO: Not sure what to do about robots with respect to friction - we never know if they are slowing down to stop or if they are slowing down to change direction
355+
if ax == 0: # Due to friction, if acc = 0 then stopped.
356+
sx = 0 # TODO: Not sure what to do about robots with respect to friction - we never know if they are slowing down to stop or if they are slowing down to change direction
383357
else:
384-
tx_stop = - ux / ax
358+
tx_stop = -ux / ax
385359
tx = min(t, tx_stop)
386360
sx = ux * tx + 0.5 * ax * tx * tx
387361

388362
if ay == 0:
389363
sy = 0
390364
else:
391-
ty_stop = - uy / ay
365+
ty_stop = -uy / ay
392366
ty = min(t, ty_stop)
393367
sy = uy * ty + 0.5 * ay * ty * ty
394368

395-
return (start_x + sx, start_y + sy) # TODO: Doesn't take into account spin / angular vel
396-
369+
return (
370+
start_x + sx,
371+
start_y + sy,
372+
) # TODO: Doesn't take into account spin / angular vel
373+
397374
def predict_frame_after(self, t: float):
398-
yellow_pos = [self.predict_object_pos_after(t, Robot(Colour.YELLOW, i)) for i in range(6)]
399-
blue_pos = [self.predict_object_pos_after(t, Robot(Colour.BLUE, i)) for i in range(6)]
375+
yellow_pos = [
376+
self.predict_object_pos_after(t, Robot(Colour.YELLOW, i)) for i in range(6)
377+
]
378+
blue_pos = [
379+
self.predict_object_pos_after(t, Robot(Colour.BLUE, i)) for i in range(6)
380+
]
400381
ball_pos = self.predict_object_pos_after(t, Ball)
401382
if ball_pos is None or None in yellow_pos or None in blue_pos:
402383
return None
403384
else:
404385
return FrameData(
405386
self._records[-1].ts + t,
406-
list(map(lambda pos: RobotData(pos[0], pos[1], 0), yellow_pos)),
387+
list(map(lambda pos: RobotData(pos[0], pos[1], 0), yellow_pos)),
407388
list(map(lambda pos: RobotData(pos[0], pos[1], 0), blue_pos)),
408-
[BallData(ball_pos[0], ball_pos[1], 0)] # TODO : Support z axis
389+
[BallData(ball_pos[0], ball_pos[1], 0)], # TODO : Support z axis
409390
)

0 commit comments

Comments
 (0)