1
1
import numpy as np
2
- import pygame
3
2
import pygame .locals as G
4
3
from App .Utils import Colors , normalized
5
4
from App .CSpinningTarget import CSpinningTarget
6
5
import time
7
6
import scipy .interpolate as sInterp
8
-
9
- class CAppMode :
10
- def __init__ (self , app ):
11
- self ._app = app
12
- self ._paused = True
13
- return
14
-
15
- def on_event (self , event ):
16
- if event .type == G .KEYDOWN :
17
- if event .key in [G .K_p , G .K_RETURN ]:
18
- self ._paused = not self ._paused
19
- return
20
-
21
- def on_render (self , window ):
22
- if self ._paused :
23
- self ._app .drawText ('Paused' , (55 , 55 ), Colors .RED )
24
- return
25
-
26
- def accept (self , tracked ):
27
- if self ._paused : return
28
- self ._app ._dataset .store (tracked , np .array (self ._pos ))
29
- return
30
- pass
7
+ from App .CGameMode import CGameMode
8
+ from App .CAppMode import CAppMode
31
9
32
10
class CMoveToGoal (CAppMode ):
33
11
def __init__ (self , app ):
@@ -94,16 +72,22 @@ def on_event(self, event):
94
72
return
95
73
96
74
if G .K_RIGHT == event .key :
75
+ self ._reset (clockwise = False )
76
+ self ._active = True
77
+ return
78
+
79
+ if G .K_LEFT == event .key :
80
+ self ._reset (clockwise = True )
97
81
self ._active = True
98
82
return
99
83
return
100
84
101
- def accept (self , tracked ):
85
+ def on_sample (self , tracked ):
102
86
if self ._active :
103
- super ().accept (tracked )
87
+ super ().on_sample (tracked )
104
88
return
105
89
106
- def _reset (self ):
90
+ def _reset (self , clockwise = False ):
107
91
path = np .array ([
108
92
[- 1 , 1 ],
109
93
[ 1 , 1 ],
@@ -112,7 +96,9 @@ def _reset(self):
112
96
[- 1 , 1 ],
113
97
], np .float32 )
114
98
lvl = (self ._maxLevel - self ._level ) / ((2.0 * self ._maxLevel ) + 0 )
115
- self ._pos , self ._goal , * self ._path = 0.5 + lvl * path
99
+ path = 0.5 + lvl * path
100
+ if clockwise : path = path [::- 1 ]
101
+ self ._pos , self ._goal , * self ._path = path
116
102
self ._active = False
117
103
self ._transitionStart = None
118
104
return
@@ -150,9 +136,9 @@ def on_tick(self, deltaT):
150
136
self ._startT = time .time ()
151
137
return
152
138
153
- def accept (self , tracked ):
139
+ def on_sample (self , tracked ):
154
140
if self ._active :
155
- super ().accept (tracked )
141
+ super ().on_sample (tracked )
156
142
return
157
143
158
144
def on_render (self , window ):
@@ -173,13 +159,23 @@ def __init__(self, app):
173
159
self ._pos = np .zeros ((2 , )) + 0.5
174
160
self ._target = CSpinningTarget (app )
175
161
self ._points = None
162
+ self ._scale = 1.0
176
163
self ._newSpline (extend = False )
177
164
return
165
+
166
+ def _updateScale (self ):
167
+ newScale = np .random .uniform (0.1 , 0.2 ) + self ._scale
168
+ self ._scale = newScale
169
+ if 1.0 < self ._scale : self ._scale = 0.0
170
+ return newScale
178
171
179
172
def _newSpline (self , extend = True ):
180
173
self ._T = 0.0
181
174
N = 3
182
- points = np .random .normal (size = (4 , 2 ), loc = 0.5 , scale = 0.5 )
175
+ scale = self ._updateScale ()
176
+ points = np .random .uniform (size = (N + 1 , 2 )) - 0.5
177
+ points /= np .linalg .norm (points , axis = - 1 , keepdims = True ) + 1e-6
178
+ points = 0.5 + (points * scale )
183
179
if extend :
184
180
points = np .concatenate ([self ._points [- N :], points ], axis = 0 )
185
181
@@ -189,7 +185,7 @@ def _newSpline(self, extend=True):
189
185
190
186
speed = np .random .uniform (0.15 , 1.0 , size = 1 )[0 ]
191
187
T = distance [- 1 ] / speed
192
- self ._maxT = np .clip (T , 20 , 40 )
188
+ self ._maxT = np .clip (T , N * 3 , N * 10 )
193
189
distance /= distance [- 1 ]
194
190
195
191
shift = distance [N - 1 ] if extend else 0.0
@@ -260,78 +256,7 @@ def on_event(self, event):
260
256
return
261
257
pass
262
258
#####################
263
- # TODO: find a way to collect data during the game mode and then use it to train the model
264
- # Maybe store the last 2 seconds before the hit
265
- class CGameMode :
266
- def __init__ (self , app ):
267
- self ._app = app
268
- self ._pos = np .zeros ((2 , )) + 0.5
269
- self ._T = 0.0
270
- self ._currentRadius = 0.0
271
- self ._radiusPerSecond = 0.01
272
- self ._hits = 0
273
- self ._maxHits = 3
274
-
275
- self ._totalTime = 0
276
- self ._totalHits = 0
277
- self ._totalDistance = 0
278
- return
279
-
280
- def on_tick (self , deltaT ):
281
- self ._T += deltaT
282
- T = self ._T
283
- self ._currentRadius = T * self ._radiusPerSecond
284
- return
285
-
286
- def on_render (self , window ):
287
- wh = np .array (window .get_size ())
288
- pos = tuple (np .multiply (wh , self ._pos ).astype (np .int32 ))
289
- self ._app .drawObject (pos , color = Colors .RED , R = 3 )
290
- # second circle
291
- R = np .multiply (wh , self ._currentRadius ).min ().astype (np .int32 )
292
- pygame .draw .circle (window , Colors .RED , pos , int (R ), width = 1 )
293
-
294
- # score at the top center
295
- if 0 < self ._totalHits :
296
- self ._app .drawText (
297
- 'Hits: %d, mean accuracy: %.4f, time: %.1f' % (
298
- self ._totalHits , self ._totalDistance / self ._totalHits , self ._totalTime / self ._totalHits
299
- ),
300
- pos = (wh [0 ] // 2 , 80 ),
301
- color = Colors .BLACK ,
302
- )
303
- return
304
-
305
- def on_event (self , event ):
306
- return
307
-
308
- def play (self , pos , tracked ):
309
- pos = np .array (pos ).reshape ((2 , ))
310
- # check if the click is inside the circle
311
- D = np .square (np .subtract (pos , self ._pos )).sum ()
312
- D = np .sqrt (D )
313
- if D < self ._currentRadius :
314
- self ._hit (D )
315
- return
316
-
317
- def _hit (self , D ):
318
- self ._totalHits += 1
319
- self ._totalDistance += D
320
- self ._totalTime += self ._T
321
-
322
- self ._T = 0.0
323
- self ._currentRadius = 0.0
324
-
325
- self ._hits += 1
326
- if self ._maxHits <= self ._hits :
327
- self ._pos = np .random .uniform (size = (2 , ))
328
- self ._hits = 0
329
- return
330
- pass
331
-
332
- #####################
333
259
APP_MODES = [
334
- CGameMode ,
335
260
CLookAtMode ,
336
261
CCornerMode ,
337
262
CSplineMode ,
0 commit comments