Module moog.game_rules.portal

Portal.

The entrypoint is Portal, a rule that teleports a sprite from one portal sprite position to another.

Expand source code
"""Portal.

The entrypoint is Portal, a rule that teleports a sprite from one portal sprite
position to another.
"""

from . import abstract_rule
import numpy as np


class Portal(abstract_rule.AbstractRule):
    """Makes a sprite teleport if it enters a portal sprite."""

    def __init__(self, teleporting_layer, portal_layer):
        """Constructor.

        The environment state must have an even number of sprites in
        portal_layer, because portals are paired up in order. I.e. if there are
        4 portals, the first two will teleport to each other and the second two
        will teleport to each other.

        Also, once a sprite has teleported, it cannot immediately teleport again
        until it exits the portal sprite. This is kept track of by
        self._currently_teleporting, and is necessary to prevent a sprite from
        immediately teleporting back and forth between portals.

        Args:
            teleporting_layer: String. Must be a key in the environment state.
                Sprites in this layer will be teleported from the state if their
                position enters a sprite in portal_layer.
            portal_layer: String. Must be a key in the environment state.
        """        
        self._teleporting_layer = teleporting_layer
        self._portal_layer = portal_layer

    def reset(self, state, meta_state):
        del state
        del meta_state
        self._currently_teleporting = set()

    def step(self, state, meta_state):
        """Apply rule to state.

        Teleport sprites in teleporting layer if they have entered a portal
        sprite, unless they are in self._currently_teleporting.
        """
        del meta_state

        portals = state[self._portal_layer]
        num_portals = len(portals)
        if num_portals % 2 != 0:
            raise ValueError(
                'There must be an even number of portals, but you have {} '
                'portals.'.format(num_portals))
        
        for sprite in state[self._teleporting_layer]:
            in_portals = [portal.contains_point(sprite.position)
                          for portal in portals]
            in_portal_inds = np.argwhere(in_portals)[:, 0]

            if len(in_portal_inds) == 0:
                # Sprite is not in any portal, so make sure we don't think
                # sprite is currently teleporting
                self._currently_teleporting.discard(sprite.id)
                continue

            if sprite.id in self._currently_teleporting:
                # To prevent immediately teleporting back and forth between
                # portals
                continue
            
            # Teleport the sprite
            entry_ind = in_portal_inds[0]
            exit_ind = entry_ind - 1 if entry_ind % 2 else entry_ind + 1
            sprite.position = np.copy(portals[exit_ind].position)
            self._currently_teleporting.add(sprite.id)

Classes

class Portal (teleporting_layer, portal_layer)

Makes a sprite teleport if it enters a portal sprite.

Constructor.

The environment state must have an even number of sprites in portal_layer, because portals are paired up in order. I.e. if there are 4 portals, the first two will teleport to each other and the second two will teleport to each other.

Also, once a sprite has teleported, it cannot immediately teleport again until it exits the portal sprite. This is kept track of by self._currently_teleporting, and is necessary to prevent a sprite from immediately teleporting back and forth between portals.

Args

teleporting_layer
String. Must be a key in the environment state. Sprites in this layer will be teleported from the state if their position enters a sprite in portal_layer.
portal_layer
String. Must be a key in the environment state.
Expand source code
class Portal(abstract_rule.AbstractRule):
    """Makes a sprite teleport if it enters a portal sprite."""

    def __init__(self, teleporting_layer, portal_layer):
        """Constructor.

        The environment state must have an even number of sprites in
        portal_layer, because portals are paired up in order. I.e. if there are
        4 portals, the first two will teleport to each other and the second two
        will teleport to each other.

        Also, once a sprite has teleported, it cannot immediately teleport again
        until it exits the portal sprite. This is kept track of by
        self._currently_teleporting, and is necessary to prevent a sprite from
        immediately teleporting back and forth between portals.

        Args:
            teleporting_layer: String. Must be a key in the environment state.
                Sprites in this layer will be teleported from the state if their
                position enters a sprite in portal_layer.
            portal_layer: String. Must be a key in the environment state.
        """        
        self._teleporting_layer = teleporting_layer
        self._portal_layer = portal_layer

    def reset(self, state, meta_state):
        del state
        del meta_state
        self._currently_teleporting = set()

    def step(self, state, meta_state):
        """Apply rule to state.

        Teleport sprites in teleporting layer if they have entered a portal
        sprite, unless they are in self._currently_teleporting.
        """
        del meta_state

        portals = state[self._portal_layer]
        num_portals = len(portals)
        if num_portals % 2 != 0:
            raise ValueError(
                'There must be an even number of portals, but you have {} '
                'portals.'.format(num_portals))
        
        for sprite in state[self._teleporting_layer]:
            in_portals = [portal.contains_point(sprite.position)
                          for portal in portals]
            in_portal_inds = np.argwhere(in_portals)[:, 0]

            if len(in_portal_inds) == 0:
                # Sprite is not in any portal, so make sure we don't think
                # sprite is currently teleporting
                self._currently_teleporting.discard(sprite.id)
                continue

            if sprite.id in self._currently_teleporting:
                # To prevent immediately teleporting back and forth between
                # portals
                continue
            
            # Teleport the sprite
            entry_ind = in_portal_inds[0]
            exit_ind = entry_ind - 1 if entry_ind % 2 else entry_ind + 1
            sprite.position = np.copy(portals[exit_ind].position)
            self._currently_teleporting.add(sprite.id)

Ancestors

Methods

def step(self, state, meta_state)

Apply rule to state.

Teleport sprites in teleporting layer if they have entered a portal sprite, unless they are in self._currently_teleporting.

Expand source code
def step(self, state, meta_state):
    """Apply rule to state.

    Teleport sprites in teleporting layer if they have entered a portal
    sprite, unless they are in self._currently_teleporting.
    """
    del meta_state

    portals = state[self._portal_layer]
    num_portals = len(portals)
    if num_portals % 2 != 0:
        raise ValueError(
            'There must be an even number of portals, but you have {} '
            'portals.'.format(num_portals))
    
    for sprite in state[self._teleporting_layer]:
        in_portals = [portal.contains_point(sprite.position)
                      for portal in portals]
        in_portal_inds = np.argwhere(in_portals)[:, 0]

        if len(in_portal_inds) == 0:
            # Sprite is not in any portal, so make sure we don't think
            # sprite is currently teleporting
            self._currently_teleporting.discard(sprite.id)
            continue

        if sprite.id in self._currently_teleporting:
            # To prevent immediately teleporting back and forth between
            # portals
            continue
        
        # Teleport the sprite
        entry_ind = in_portal_inds[0]
        exit_ind = entry_ind - 1 if entry_ind % 2 else entry_ind + 1
        sprite.position = np.copy(portals[exit_ind].position)
        self._currently_teleporting.add(sprite.id)

Inherited members