import json


# Decoder: haha, what you find is actually an enumerator;
#   which also digs some content from it's math space *decoded*
#   for the rest of us, the normal readers: some basic math becomes
#   almost a black box entity.

# IOTA E systems start to infer
#   They build a compatible block you can show for integrated numbers.
#   This includes some critical transition states and animation keyframing.

# We use logexp-native number systeming, which is actually a mathematical
# transistion through laegna states, by very basic modelling. This is not
# linear counting model, but rather linearly indexed logexp model; you
# build machines on first-order atoms of logic and functionality, which
# in turn, uses linear models of counting and repetition, expressed easily
# in terms of some kind of counting; easiest models count in complex numbers,
# where i only resonates with slightly negative number, zero divided by
# infinity where new set of angles appears rather through *phasing of one-
# dimensional system*, than two dimensionality of base-reliance math; then
# we see space models are linearly introduced through continued phasing,
# utilizing that each separate dimension has special coding into same
# number system, which is effect of quadratic metalinearization: one where
# internal and external Hilbert space, form a single moment of linear
# properties in their lifetime: as any such first-level entity, it's instantly
# catched by our math, and equal decider - base of number system is four, not
# even four point 1 or five; altought both four point 1 and five are trivial
# and linear on basis of four; just to their another base-4 representation.
# They are also uniquely comparable measured in their own units, but sooner
# or later you find - you use base 4 for operations if you use -, +, / and *
# which is almost inevitable. You use + and -, even "not" (False) or
# "no-not" (True) for advanced numbers, which is multiplier of 2 and not
# 5, as you would expect from mapping expects for simplistic symmetries
# we have, but into decimal system. We want to count exponents, but not
# in terms of exponential expansion, such as using square matrices for
# basic principles of math and logic or physics and musical oscillations.

# Model:
# 1. Apply Laegna System as given in Sheep Counter; the ordinal-level Laegna display of it's most primitive and compliant number
#    form, also easy for imagination of any number system described in Laegna texts; rather domain-based simplifications of order.
#    For example, zero in multiplication and division means number has no width at all, while 3 has width 3; in slices, zero has
#    length 2 with plus and minus - -0.(9) followed by -0.(0)1 and +0.(0)1, to be complete for any transistion and order, where one
#    infinitesimal is added to limit, but degree higher space, and the result is divided by infinity because of inwards-growth of
#    still fractal; in third sense zero is the center point, -1 and +1 being the numbers one unit above and below; three together
#    take space of 2 units; as well -2 to -0, or +2 to +0 takes space of 2 units: -2 to 2 takes space of 2 units + 1 infinitesimal,
#    and we remain very open for this effect. Sheep Counter is kind of universal - the number system used is resistant for any such
#    difference in 3 mentioned modes, where I prefer to count Oi, Oo, Oa, Oe as [-1, -0.75, -0.5, -0.25, -0] - these points create
#    four laegna numbers, small digits, inside the last number: [-1, -0] is the whole number slice, representing "O"; now where
#    "A" represents [0, 1], the very first counted number - you see in counted dimension, this would be a single entity, from 0 to 1;
#    because of resolution of discrete space. But adding small letter digits will divide it by range again - now, each time, the
#    last square; number complexity is the one which can be encoded: if O (2) digits are used before, and o (2) digits after comma
#    or dot, where "Oi" is "O,i" or "O.i" similar to "0,7" or "0.7" in estonian or english. Oi means in area of O, take the lowest
#    digit. Ai, Ao, Aa, Ae transform to Ai=+0.00 to 0.25; Ao=+0.25 to 0.50; Aa=+0.50 to +0.75; Ae=+0.75 to +1.0. We express this
#    necessarily in point list to express it simply, so it's [+0, +0.25, +0.50, +0.75, +1.0]. +0 is metaphor or ideal when used
#    alone: using 2 digits for each would vaguely represent in decimal system that we want them to be 1/4 precise. We can see how
#    4+1 points marks 4 numbers, but we can be careful with one thing: [0.00+<=>.25-; .25+<=>.50+; .50+<=>.75-; .75+<=>1.0-]. If
#    we count infinitesimals, we necessarily need to clarify the points, which are always *between two numbers by middle condition*.

# 2. Convert this mode, used for universal counting or sheep counting, into another mode, which is clear for advanced Laegna conditioning:
#
#    > EEEE becomes the *highest* number in octave compliant projection; for any R it's the higher bound of it's box.
#    > IIII becomes the *lowest* number in each R=x bounding box of base_4 4^x elements, or base_2 2^x elements, where we add some additional
#    >   elements to the bounding box, we need to take account at this step; for any number system we could imagine to invent: in any particular
#    >   case, discrete projections to number systems can be defined by your own axioms, properties and relations to your real-world events.
#    > EEEE and IIII compability is what we already had.
#    >   OOOO and AAAA compability is the future.
#
#    > OOOO becomes the middle element for signed number for each range, first of higher half, and there we currently have OAAA as last element.
#    > AAAA becomes the second middle element, last of second half.
#    > Subsequently, AOOO is then the lowest element of AUUU probability (last 3 digits are unknowns in simple Laegna expression, where "U" is base-2,
#    > or kind of "metaphysical" for this digit, all it's properties symmetrically: in logic, we simply do not do operation for such digit, but
#    > then it grows in complexity for normal math - we use simple counting for trivial programs, as in sheep counter, and for example we can use
#    > it to count things in our bag; more advanced use for sheep counter - we can imagine, what happens with sub-one, small-letter digits or
#    > fractionals; advanced laegna still asks this - we can use those digits not from start of single "dot", but as possible scape for each number,
#    > but we metaphysically crawl inside: AaAa can be very sensitive frequency in regards to precise values of AA digits - they are A^2, A*A, in
#    > density; making non-octave numbers as multipliers, such as primes 7 and 13, creates advanced number math and maps to real-world problem complexities
#    > rather than their solutions; one which is unified into design "broken" parts on head page - with an explanation text why it's not *bug*);

#    > To introduce fluent Laegna behaviour, tolerance to logecs (logical) values, which can be number axes: Laegna number becomes inheretly two-dimensional,
#    > because harmony is achieved with yin and yang, heaven or hell, heaven or earth, earth or hell - well it's ZXY relations in my terms of current,
#    > higher or lower space in terms of measurement of each life, how other modes scale to it's mode - binary, based on 7, based on 33, roughly answers
#    > some christian, muslim or buddhist cosmologies which necessarily scale to octaves and not classic frequencies, which form coordinates *inside*
#    > and *closely harmonic* in their scope; close harmonics creates distance - or rather I say destance to form this kind of "connectivity" involved in
#    > positive aspect of this word; but they are separate: being another object or subject, even gender if we have some eternal connections rotating
#    > in our worlds, between men and women (to just mix spiritual and material paradigms roughly: what is the eternal connection, the "twin flame"? it can
#    > often break in materials and matters, clarifications and confusions if you think this: sometimes, the metaphysical reality is just shifting, and
#    > we *reproject* our ideal man or woman - or better yet, the *average ideal*, something vaguely resembling actually born into these realms; and here
#    > each eternal dimension necessarily moves in every material condition; what is the past, the future and the current state - many metaphysical dimensions,
#    > for example t(15) and s(12, 4), lets say time is linear and space is 2D, but in this simple system: "t(15)&s(12,4)=>{ourownlogicblock}", where this
#    > condition of this time [i.e. metaphysical "time"] or another time [i.e. metaphysical "future" or the "past"]); metaphysically, we see long chain of
#    > futures, a worm eating it's tail, where each future has one element less. Before each element is one "now" in a que, some practical now for you in
#    > some future moment - but then there is "Now", and it's the complete, present set of each "Now"; then "Past+Now+Future=>Eternity^2", a set where
#    > projection of now, past and future, in their right order, are each, from eternal time, seen as aspects of metaphysical entity of "Now", the inner
#    > "nows" in projections of the fractal - or just this layer, each entity is a timeline, but with new center. "Center", now, is a projection which would
#    > look like each center from each side.
#
#    > But this applies in some classical logic: if p_1, p_2, p_3 are elements; P is set of these elements: but if you ask for these three elements, P *is*
#    > any of them; but if it is not any of these elements, P for such element is not equal to itself - where exeption might be added to another view if P
#    > is equal to also partial set, worth one element, or simply set of it's elements - if P is certain layer representing single elements, we might not
#    > need this complexity; it arrives with some projects of exponentiation, such as p_3 being 8 times more efficient, despite still the same, as p_1:
#    > universality creates expansive growth in discrete numbers, which locally might even seem growing linearly, the only way to see our local reality - each
#    > thing, day by day, happens mostly by counting or it's linear measures, and probabilities such as 7/13 are very hard to point somewhere directly, even
#    > if this one appears in a brief: rather if you are a machine or fraction-mental, or see those fractions somewhere in your sensitive world; and this
#    > is one adaptible to nerve systems such as DL, but might lack special biological interest or special motivation, or your spiritual claim that it's "better"
#    > to know that, in real time: our nerves sense patterns in real time, where we learn variations, and kind of synthesis can unite this into virtual wavelength,
#    > layered proposition, to your visual system or even, how you decode mental visual into graphical one, such as a graph or a symbol, with some effort. Various
#    > levels of such systeming can be achieved; in reality: for any such case, we say probability is material only if we see it directly, and it's contained
#    > in single, local, material, or logically single, local, termable quality. We use symmetries -2 to -1 and 1 to 2 to form linearized exponential measures,
#    > divided by infinity where the number "1" does not move, but the number "zero" definitely forms a quantum dimension to still unite somehow to 1/infinity,
#    > just a polarity of the same number: single operation would trigger this, instead of the other, lower-precision zero; to not lose any higher relation,
#    > and often they are zeroes in systems of same scope - they would correlate the same way, for example if it has a certain action, it also has a zero amount
#    > of work to that direction, but if an effect comes two days later: near zero, it has modifier which relates to this zero as local two, two divided by infinity.
#
#    > And it's not visible in limits of numbers: the one with zero, is visible if you compare the numbers *first*, then resolve the unknown limit for this calc
#    > *itself*; instantly, you see those two already compare in your system, and in any projection the average forms a *coherent* system; the average of the
#    > possible projections you can see this in: then, A * infinity / 2 is twice smaller than B * infinity; but if they numberwise compare in any system, and regard
#    > to this operation: normally we won't assign value to whole operational sentence, but now we just assign: A * infinity / 2 is twice smaller than B * infinity.
#    > A theorem is, in symmetric projection we never assign anything else. We just use the only values we got, and assume that it never comes out that
#    > A * infinity / 2 is anything other than B * infinity in zero scope, unless we use distorted and approximate projection, which we *generally do*: still linear
#    > systems only slowly become inconsistent, close measurement or senses or in hands of an AI, a back-gradient-linear future sense approximator; it efficiently
#    > does it's logic *backwards*, but defines as *forewards* - then, yet, it starts to question itself in *forewards* manner; we can see it's equivalent experience
#    > worth of matter, qualitatively it's sometimes worth an experience, and you fill your cup of wisdom without actually experiencing result on calculator screen,
#    > result of attempt or result of in-head calculation if this artifice is doing that for you, and not this, as a "thing" - "that" definitely feels more full, and
#    > you can already use such verbatims.

# ==================================================================================================================================================================
# END OF MANUAL
# ==================================================================================================================================================================

# ==================================================================================================================================================================
# IMPLEMENTATION
# ==================================================================================================================================================================

# Let's dive in.
# ∞ - UTF-8 infinity sign.

def LaegnaValueBase4(digits):
    mult = 4**(len(digits)-1)
    value = 0
    for dig in range(len(digits)):
        value += digits[dig] * mult
        mult //= 4
    return value + 1

def WaveweaverValueBase4(digits):
    mult = 4**(len(digits)-1)
    value = 0
    for dig in range(len(digits)):
        digit = digits[dig]
        if dig > 0:
            if digits[dig-1] in [1, 2]:
                if digit == 1: digit = 2
                elif digit == 2: digit = 1
            if digits[dig-1] in [1, 2]:
                if digit == 0: digit = 1
                elif digit == 1: digit = 0
                elif digit == 2: digit = 3
                elif digit == 3: digit = 2
        value += digit * mult
        mult //= 4
    return value + 1

def WaveweaverDigitsBase4(digitsin):
    digitsout = []
    for dig in range(len(digitsin)):
        digit = digitsin[dig]
        if dig > 0:
            if digitsin[dig-1] in [1, 2]:
                if digit == 1: digit = 2
                elif digit == 2: digit = 1
            if digitsin[dig-1] in [1, 2]:
                if digit == 0: digit = 1
                elif digit == 1: digit = 0
                elif digit == 2: digit = 3
                elif digit == 3: digit = 2
        digitsout.append(digit)
    return digitsout

def num2let(digits):
    let = ["I", "O", "A", "E"]
    return "".join(let[d] for d in digits)

HEX_TABLE = [
    ["K", "J", "I", "L"],
    ["Q", "P", "O", "P"],
    ["C", "B", "A", "B"],
    ["G", "F", "E", "F"],
]

# YOUR EXACT BINARY TABLE
BIN_TABLE = {
    0: [1,1],  # I -> OO
    1: [1,2],  # O -> OA
    2: [2,1],  # A -> AO
    3: [2,2],  # E -> AA
}

def normalize_digits(digits):
    out = []
    for d in digits:
        if isinstance(d, (list,tuple)) and len(d)==2:
            out.append(d[1])
        else:
            out.append(d)
    return out

def num2hex(digits):
    digits = normalize_digits(digits)
    if len(digits)%2 != 0:
        return None
    out=""
    for i in range(0,len(digits),2):
        out += HEX_TABLE[digits[i]][digits[i+1]]
    return out

def num2bin(digits):
    digits = normalize_digits(digits)
    out=[]
    for d in digits:
        pair = BIN_TABLE[d]
        out.append("O" if pair[0]==1 else "A")
        out.append("O" if pair[1]==1 else "A")
    return "".join(out)

def extreme_bin(label):
    return label*2

def decimal_hex_label(decimal_num):
    try:
        if isinstance(decimal_num,str):
            val=int(decimal_num)
        elif isinstance(decimal_num,(int,float)) and float(decimal_num).is_integer():
            val=int(decimal_num)
        else:
            return None
        return format(val,"X")
    except:
        return None

def decimal_bin_label(decimal_num):
    try:
        if isinstance(decimal_num,str):
            val=int(decimal_num)
        elif isinstance(decimal_num,(int,float)) and float(decimal_num).is_integer():
            val=int(decimal_num)
        else:
            return None
        return format(val,"b")
    except:
        return None

def countR(R=1,prefix=None):
    if prefix is None:
        prefix=[]
    for dig in range(4):
        if R==1:
            yield prefix+[dig]
        else:
            for num in countR(R-1,prefix+[dig]):
                yield num

def laegna_wave_hex_label(num_str,R):
    if all(ch==num_str[0] for ch in num_str) and num_str[0] in "WVU∩" and len(num_str)%2==0:
        return num_str[0]*(len(num_str)//2)
    if R%2!=0:
        return None
    let_to_digit={"I":0,"O":1,"A":2,"E":3}
    digits=[let_to_digit[ch] for ch in num_str if ch in let_to_digit]
    if len(digits)%2!=0:
        return None
    return num2hex(digits)

def numberlist(R=1):
    fullnumbers=[]
    for _ in range(4**R):
        fullnumbers.append({"Decimal":{},"Wave":{},"Laegna":{}})

    for num in countR(R):
        w_idx = WaveweaverValueBase4(num) - 1
        l_idx = LaegnaValueBase4(num) - 1
    
        wave_str = num2let(num)
        laeg_str = num2let(num)
    
        fullnumbers[w_idx]["Wave"]["Num"] = wave_str
        fullnumbers[w_idx]["Wave"]["Digits"] = num          # ← FIX
    
        fullnumbers[l_idx]["Laegna"]["Num"] = laeg_str
        fullnumbers[l_idx]["Laegna"]["Digits"] = num

    numbers=[]

    # -inf
    numbers.append({
        "Decimal":{"Num":"0","Signed":"-inf","Hex":decimal_hex_label("0"),"Bin":decimal_bin_label("0")},
        "Wave":{"Num":"W"*R,"Hex":laegna_wave_hex_label("W"*R,R),"Bin":extreme_bin("W"*R)},
        "Laegna":{"Num":"W"*R,"Hex":laegna_wave_hex_label("W"*R,R),"Bin":extreme_bin("W"*R)}
    })

    half=4**R//2
    offset_signed=4**2//2

    # negative side
    for idx in range(half):
        dec=str(idx+1)
        signed=str(idx-offset_signed)
        fullnumbers[idx]["Decimal"]={
            "Num":dec,
            "Signed":signed,
            "Hex":decimal_hex_label(dec),
            "Bin":decimal_bin_label(dec)
        }

        # Wave
        w=fullnumbers[idx]["Wave"]
        w["Hex"]=laegna_wave_hex_label(w["Num"],R)
        w["Bin"]=num2bin(w["Digits"])

        # Laegna
        l=fullnumbers[idx]["Laegna"]
        l["Hex"]=laegna_wave_hex_label(l["Num"],R)
        l["Bin"]=num2bin(l["Digits"])

        numbers.append(fullnumbers[idx])

    # -0
    mid_val=4**R//2+0.5
    numbers.append({
        "Decimal":{"Num":mid_val,"Signed":"-0","Hex":decimal_hex_label(mid_val),"Bin":None},
        "Wave":{"Num":"V"*R,"Hex":laegna_wave_hex_label("V"*R,R),"Bin":extreme_bin("V"*R)},
        "Laegna":{"Num":"V"*R,"Hex":laegna_wave_hex_label("V"*R,R),"Bin":extreme_bin("V"*R)}
    })

    # +0
    numbers.append({
        "Decimal":{"Num":mid_val,"Signed":"+0","Hex":decimal_hex_label(mid_val),"Bin":None},
        "Wave":{"Num":"U"*R,"Hex":laegna_wave_hex_label("U"*R,R),"Bin":extreme_bin("U"*R)},
        "Laegna":{"Num":"U"*R,"Hex":laegna_wave_hex_label("U"*R,R),"Bin":extreme_bin("U"*R)}
    })

    # positive side
    for idx in range(half):
        base=idx+half
        dec=str(base+1)
        signed="+"+str(idx+1)
        fullnumbers[base]["Decimal"]={
            "Num":dec,
            "Signed":signed,
            "Hex":decimal_hex_label(dec),
            "Bin":decimal_bin_label(dec)
        }

        w=fullnumbers[base]["Wave"]
        w["Hex"]=laegna_wave_hex_label(w["Num"],R)
        w["Bin"]=num2bin(w["Digits"])

        l=fullnumbers[base]["Laegna"]
        l["Hex"]=laegna_wave_hex_label(l["Num"],R)
        l["Bin"]=num2bin(l["Digits"])

        numbers.append(fullnumbers[base])

    # +inf
    numbers.append({
        "Decimal":{"Num":"2inf","Signed":"+inf","Hex":None,"Bin":None},
        "Wave":{"Num":"∩"*R,"Hex":laegna_wave_hex_label("∩"*R,R),"Bin":extreme_bin("∩"*R)},
        "Laegna":{"Num":"∩"*R,"Hex":laegna_wave_hex_label("∩"*R,R),"Bin":extreme_bin("∩"*R)}
    })

    return numbers

class Rib:
    def __init__(self,R,b=4):
        self.R=R
        self.b=b
        self.numbers=numberlist(R)
        self.B=b**R
        self.halfB=self.B/2
        self.W=(0,-self.halfB-2)
        self.V=(self.halfB,-1)
        self.U=(self.halfB+1,+1)
        self.UU=(self.B,self.halfB+2)

    def __len__(self):
        return len(self.numbers)

    def to_list(self):
        return self.numbers

    def to_json(self):
        return {"R":self.R,"base":self.b,"B":self.B,"numbers":self.numbers}

class MathScript:
    def __init__(self,R_list=None,base=4):
        if R_list is None:
            R_list=[1,2,3,4]
        self.R_list=R_list
        self.base=base
        self.chapters=[Rib(R,base) for R in R_list]

    def __len__(self):
        return sum(len(ch) for ch in self.chapters)

    def to_list(self):
        return [ch.to_list() for ch in self.chapters]

    def to_json(self):
        return {
            "meta":{"version":1,"description":"Laegna / Waveweaver number system export"},
            "chapters":[{"R":ch.R,"base":ch.b,"numbers":ch.to_list()} for ch in self.chapters]
        }

if __name__=="__main__":
    script=MathScript()
    print(json.dumps(script.to_json(),ensure_ascii=False,indent=2))
