We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.

Kontakion-machine

From Esolang
Jump to navigation Jump to search

A Kontakion-machine uses heptavtinimal terscii encoding and generates a Kontakion.

It can evaluate a word or a set of words and operates by producing a jump-address in the case of a collision between two words.

machine

# -----------------------------
# TERSCII ENCODING
# -----------------------------
_CHAR_TO_TERSCII_CODE = {}

# Mapping for the Basic Roman Block (00-88)
terscii_roman_block_map = [
    # Col 0    Col 1    Col 2    Col 3    Col 4    Col 5    Col 6    Col 7    Col 8
    ["ES", "SP", "0", "9", "I", "R", "_", "i", "r"], # Row 0
    ["EL", "-", "1", "A", "J", "S", "a", "j", "s"], # Row 1
    ["ET", "'", "2", "B", "K", "T", "b", "k", "t"], # Row 2
    ["LR", ",", "3", "C", "L", "U", "c", "l", "u"], # Row 3
    ["OP", ";", "4", "D", "M", "V", "d", "m", "v"], # Row 4
    ["RL", ":", "5", "E", "N", "W", "e", "n", "w"], # Row 5
    ["SU", ".", "6", "F", "O", "X", "f", "o", "x"], # Row 6
    ["HT", "!", "7", "G", "P", "Y", "g", "p", "y"], # Row 7
    ["SD", "?", "8", "H", "Q", "Z", "h", "q", "z"], # Row 8
]

for row_idx, row_chars in enumerate(terscii_roman_block_map):
    for col_idx, char_code_str in enumerate(row_chars):
        terscii_code = f"{row_idx}{col_idx}"
        # Explicitly map known characters, prioritizing printable characters
        if char_code_str == "SP":
            _CHAR_TO_TERSCII_CODE[" "] = terscii_code
        elif len(char_code_str) == 1: # Single character (digit, letter, punctuation)
            _CHAR_TO_TERSCII_CODE[char_code_str] = terscii_code
        # Control codes like ES, EL, ET, LR, OP, RL, SU, HT, SD are not direct printable chars 
        # that would appear in the 'word' for this context, so we don't map them here.

# Mapping for the Extended Block (Block 01)
terscii_extended_block_map = [
    # Col 0 Col 1 Col 2 Col 3 Col 4 Col 5 Col 6 Col 7 Col 8
    [None, '‘', None, None, None, None, None, None, None], # Row 0
    [None, '*', None, None, None, None, None, None, None], # Row 1
    [None, '’', None, None, None, None, None, None, None], # Row 2
    [None, '/', None, None, None, None, None, None, None], # Row 3
    [None, '|', None, None, None, None, None, None, None], # Row 4
    [None, '\\', None, None, None, None, None, None, None], # Row 5
    [None, '‹', None, None, None, None, None, None, None], # Row 6
    [None, '◊', None, None, None, None, None, None, None], # Row 7
    [None, '›', None, None, None, None, None, None, None], # Row 8
]

# Process Extended Block
for row_idx, row_chars in enumerate(terscii_extended_block_map):
    for col_idx, char_code_str in enumerate(row_chars):
        if char_code_str is not None: # Only map if character is present
            terscii_code = f"1{row_idx}{col_idx}" # Block 1 prefix, e.g., '101' for '‘'
            _CHAR_TO_TERSCII_CODE[char_code_str] = terscii_code

def word_to_terscii_string(word):
    terscii_parts = []
    for char in word:
        terscii_code = _CHAR_TO_TERSCII_CODE.get(char)
        if terscii_code is None:
            terscii_parts.append("00") # Default to 'ES' (End of String) for unmapped characters
        else:
            terscii_parts.append(terscii_code)
    return "".join(terscii_parts)

def convert_hex_string_to_terscii_codes(hex_str):
    terscii_hex_parts = []
    for char in hex_str.upper(): # Ensure uppercase for hex digits A-F
        terscii_code = _CHAR_TO_TERSCII_CODE.get(char)
        if terscii_code is None:
            # For characters not explicitly in the TerSCII tables (e.g. if pad chars were not '0')
            # Fallback to '00' (ES) as a general default.
            terscii_hex_parts.append("00")
        else:
            terscii_hex_parts.append(terscii_code)
    return "".join(terscii_hex_parts)

# -----------------------------
# COLLISION RESOLUTION AND ORCHESTRATION
# -----------------------------

def process_words_with_collision_resolution(words):
    global_seen_addresses = set()
    jump_register = {}
    final_output = []
    MAX_COLLISION_ATTEMPTS = 64 # Cap similar to internal octal doubling

    print("\n--- Processing Words ---\n")

    for word in words:
        print(f"Analyzing WORD: {word}")
        word_registry = analyze(word)
        terscii_representation = word_to_terscii_string(word)

        # Store current word's results temporarily to allow for jump register updates
        current_word_processed_entries = []

        for hept, original_full_addr, radix_val, seq_counter in word_registry:
            current_seq_counter = seq_counter
            current_full_addr = original_full_addr
            attempts = 0
            collision_detected_for_this_entry = False

            # Extract base parts to rebuild address
            pad_radix_part = original_full_addr[2:23] # '0'*15 + radix_hex

            while current_full_addr in global_seen_addresses and attempts < MAX_COLLISION_ATTEMPTS:
                if not collision_detected_for_this_entry: # Mark first collision for this entry
                    collision_detected_for_this_entry = True
                    # Only add to jump register if it's the first time this original address causes a collision
                    if original_full_addr not in jump_register:
                        jump_register[original_full_addr] = None # Placeholder, will be updated with final unique address

                current_seq_counter += 1
                # The current_seq_counter (0-63) directly maps to a TerSCII index (0-80).
                # We format this index as a 3-digit hex string for the address.
                new_seq_hex = format(current_seq_counter, '03X')
                current_full_addr = f"0x{pad_radix_part}{new_seq_hex}"
                attempts += 1

            if collision_detected_for_this_entry:
                jump_register[original_full_addr] = current_full_addr

            if current_full_addr in global_seen_addresses:
                print(f"  WARNING: Collision for {word} at {current_full_addr} could not be resolved after {MAX_COLLISION_ATTEMPTS} attempts. Using potentially non-unique address: {current_full_addr}")

            global_seen_addresses.add(current_full_addr)
            current_word_processed_entries.append((word, hept, current_full_addr, terscii_representation))

        final_output.extend(current_word_processed_entries)

    # Sort the final output by hept_to_int value across all words
    # Sorting key remains on the base hept value, not the appended terscii representation
    final_output.sort(key=lambda x: hept_to_int(x[1]))

    print("\n--- Final Registry Output ---\n")
    for idx, (word, hept, full_addr, terscii_encoded_word) in enumerate(final_output):
        last9 = full_addr[-9:]
        terscii_encoded_last9_hex = convert_hex_string_to_terscii_codes(last9)
        # The requested format: idx:HEPT_code<TERSCII_encoded_address_part>TERSCII_encoded_word
        print(f"{idx}:{hept}<{terscii_encoded_last9_hex}>{terscii_encoded_word}")

    # Removed printing of jump_register debugfs as requested.

# -----------------------------
# RUN IT WITH MULTIPLE WORDS
# -----------------------------
words_to_analyze = ["Hello, ", "World!"]
process_words_with_collision_resolution(words_to_analyze)

example

A + B problem

-- Processing Words ---

Analyzing WORD: A
Analyzing WORD: B

--- Final Registry Output ---

0:0<020242335332020202>13
1:0<020222720253024212>23
2:A<020242335332020212>23
3:B<020242335322020212>23
4:D<020242335312020222>23
5:H<020242335302020232>23
6:P<020242334363020242>23
7:AE<020242334353020252>23
8:BJ<020242334343020262>23
9:DT<020242334333020272>23
10:IM<020242334323020282>23
11:RZ<020242334313020203>23
12:AJY<020242334303020213>23
13:BMP<020242333343021262>23
14:BST<020242331362023243>23
15:BUW<020242334382020223>23
16:BWT<020242332382022223>23
17:CEA<020242332363022242>23
18:E0E<020242333333021272>23
19:EFH<020242331313023203>23
20:EJN<020242331353023252>23
21:ELM<020242331352023253>23
22:EPS<020242334372020233>23
23:ETM<020242332372022233>23
24:FJB<020242332353022252>23
25:GJD<020242333363021242>23
26:HBQ<020242332302023232>23
27:HPA<020242334312021222>23
28:HXG<020242334332021202>23
29:J0J<020242333323021282>23
30:JLP<020242331303023213>23
31:JUA<020242331343023262>23
32:JXZ<020242331342023263>23
33:KCS<020242332332023202>23
34:KFK<020242334362020243>23
35:KMZ<020242332362022243>23
36:LTD<020242332343022262>23
37:LTK<020242333342021263>23
38:MAM<020242333303021213>23
39:NTH<020242333353021252>23
40:NWJ<020242331372023233>23
41:NYJ<020242332303022213>23
42:OBN<020242333302022232>23
43:PCD<020242331323023282>23
44:PEG<020242331363023242>23
45:QEB<020242334302021232>23
46:QNV<020242332312023222>23
47:QUN<020242334322021212>23
48:QYQ<020242334342020263>23
49:SAW<020242332342022263>23
50:SWS<020242333352021253>23
51:T0T<020242333313021203>23
52:TYE<020242331382023223>23
53:TZE<020242332313022203>23
54:UAG<020242333312022222>23
55:UOB<020242331333023272>23
56:UVY<020242331332024202>23
57:VGK<020242332322023212>23
58:VLV<020242334352020253>23
59:W0Y<020242332352022253>23
60:WKW<020242333362021243>23
61:WZP<020242332323022282>23
62:X0Q<020242333322022212>23
63:YEY<020242333372021233>23
64:YMH<020242332333022272>23
65:YMV<020242333332022202>23
66:ZBZ<020242333382021223>23

See also