4
4
import numpy as np
5
5
from itertools import tee
6
6
import itertools
7
- import os
7
+ from pathlib import Path
8
8
9
9
try :
10
10
from tkinter import Tk , Canvas
@@ -57,24 +57,24 @@ class Pinball(Domain):
57
57
"""
58
58
59
59
#: default location of config files shipped with rlpy
60
- default_config_dir = os .path .join (__rlpy_location__ , "domains" , "PinballConfigs" )
60
+ DEFAULT_CONFIG_DIR = Path (__rlpy_location__ ).joinpath ("domains/PinballConfigs" )
61
+
62
+ @classmethod
63
+ def default_cfg (cls , name = "pinball_simple_single.json" ):
64
+ return cls .DEFAULT_CONFIG_DIR .joinpath (name )
61
65
62
66
def __init__ (
63
67
self ,
64
68
noise = 0.1 ,
65
69
episode_cap = 1000 ,
66
- configuration = os . path . join ( default_config_dir , "pinball_simple_single.cfg " ),
70
+ config_file = DEFAULT_CONFIG_DIR . joinpath ( "pinball_simple_single.json " ),
67
71
):
68
72
"""
69
- configuration:
70
- location of the configuration file
71
- episode_cap:
72
- maximum length of an episode
73
- noise:
74
- with probability noise, a uniformly random action is executed
73
+ :param config_file: Location of the configuration file.
74
+ :param episode_cap: Maximum length of an episode
75
+ :param noise: With probability noise, a uniformly random action is executed
75
76
"""
76
77
self .NOISE = noise
77
- self .configuration = configuration
78
78
self .screen = None
79
79
self .actions = [
80
80
PinballModel .ACC_X ,
@@ -91,14 +91,12 @@ def __init__(
91
91
continuous_dims = [4 ],
92
92
episode_cap = episode_cap ,
93
93
)
94
- self .environment = PinballModel (
95
- self .configuration , random_state = self .random_state
96
- )
94
+ self .environment = PinballModel (config_file , random_state = self .random_state )
97
95
98
96
def show_domain (self , a ):
99
97
if self .screen is None :
100
98
master = Tk ()
101
- master .title ("RLPY Pinball" )
99
+ master .title ("RLPy Pinball" )
102
100
self .screen = Canvas (master , width = 500.0 , height = 500.0 )
103
101
self .screen .configure (background = "LightGray" )
104
102
self .screen .pack ()
@@ -149,7 +147,7 @@ def is_terminal(self):
149
147
return self .environment .episode_ended ()
150
148
151
149
152
- class BallModel ( object ) :
150
+ class BallModel :
153
151
154
152
""" This class maintains the state of the ball
155
153
in the pinball domain. It takes care of moving
@@ -202,7 +200,7 @@ def _clip(self, val, low=-2, high=2):
202
200
return val
203
201
204
202
205
- class PinballObstacle ( object ) :
203
+ class PinballObstacle :
206
204
207
205
""" This class represents a single polygon obstacle in the
208
206
pinball domain and detects when a :class:`BallModel` hits it.
@@ -216,7 +214,7 @@ def __init__(self, points):
216
214
:param points: A list of points defining the polygon
217
215
:type points: list of lists
218
216
"""
219
- self .points = points
217
+ self .points = np . array ( points )
220
218
self .min_x = min (self .points , key = lambda pt : pt [0 ])[0 ]
221
219
self .max_x = max (self .points , key = lambda pt : pt [0 ])[0 ]
222
220
self .min_y = min (self .points , key = lambda pt : pt [1 ])[1 ]
@@ -375,7 +373,7 @@ def _intercept_edge(self, pt_pair, ball):
375
373
return False
376
374
377
375
378
- class PinballModel ( object ) :
376
+ class PinballModel :
379
377
380
378
""" This class is a self-contained model of the pinball
381
379
domain for reinforcement learning.
@@ -395,13 +393,8 @@ class PinballModel(object):
395
393
THRUST_PENALTY = - 5
396
394
END_EPISODE = 10000
397
395
398
- def __init__ (self , configuration , random_state = np . random . RandomState () ):
396
+ def __init__ (self , config_file , random_state ):
399
397
""" Read a configuration file for Pinball and draw the domain to screen
400
-
401
- :param configuration: a configuration file containing the polygons,
402
- source(s) and target location.
403
- :type configuration: str
404
-
405
398
"""
406
399
407
400
self .random_state = random_state
@@ -412,33 +405,23 @@ def __init__(self, configuration, random_state=np.random.RandomState()):
412
405
self .DEC_Y : (0 , - 1 ),
413
406
self .ACC_NONE : (0 , 0 ),
414
407
}
408
+ import json
415
409
416
410
# Set up the environment according to the configuration
417
- self .obstacles = []
418
- self .target_pos = []
419
- self .target_rad = 0.01
420
-
421
- ball_rad = 0.01
422
- start_pos = []
423
- with open (configuration ) as fp :
424
- for line in fp .readlines ():
425
- tokens = line .strip ().split ()
426
- if not len (tokens ):
427
- continue
428
- elif tokens [0 ] == "polygon" :
429
- self .obstacles .append (
430
- PinballObstacle (list (zip (* [iter (map (float , tokens [1 :]))] * 2 )))
431
- )
432
- elif tokens [0 ] == "target" :
433
- self .target_pos = [float (tokens [1 ]), float (tokens [2 ])]
434
- self .target_rad = float (tokens [3 ])
435
- elif tokens [0 ] == "start" :
436
- start_pos = list (zip (* [iter (map (float , tokens [1 :]))] * 2 ))
437
- elif tokens [0 ] == "ball" :
438
- ball_rad = float (tokens [1 ])
411
+ with config_file .open () as f :
412
+ config = json .load (f )
413
+ try :
414
+ self .obstacles = list (map (PinballObstacle , config ["obstacles" ]))
415
+ self .target_pos = config ["target_pos" ]
416
+ self .target_rad = config ["target_rad" ]
417
+ start_pos = config ["start_pos" ]
418
+ ball_rad = config ["ball_rad" ]
419
+ except KeyError as e :
420
+ raise KeyError (f"Pinball config doesn't have a key: { e } " )
421
+
439
422
self .start_pos = start_pos [0 ]
440
- a = self .random_state .randint (len (start_pos ))
441
- self .ball = BallModel (list (start_pos [a ]), ball_rad )
423
+ start_idx = self .random_state .randint (len (start_pos ))
424
+ self .ball = BallModel (list (start_pos [start_idx ]), ball_rad )
442
425
443
426
def get_state (self ):
444
427
""" Access the current 4-dimensional state vector
@@ -520,7 +503,7 @@ def _check_bounds(self):
520
503
self .ball .position [1 ] = 0.05
521
504
522
505
523
- class PinballView ( object ) :
506
+ class PinballView :
524
507
525
508
""" This class displays a :class:`PinballModel`
526
509
@@ -592,14 +575,13 @@ def blit(self):
592
575
593
576
def run_pinballview (width , height , configuration ):
594
577
"""
595
-
596
- Changed from original Pierre-Luc Bacon implementation to reflect
597
- the visualization changes in the PinballView Class.
598
-
578
+ Changed from original Pierre-Luc Bacon implementation to reflect
579
+ the visualization changes in the PinballView Class.
599
580
"""
581
+
600
582
width , height = float (width ), float (height )
601
583
master = Tk ()
602
- master .title ("RLPY Pinball" )
584
+ master .title ("RLPy Pinball" )
603
585
screen = Canvas (master , width = 500.0 , height = 500.0 )
604
586
screen .configure (background = "LightGray" )
605
587
screen .pack ()
0 commit comments