Skip to content

I Ching

A Book of Changes engine with the 64-hexagram deck and the three-coin casting spread. Casting is RNG-driven: six lines form a primary hexagram and, where lines change, a relating hexagram.

from fortune_telling_core import RandomRng, ReadingRequest
from fortune_telling_core.traditions.iching import ICHING_DECK, CASTING, build_engine

request = ReadingRequest(deck_id=ICHING_DECK.id, spread_id=CASTING.id)
reading = build_engine().read(request, rng=RandomRng(seed=42))

iching

ICHING_DECK module-attribute

ICHING_DECK = Deck(
    id="iching.deck.hexagrams.v1",
    symbols=tuple(
        (
            Symbol(
                id=hexagram.symbol_id,
                name=hexagram.pinyin,
                attributes={
                    "number": str(hexagram.number),
                    "pinyin": hexagram.pinyin,
                    "english": hexagram.english,
                    "glyph": hexagram.glyph,
                    "lower_trigram": hexagram.lower,
                    "upper_trigram": hexagram.upper,
                    "binary": format(
                        hexagram.binary, "06b"
                    ),
                },
            )
        )
        for hexagram in HEXAGRAMS
    ),
)

CASTING module-attribute

CASTING = Spread(
    id="iching.spread.casting.v1",
    name="Casting",
    positions=(
        Position(
            "primary",
            "Primary",
            "The hexagram cast from the six lines.",
        ),
        Position(
            "relating",
            "Relating",
            "The hexagram after the changing lines transform.",
        ),
    ),
)

IChingEngine

Bases: AbstractEngine

I Ching engine using the three-coin casting method.

The engine casts six lines to build a primary hexagram and, by transforming the changing lines (old yin and old yang), a relating hexagram. When no line changes, the relating hexagram equals the primary.

id class-attribute instance-attribute

id = 'iching.engine'

version class-attribute instance-attribute

version = '0.1.0'

deck

deck(request: ReadingRequest) -> Deck

Return the hexagram deck for a request.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request whose deck_id must match ICHING_DECK.id.

required

Returns:

Type Description
Deck

The bundled hexagram deck.

Raises:

Type Description
ValidationError

If the request names an unsupported deck.

Source code in src/fortune_telling_core/traditions/iching/engine.py
def deck(self, request: ReadingRequest) -> Deck:
    """Return the hexagram deck for a request.

    Args:
        request: Reading request whose ``deck_id`` must match
            ``ICHING_DECK.id``.

    Returns:
        The bundled hexagram deck.

    Raises:
        ValidationError: If the request names an unsupported deck.
    """

    if request.deck_id != ICHING_DECK.id:
        raise ValidationError(f"unsupported I Ching deck: {request.deck_id}")
    return ICHING_DECK

spread

spread(request: ReadingRequest) -> Spread

Return the casting spread.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request whose spread_id must match CASTING.id.

required

Returns:

Type Description
Spread

The bundled casting spread.

Raises:

Type Description
ValidationError

If the spread is not supported.

Source code in src/fortune_telling_core/traditions/iching/engine.py
def spread(self, request: ReadingRequest) -> Spread:
    """Return the casting spread.

    Args:
        request: Reading request whose ``spread_id`` must match
            ``CASTING.id``.

    Returns:
        The bundled casting spread.

    Raises:
        ValidationError: If the spread is not supported.
    """

    if request.spread_id != CASTING.id:
        raise ValidationError(f"unsupported I Ching spread: {request.spread_id}")
    return CASTING

draw

draw(request: ReadingRequest, rng: Rng) -> Draw

Cast a hexagram for the request.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request.

required
rng Rng

Random source; eighteen floats are consumed (three coins per line).

required

Returns:

Type Description
Draw

A draw with the primary and relating hexagram selections.

Raises:

Type Description
ValidationError

If the requested deck or spread is unsupported.

ExhaustedRngError

If the supplied RNG cannot provide enough values.

Source code in src/fortune_telling_core/traditions/iching/engine.py
def draw(self, request: ReadingRequest, rng: Rng) -> Draw:
    """Cast a hexagram for the request.

    Args:
        request: Reading request.
        rng: Random source; eighteen floats are consumed (three coins per
            line).

    Returns:
        A draw with the primary and relating hexagram selections.

    Raises:
        ValidationError: If the requested deck or spread is unsupported.
        ExhaustedRngError: If the supplied RNG cannot provide enough values.
    """

    self.deck(request)
    self.spread(request)
    casting = cast(rng)
    common = _common_modifiers(casting)
    selections = (
        Selection("primary", casting.primary.symbol_id, {**common, "role": "primary"}),
        Selection("relating", casting.relating.symbol_id, {**common, "role": "relating"}),
    )
    return Draw(ICHING_DECK.id, CASTING.id, selections)

build_engine

build_engine() -> IChingEngine

Create an I Ching engine.

Returns:

Type Description
IChingEngine

A new IChingEngine instance.

Source code in src/fortune_telling_core/traditions/iching/engine.py
def build_engine() -> IChingEngine:
    """Create an I Ching engine.

    Returns:
        A new ``IChingEngine`` instance.
    """

    return IChingEngine()