This is a stateful representation of Toybox -- since it manages memory, we provide __enter__
and __exit__
usage for Python's with-blocks:
with Toybox("amidar") as tb: print(tb.get_score()) # the 'tb' variable only lives in the block.
Important
Note how we should use this in a with-block; this will clean up pointers and prevent memory leaks.
__init__(self, game_name, grayscale=True, frameskip=0)
¶
Show source code in ctoybox/ffi.py
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | def __init__(self, game_name: str, grayscale: bool=True, frameskip: int=0): """ Construct a new Toybox state/game wrapper. Use this in a with block! Parameters: game_name: One of "breakout", "space_invaders", "amidar", etc. grayscale: Toybox can render directly to grayscale, saving time. frameskip: When an action is submitted, for how many extra frames should it be applied? """ self.game_name = game_name self.frames_per_action = frameskip+1 self.rsimulator = Simulator(game_name) self.rstate = self.rsimulator.new_game() self.grayscale = grayscale self.deleted = False self.new_game() |
Construct a new Toybox state/game wrapper. Use this in a with block!
Parameters
Name | Type | Description | Default |
---|---|---|---|
game_name |
str |
One of "breakout", "space_invaders", "amidar", etc. | required |
grayscale |
bool |
Toybox can render directly to grayscale, saving time. | True |
frameskip |
int |
When an action is submitted, for how many extra frames should it be applied? | 0 |
apply_action(self, action_input_obj)
¶
Show source code in ctoybox/ffi.py
352 353 354 355 356 357 358 359 360 361 362 363 364 | def apply_action(self, action_input_obj: Input): """Takes an [ctoybox.Input][] action and applies it - unlike the ALE actions (which allow some permutations) this allows for fine-grained button pressing. This applies the action *k* times, where *k* based on the frameskip passed to the Toybox constructor. Parameters: action_input_obj: An instance of the [ctoybox.Input][] class. """ # implement frameskip(k) by sending the action (k+1) times every time we have an action. js = json_str(action_input_obj).encode('UTF-8') js_cstr = ffi.new("char []", js) for _ in range(self.frames_per_action): lib.state_apply_action(self.rstate.get_state(), js_cstr) |
Takes an [ctoybox.Input][] action and applies it - unlike the ALE actions (which allow some permutations) this allows for fine-grained button pressing.
This applies the action k times, where k based on the frameskip passed to the Toybox constructor.
Parameters
Name | Type | Description | Default |
---|---|---|---|
action_input_obj |
Input |
An instance of the [ctoybox.Input][] class. | required |
apply_ale_action(self, action_int)
¶
Show source code in ctoybox/ffi.py
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | def apply_ale_action(self, action_int: int): """Takes an integer corresponding to an action, as specified in ALE. This applies the action *k* times, where *k* based on the frameskip passed to the Toybox constructor. ```python ALE_INPUT_MAPPING = { 0 : "NOOP", 1 : "FIRE", 2 : "UP", 3 : "RIGHT", 4 : "LEFT", 5 : "DOWN", 6 : "UPRIGHT", 7 : "UPLEFT", 8 : "DOWNRIGHT", 9 : "DOWNLEFT", 10 : "UPFIRE", 11 : "RIGHTFIRE", 12 : "LEFTFIRE", 13 : "DOWNFIRE", 14 : "UPRIGHTFIRE", 15 : "UPLEFTFIRE", 16 : "DOWNRIGHTFIRE", 17 : "DOWNLEFTFIRE" } ``` Parameters: action_int: A number from 0 to 17 inclusive. """ # implement frameskip(k) by sending the action (k+1) times every time we have an action. for _ in range(self.frames_per_action): if not lib.state_apply_ale_action(self.rstate.get_state(), action_int): raise ValueError("Expected to apply action, but failed: {0}".format(action_int)) |
Takes an integer corresponding to an action, as specified in ALE.
This applies the action k times, where k based on the frameskip passed to the Toybox constructor.
ALE_INPUT_MAPPING = { 0 : "NOOP", 1 : "FIRE", 2 : "UP", 3 : "RIGHT", 4 : "LEFT", 5 : "DOWN", 6 : "UPRIGHT", 7 : "UPLEFT", 8 : "DOWNRIGHT", 9 : "DOWNLEFT", 10 : "UPFIRE", 11 : "RIGHTFIRE", 12 : "LEFTFIRE", 13 : "DOWNFIRE", 14 : "UPRIGHTFIRE", 15 : "UPLEFTFIRE", 16 : "DOWNRIGHTFIRE", 17 : "DOWNLEFTFIRE" }
Parameters
Name | Type | Description | Default |
---|---|---|---|
action_int |
int |
A number from 0 to 17 inclusive. | required |
config_to_json(self)
¶
Show source code in ctoybox/ffi.py
439 440 441 | def config_to_json(self) -> Dict[str, Any]: """Get the state's JSON representation as a python dict.""" return self.rsimulator.to_json() |
Get the state's JSON representation as a python dict.
game_over(self)
¶
Show source code in ctoybox/ffi.py
418 419 420 421 422 423 424 425 | def game_over(self) -> bool: """ Check for game over condition. Returns: ``True`` if the player has run out of lives in the current state. """ return self.rstate.game_over() |
Check for game over condition.
Returns
Type | Description |
---|---|
bool |
True if the player has run out of lives in the current state. |
get_height(self)
¶
Show source code in ctoybox/ffi.py
298 299 300 | def get_height(self) -> int: """Get the height of the rendered game in pixels.""" return self.rsimulator.get_frame_height() |
Get the height of the rendered game in pixels.
get_legal_action_set(self)
¶
Show source code in ctoybox/ffi.py
306 307 308 309 310 311 312 313 314 | def get_legal_action_set(self) -> List[int]: """Get the set of actions consumed by this game: they are ALE numbered.""" sim = self.rsimulator.get_simulator() txt = rust_str(lib.simulator_actions(sim)) try: out = json.loads(txt) except: raise ValueError(txt) return out |
Get the set of actions consumed by this game: they are ALE numbered.
get_level(self)
¶
Show source code in ctoybox/ffi.py
410 411 412 413 414 415 416 | def get_level(self) -> int: """ Access the number of levels. Returns: The number of levels completed in the current state.""" return self.rstate.level() |
Access the number of levels.
Returns
Type | Description |
---|---|
int |
The number of levels completed in the current state. |
get_lives(self)
¶
Show source code in ctoybox/ffi.py
403 404 405 406 407 408 | def get_lives(self) -> int: """Access the number of lives. Returns: The number of lives remaining in the current state.""" return self.rstate.lives() |
Access the number of lives.
Returns
Type | Description |
---|---|
int |
The number of lives remaining in the current state. |
get_rgb_frame(self)
¶
Show source code in ctoybox/ffi.py
392 393 394 | def get_rgb_frame(self) -> np.array: """Get the RGB frame as a numpy array.""" return self.rstate.render_frame_rgb(self.rsimulator) |
Get the RGB frame as a numpy array.
get_score(self)
¶
Show source code in ctoybox/ffi.py
396 397 398 399 400 401 | def get_score(self) -> int: """Access the current score. Returns: The number of points earned in the current state.""" return self.rstate.score() |
Access the current score.
Returns
Type | Description |
---|---|
int |
The number of points earned in the current state. |
get_state(self)
¶
Show source code in ctoybox/ffi.py
366 367 368 | def get_state(self) -> np.array: """This state here actually refers to the graphical, RGBA or grayscale representation of the current state.""" return self.rstate.render_frame(self.rsimulator, self.grayscale) |
This state here actually refers to the graphical, RGBA or grayscale representation of the current state.
get_width(self)
¶
Show source code in ctoybox/ffi.py
302 303 304 | def get_width(self) -> int: """Get the width of the rendered game in pixels.""" return self.rsimulator.get_frame_width() |
Get the width of the rendered game in pixels.
new_game(self)
¶
Show source code in ctoybox/ffi.py
287 288 289 290 291 292 293 294 295 296 | def new_game(self): """ Modify this Toybox wrapper to have a new_game state. Important: This discards the old state! """ old_state = self.rstate del old_state self.rstate = self.rsimulator.new_game() |
Modify this Toybox wrapper to have a new_game state.
Important
This discards the old state!
query_state_json(self, query, args='null')
¶
Show source code in ctoybox/ffi.py
466 467 468 469 470 471 472 473 | def query_state_json(self, query: str, args: Union[Dict[str, Any], str]="null") -> Dict[str, Any]: """Submit a query to the game's query system -- faster than accessing the whole JSON for quick introspection. Parameters: query: the query string to send to the game. args: a JSON argument to attach to the query string. """ return self.rstate.query_json(query, args) |
Submit a query to the game's query system -- faster than accessing the whole JSON for quick introspection.
Parameters
Name | Type | Description | Default |
---|---|---|---|
query |
str |
the query string to send to the game. | required |
args |
Union[Dict[str, Any], str] |
a JSON argument to attach to the query string. | null |
save_frame_image(self, path, grayscale=False)
¶
Show source code in ctoybox/ffi.py
378 379 380 381 382 383 384 385 386 387 388 389 390 | def save_frame_image(self, path: str, grayscale: bool =False): """Save the current frame image to a PNG file. Parameters: path: the filename to save to. grayscale: whether images should be saved in color or black & white. """ img = None if grayscale: img = Image.fromarray(self.rstate.render_frame_grayscale(self.rsimulator), 'L') else: img = Image.fromarray(self.rstate.render_frame_color(self.rsimulator), 'RGBA') img.save(path, format='png') |
Save the current frame image to a PNG file.
Parameters
Name | Type | Description | Default |
---|---|---|---|
path |
str |
the filename to save to. | required |
grayscale |
bool |
whether images should be saved in color or black & white. | False |
schema_for_config(self)
¶
Show source code in ctoybox/ffi.py
493 494 495 | def schema_for_config(self) -> Dict[str, Any]: """Get the JSON Schema for the Config object.""" return self.rsimulator.schema_for_config() |
Get the JSON Schema for the Config object.
schema_for_state(self)
¶
Show source code in ctoybox/ffi.py
489 490 491 | def schema_for_state(self) -> Dict[str,Any]: """Get the JSON Schema for the frame State object.""" return self.rsimulator.schema_for_state() |
Get the JSON Schema for the frame State object.
set_seed(self, seed)
¶
Show source code in ctoybox/ffi.py
370 371 372 373 374 375 376 | def set_seed(self, seed: int): """Control the random number generator of the config -- only affects a new_game. Parameters: seed: a parameter to reset the built-in random number generator. """ self.rsimulator.set_seed(seed) |
Control the random number generator of the config -- only affects a new_game.
Parameters
Name | Type | Description | Default |
---|---|---|---|
seed |
int |
a parameter to reset the built-in random number generator. | required |
state_to_json(self)
¶
Show source code in ctoybox/ffi.py
427 428 429 | def state_to_json(self) -> Dict[str, Any]: """Get the state's JSON representation as a python object.""" return self.rstate.to_json() |
Get the state's JSON representation as a python object.
to_state_json(self)
¶
Show source code in ctoybox/ffi.py
431 432 433 434 435 436 437 | def to_state_json(self) -> Dict[str, Any]: """Get the state's JSON representation as a python dict. Important: This method is deprecated; please use ``state_to_json`` instead! """ return self.state_to_json() |
Get the state's JSON representation as a python dict.
Important
This method is deprecated; please use state_to_json
instead!
write_config_json(self, config_js)
¶
Show source code in ctoybox/ffi.py
453 454 455 456 457 458 459 460 461 462 463 464 | def write_config_json(self, config_js: Dict[str, Any]): """Overwrite the config's JSON representation from a python dict. It is likely that some changes will be seen until you call new_game() Parameters: config_js: the python representation of the config JSON """ # from_json replaces simulator! self.rsimulator.from_json(config_js) # new_game replaces state! self.new_game() |
Overwrite the config's JSON representation from a python dict.
It is likely that some changes will be seen until you call new_game()
Parameters
Name | Type | Description | Default |
---|---|---|---|
config_js |
Dict[str, Any] |
the python representation of the config JSON | required |
write_state_json(self, js)
¶
Show source code in ctoybox/ffi.py
443 444 445 446 447 448 449 450 451 | def write_state_json(self, js: Dict[str, Any]): """Overwrite the state's JSON representation from a python dict. Parameters: js: the python representation of the JSON state. """ old_state = self.rstate del old_state self.rstate = self.rsimulator.state_from_json(js) |
Overwrite the state's JSON representation from a python dict.
Parameters
Name | Type | Description | Default |
---|---|---|---|
js |
Dict[str, Any] |
the python representation of the JSON state. | required |