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.

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