Skip to content

Prims Simple

Module: terminaltexteffects.utils.spanningtree.algo.primssimple

Simplified Prims minimum spanning tree algorithm.

A simplified Prims algorithm uses an equal weight for all links.

The algorithm starts from a chosen starting character (or a random one from the terminal) and grows by randomly linking to an unlinked neighbor.

When a neighbor is linked, the neighbor is checked for unlinked neighbors. If it has unlinked neighbors, it is considered an edge. On each step, a random edge is chosen and the process repeats.

PrimsSimple

Bases: SpanningTreeGenerator

Prims simplified minimum spanning tree algorithm.

Attributes:

Name Type Description
char_last_linked EffectCharacter | None

Character linked into the tree on the last step. None, if no character was linked during the last step.

char_link_order list[EffectCharacter]

Characters in linked order.

edge_chars list[EffectCharacter]

Characters considered edges.

edge_last_added EffectCharacter | None

Character added to the edge list on the last step. None, if no character was added during the last step.

edge_last_popped EffectCharacter | None

Character popped off the edge list on the last step. None if no character was popped during the last step.

complete bool

Whether the algorithm is complete.

Source code in terminaltexteffects/utils/spanningtree/algo/primssimple.py
class PrimsSimple(SpanningTreeGenerator):
    """Prims simplified minimum spanning tree algorithm.

    Attributes:
        char_last_linked (EffectCharacter | None): Character linked into the tree on the
            last step. None, if no character was linked during the last step.
        char_link_order (list[EffectCharacter]): Characters in linked order.
        edge_chars (list[EffectCharacter]): Characters considered edges.
        edge_last_added (EffectCharacter | None): Character added to the edge list on the
            last step. None, if no character was added during the last step.
        edge_last_popped (EffectCharacter | None): Character popped off the edge list on the
            last step. None if no character was popped during the last step.
        complete (bool): Whether the algorithm is complete.

    """

    def __init__(
        self,
        terminal: Terminal,
        starting_char: EffectCharacter | None = None,
        *,
        limit_to_text_boundary: bool = False,
    ) -> None:
        """Initialize the algorithm.

        Args:
            terminal (Terminal): TTE Terminal.
            starting_char (EffectCharacter | None, optional): Starting EffectCharacter. Defaults to None.
            limit_to_text_boundary (bool, optional): If True, the graph will not link to neighbors outside the text
                boundary.

        """
        super().__init__(terminal)
        starting_char = starting_char or terminal.get_character_by_input_coord(
            terminal.canvas.random_coord(within_text_boundary=limit_to_text_boundary),
        )
        if starting_char is None:
            msg = "Unable to find a starting character."
            raise ValueError(msg)
        self.limit_to_text_boundary = limit_to_text_boundary
        self._current_char = starting_char
        self.char_last_linked: EffectCharacter | None = self._current_char
        self.char_link_order: list[EffectCharacter] = [self._current_char]
        self.edge_chars = [self._current_char]
        self.edge_last_added: EffectCharacter | None = self._current_char
        self.edge_last_popped: EffectCharacter | None = None
        self.complete = False

    def step(self) -> None:
        """Perform a single step of the algorithm."""
        if self.edge_chars:
            self._current_char = self.edge_chars.pop(random.randrange(len(self.edge_chars)))
            self.edge_last_popped = self._current_char
            unlinked_neighbors = self.get_neighbors(
                self._current_char,
                limit_to_text_boundary=self.limit_to_text_boundary,
            )

            if unlinked_neighbors:
                next_char = unlinked_neighbors.pop(random.randrange(len(unlinked_neighbors)))
                self._current_char._link(next_char)
                self.char_link_order.append(next_char)
                self.char_last_linked = next_char
                if unlinked_neighbors:
                    self.edge_chars.append(self._current_char)
                unlinked_neighbors = [
                    neighbor for neighbor in next_char.neighbors.values() if neighbor and not neighbor.links
                ]
                if unlinked_neighbors:
                    self.edge_chars.append(next_char)
                    self.edge_last_added = next_char
        else:
            self.complete = True

__init__(terminal, starting_char=None, *, limit_to_text_boundary=False)

Initialize the algorithm.

Parameters:

Name Type Description Default
terminal Terminal

TTE Terminal.

required
starting_char EffectCharacter | None

Starting EffectCharacter. Defaults to None.

None
limit_to_text_boundary bool

If True, the graph will not link to neighbors outside the text boundary.

False
Source code in terminaltexteffects/utils/spanningtree/algo/primssimple.py
def __init__(
    self,
    terminal: Terminal,
    starting_char: EffectCharacter | None = None,
    *,
    limit_to_text_boundary: bool = False,
) -> None:
    """Initialize the algorithm.

    Args:
        terminal (Terminal): TTE Terminal.
        starting_char (EffectCharacter | None, optional): Starting EffectCharacter. Defaults to None.
        limit_to_text_boundary (bool, optional): If True, the graph will not link to neighbors outside the text
            boundary.

    """
    super().__init__(terminal)
    starting_char = starting_char or terminal.get_character_by_input_coord(
        terminal.canvas.random_coord(within_text_boundary=limit_to_text_boundary),
    )
    if starting_char is None:
        msg = "Unable to find a starting character."
        raise ValueError(msg)
    self.limit_to_text_boundary = limit_to_text_boundary
    self._current_char = starting_char
    self.char_last_linked: EffectCharacter | None = self._current_char
    self.char_link_order: list[EffectCharacter] = [self._current_char]
    self.edge_chars = [self._current_char]
    self.edge_last_added: EffectCharacter | None = self._current_char
    self.edge_last_popped: EffectCharacter | None = None
    self.complete = False

step()

Perform a single step of the algorithm.

Source code in terminaltexteffects/utils/spanningtree/algo/primssimple.py
def step(self) -> None:
    """Perform a single step of the algorithm."""
    if self.edge_chars:
        self._current_char = self.edge_chars.pop(random.randrange(len(self.edge_chars)))
        self.edge_last_popped = self._current_char
        unlinked_neighbors = self.get_neighbors(
            self._current_char,
            limit_to_text_boundary=self.limit_to_text_boundary,
        )

        if unlinked_neighbors:
            next_char = unlinked_neighbors.pop(random.randrange(len(unlinked_neighbors)))
            self._current_char._link(next_char)
            self.char_link_order.append(next_char)
            self.char_last_linked = next_char
            if unlinked_neighbors:
                self.edge_chars.append(self._current_char)
            unlinked_neighbors = [
                neighbor for neighbor in next_char.neighbors.values() if neighbor and not neighbor.links
            ]
            if unlinked_neighbors:
                self.edge_chars.append(next_char)
                self.edge_last_added = next_char
    else:
        self.complete = True