Skip to content

Old Cyrillic / Church Slavonic Numerals

An Old Cyrillic numeral engine that deterministically sums the Greek-derived letter values of a Church Slavonic word (1-900). The raw total is stamped over a single structural result symbol. Historical letter-form variants (koppa/cherv for 90, ksi for 60, uk/izhitsa for 400, omega for 800) are configurable, and letters with no numeral value are rejected by default rather than dropped.

from fortune_telling_core import Querent, ReadingRequest
from fortune_telling_core.traditions.cyrillic_slavonic_numerals import (
    CYRILLIC_SLAVONIC_NUMERALS_DECK,
    CYRILLIC_SLAVONIC_NUMERALS_SPREAD,
    build_engine,
)

request = ReadingRequest(
    deck_id=CYRILLIC_SLAVONIC_NUMERALS_DECK.id,
    spread_id=CYRILLIC_SLAVONIC_NUMERALS_SPREAD.id,
    querent=Querent(id="sample", display_name="Sample", attributes={"name": "миро"}),
)
reading = build_engine().cast(request)
# м=40, и=8, р=100, о=70 -> total 218

cyrillic_slavonic_numerals

CYRILLIC_SLAVONIC_NUMERALS_DECK module-attribute

CYRILLIC_SLAVONIC_NUMERALS_DECK = Deck(
    id="cyrillic_slavonic_numerals.deck.total.v1",
    symbols=(
        Symbol(
            id=CYRILLIC_SLAVONIC_NUMERALS_RESULT_SYMBOL,
            name="Old Cyrillic Numeral Total",
            attributes={"kind": "raw_total"},
        ),
    ),
)

CYRILLIC_SLAVONIC_NUMERALS_SPREAD module-attribute

CYRILLIC_SLAVONIC_NUMERALS_SPREAD = Spread(
    id="cyrillic_slavonic_numerals.spread.name.v1",
    name="Old Cyrillic Numeral Total",
    positions=(
        Position(
            "total",
            "Total",
            "The summed Old Cyrillic numeral value.",
        ),
    ),
)

KoppaMode

Bases: StrEnum

How the value 90 is represented.

CHERV_90 class-attribute instance-attribute

CHERV_90 = 'cherv_90'

KOPPA_90 class-attribute instance-attribute

KOPPA_90 = 'koppa_90'

LetterTable

Bases: StrEnum

Supported Old Cyrillic numeral tables.

COMMON_CHURCH_SLAVONIC class-attribute instance-attribute

COMMON_CHURCH_SLAVONIC = 'common_church_slavonic'

Omega800Mode

Bases: StrEnum

Which letter forms are accepted for value 800.

OMEGA class-attribute instance-attribute

OMEGA = 'omega'

OT class-attribute instance-attribute

OT = 'ot'

BROAD_OMEGA class-attribute instance-attribute

BROAD_OMEGA = 'broad_omega'

TitloMode

Bases: StrEnum

Whether a titlo mark is required in the input.

OPTIONAL class-attribute instance-attribute

OPTIONAL = 'optional'

REQUIRED class-attribute instance-attribute

REQUIRED = 'required'

U400Mode

Bases: StrEnum

Which letter forms are accepted for value 400.

UK class-attribute instance-attribute

UK = 'uk'

IZHITSA class-attribute instance-attribute

IZHITSA = 'izhitsa'

BOTH class-attribute instance-attribute

BOTH = 'both'

UnvaluedLettersMode

Bases: StrEnum

How obsolete but unvalued letters are handled.

REJECT class-attribute instance-attribute

REJECT = 'reject'

XiMode

Bases: StrEnum

How the value 60 is represented.

KSI_60 class-attribute instance-attribute

KSI_60 = 'ksi_60'

CHERV_60 class-attribute instance-attribute

CHERV_60 = 'cherv_60'

CyrillicSlavonicNumeralsEngine

Bases: AbstractEngine

Old Cyrillic / Church Slavonic numeral engine.

id class-attribute instance-attribute

id = 'cyrillic_slavonic_numerals.engine'

version class-attribute instance-attribute

version = '0.1.0'

deck

deck(request: ReadingRequest) -> Deck

Return the Old Cyrillic numerals deck.

Source code in src/fortune_telling_core/traditions/cyrillic_slavonic_numerals/engine.py
def deck(self, request: ReadingRequest) -> Deck:
    """Return the Old Cyrillic numerals deck."""

    if request.deck_id != CYRILLIC_SLAVONIC_NUMERALS_DECK.id:
        raise ValidationError(f"unsupported Old Cyrillic deck: {request.deck_id}")
    return CYRILLIC_SLAVONIC_NUMERALS_DECK

spread

spread(request: ReadingRequest) -> Spread

Return the Old Cyrillic numerals spread.

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

    if request.spread_id != CYRILLIC_SLAVONIC_NUMERALS_SPREAD.id:
        raise ValidationError(f"unsupported Old Cyrillic spread: {request.spread_id}")
    return CYRILLIC_SLAVONIC_NUMERALS_SPREAD

draw

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

Compute the Old Cyrillic total as a deterministic draw.

Source code in src/fortune_telling_core/traditions/cyrillic_slavonic_numerals/engine.py
def draw(self, request: ReadingRequest, rng: Rng) -> Draw:
    """Compute the Old Cyrillic total as a deterministic draw."""

    del rng
    fields = collect_values(request)
    name = require_string(fields, "name")
    letter_table = _parse(fields.get("letter_table"), LetterTable.COMMON_CHURCH_SLAVONIC)
    koppa_mode = _parse(fields.get("koppa_mode"), KoppaMode.CHERV_90)
    xi_mode = _parse(fields.get("xi_mode"), XiMode.KSI_60)
    u_400_mode = _parse(fields.get("u_400_mode"), U400Mode.UK)
    omega_800_mode = _parse(fields.get("omega_800_mode"), Omega800Mode.OMEGA)
    unvalued_letters = _parse(fields.get("unvalued_letters"), UnvaluedLettersMode.REJECT)
    titlo = _parse(fields.get("titlo"), TitloMode.OPTIONAL)

    units = cyrillic_slavonic_numerals.values(
        name,
        letter_table=letter_table,
        koppa_mode=koppa_mode,
        xi_mode=xi_mode,
        u_400_mode=u_400_mode,
        omega_800_mode=omega_800_mode,
        unvalued_letters=unvalued_letters,
        titlo=titlo,
    )
    if not units:
        raise ValidationError("name must contain at least one Old Cyrillic numeral letter")
    total = cyrillic_slavonic_numerals.total(units)

    selection = Selection(
        "total",
        CYRILLIC_SLAVONIC_NUMERALS_RESULT_SYMBOL,
        {
            "value": str(total),
            "total": str(total),
            "value_system": cyrillic_slavonic_numerals.ID,
            "value_system_version": cyrillic_slavonic_numerals.VERSION,
            "letter_table": letter_table.value,
            "koppa_mode": koppa_mode.value,
            "xi_mode": xi_mode.value,
            "u_400_mode": u_400_mode.value,
            "omega_800_mode": omega_800_mode.value,
            "unvalued_letters": unvalued_letters.value,
            "titlo": titlo.value,
            "normalized_name": "".join(unit.char for unit in units),
            "values": format_value_trace(units),
        },
    )
    return Draw(
        CYRILLIC_SLAVONIC_NUMERALS_DECK.id,
        CYRILLIC_SLAVONIC_NUMERALS_SPREAD.id,
        (selection,),
    )

cast

cast(request: ReadingRequest) -> Reading

Compute an Old Cyrillic numerals reading without a caller RNG.

Source code in src/fortune_telling_core/traditions/cyrillic_slavonic_numerals/engine.py
def cast(self, request: ReadingRequest) -> Reading:
    """Compute an Old Cyrillic numerals reading without a caller RNG."""

    draw = self.draw(request, _NULL_RNG)
    return self._interpret(request, draw, rng=None)

build_engine

build_engine() -> CyrillicSlavonicNumeralsEngine

Create an Old Cyrillic / Church Slavonic numeral engine.

Source code in src/fortune_telling_core/traditions/cyrillic_slavonic_numerals/engine.py
def build_engine() -> CyrillicSlavonicNumeralsEngine:
    """Create an Old Cyrillic / Church Slavonic numeral engine."""

    return CyrillicSlavonicNumeralsEngine()