Skip to content

base_generator

Module: terminaltexteffects.utils.spanningtree.base_generator

Base spanning tree generator.

SpanningTreeGenerator

Bases: ABC

Abstract base class for spanning-tree and graph-traversal generators.

Source code in terminaltexteffects/utils/spanningtree/base_generator.py
class SpanningTreeGenerator(ABC):
    """Abstract base class for spanning-tree and graph-traversal generators."""

    def __init__(self, terminal: Terminal) -> None:
        """Initialize the tree generator.

        Args:
            terminal (Terminal): TTE terminal used as the source of characters,
                neighbor relationships, and text-boundary checks.

        """
        self.terminal = terminal

    def get_neighbors(
        self,
        character: EffectCharacter,
        *,
        unlinked_only: bool = True,
        limit_to_text_boundary: bool = False,
    ) -> list[EffectCharacter]:
        """Get the neighbors for a given character and apply filters.

        Args:
            character (EffectCharacter): Subject character.
            unlinked_only (bool, optional): If True, filter out any neighbors with
                links. If False, include both linked and unlinked neighbors.
                Defaults to True.
            limit_to_text_boundary (bool, optional): If True, filter out neighbors outside the text boundary.
                Defaults to False.

        Returns:
            list[EffectCharacter]: List of EffectCharacter neighbors.

        """
        neighbors = [neighbor for neighbor in character.neighbors.values() if neighbor]
        if limit_to_text_boundary:
            neighbors = [
                neighbor for neighbor in neighbors if self.terminal.canvas.coord_is_in_text(neighbor.input_coord)
            ]
        if unlinked_only:
            neighbors = [neighbor for neighbor in neighbors if not neighbor.links]
        return neighbors

    @staticmethod
    def _require_unlinked(character: EffectCharacter) -> None:
        """Reject character state left by an earlier tree-generation run."""
        if character.links:
            msg = f"Cannot generate a spanning tree from pre-linked character {character!r}."
            raise ValueError(msg)

    def _get_unvisited_neighbors(
        self,
        character: EffectCharacter,
        visited_chars: set[EffectCharacter],
        *,
        limit_to_text_boundary: bool = False,
    ) -> list[EffectCharacter]:
        """Return eligible neighbors using generator-owned visitation state.

        Raises:
            ValueError: An unvisited neighbor contains links from an earlier tree-generation run.

        """
        unvisited_neighbors: list[EffectCharacter] = []
        for neighbor in self.get_neighbors(
            character,
            unlinked_only=False,
            limit_to_text_boundary=limit_to_text_boundary,
        ):
            if neighbor in visited_chars:
                continue
            self._require_unlinked(neighbor)
            unvisited_neighbors.append(neighbor)
        return unvisited_neighbors

    @abstractmethod
    def step(self) -> None:
        """Progress the algorithm by one step."""

__init__(terminal)

Initialize the tree generator.

Parameters:

Name Type Description Default
terminal Terminal

TTE terminal used as the source of characters, neighbor relationships, and text-boundary checks.

required
Source code in terminaltexteffects/utils/spanningtree/base_generator.py
def __init__(self, terminal: Terminal) -> None:
    """Initialize the tree generator.

    Args:
        terminal (Terminal): TTE terminal used as the source of characters,
            neighbor relationships, and text-boundary checks.

    """
    self.terminal = terminal

get_neighbors(character, *, unlinked_only=True, limit_to_text_boundary=False)

Get the neighbors for a given character and apply filters.

Parameters:

Name Type Description Default
character EffectCharacter

Subject character.

required
unlinked_only bool

If True, filter out any neighbors with links. If False, include both linked and unlinked neighbors. Defaults to True.

True
limit_to_text_boundary bool

If True, filter out neighbors outside the text boundary. Defaults to False.

False

Returns:

Type Description
list[EffectCharacter]

list[EffectCharacter]: List of EffectCharacter neighbors.

Source code in terminaltexteffects/utils/spanningtree/base_generator.py
def get_neighbors(
    self,
    character: EffectCharacter,
    *,
    unlinked_only: bool = True,
    limit_to_text_boundary: bool = False,
) -> list[EffectCharacter]:
    """Get the neighbors for a given character and apply filters.

    Args:
        character (EffectCharacter): Subject character.
        unlinked_only (bool, optional): If True, filter out any neighbors with
            links. If False, include both linked and unlinked neighbors.
            Defaults to True.
        limit_to_text_boundary (bool, optional): If True, filter out neighbors outside the text boundary.
            Defaults to False.

    Returns:
        list[EffectCharacter]: List of EffectCharacter neighbors.

    """
    neighbors = [neighbor for neighbor in character.neighbors.values() if neighbor]
    if limit_to_text_boundary:
        neighbors = [
            neighbor for neighbor in neighbors if self.terminal.canvas.coord_is_in_text(neighbor.input_coord)
        ]
    if unlinked_only:
        neighbors = [neighbor for neighbor in neighbors if not neighbor.links]
    return neighbors

step() abstractmethod

Progress the algorithm by one step.

Source code in terminaltexteffects/utils/spanningtree/base_generator.py
@abstractmethod
def step(self) -> None:
    """Progress the algorithm by one step."""