22from entities .game .field import Field
33from entities .data .vision import FrameData , RobotData , BallData
44from entities .data .referee import RefereeData
5+ from entities .game .game_object import Ball , Colour , GameObject , Robot
56from entities .game .team_info import TeamInfo
67from entities .referee .referee_command import RefereeCommand
78from entities .referee .stage import Stage
8- from enum import Enum
9- from entities .game .game_object import Ball , Colour , GameObject , Robot
109
1110
1211class 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