Haczyk

From Esolang
Jump to navigation Jump to search

Haczyk is a language where the variables barter based on the letters in their names.

Name

The name comes from haczyk, which was a Polish word according to English Wiktionary at the time the language was created, defined as informally meaning "catch, hidden disadvantage in a deal" and as the diminutive of hook.

Description

Haczyk 0.1.0

In Haczyk 0.1.0, the only datatype is an unordered dictionary. Each variable has an unordered dictionary which contains characters and corresponding numbers. The variables desire the characters which are in their name or which correspond to negative numbers.

Variables are assigned characters using the assignment operators +< which adds things and -< which takes things away. Each of these can be followed by a number between 0 and 9, where 0 indicates nothing was added or taken away, 1 indicates one of each character was added or taken away, etc.

name +<9 corn

causes the variable name to consist of an unordered dictionary where "c", "o", "r" and "n" correspond to 9.

Each time that a variable is assigned, the variables barter for characters they want, which include characters in their name or for which they have a negative number. For each character in its name, the variable checks if another variable has either the character in its name or a character for which it has a negative number, then checks if it has a character which the variable wants. If both of these are true, the variables trade characters.

There are if-statements and while-loops, where in practice, an if-statement is a while-loop which only runs once.

These loops always start with a question mark. Then there is either a number, which signifies the amount of times to loop, or another question mark, which signifies an infinite loop. Then there is a set of parentheses. Then on a new line, there can be other pieces of code, including other loops. Finally, at the very end, there is a single close bracket (there is no corresponding open bracket).

Example of an unconditional while-loop:

?100()//repeats 100 times unconditionally
name +<9 corn
)
//At the end, name contains 900 of "c", "o", "r", and "n".

Not Turing-Complete

In order to be Turing-complete, the language has to:

  • be able to store data without changing it
  • be able to change conditionally

Haczyk 0.1.0 can't do the latter, only being able to loop conditionally. It cannot be Turing-complete for this reason. It might be able to do the former, because as long as the character doesn't appear in any other names, you can add the character to one variable over time.


Implementation

This is the implementation of Haczyk 0.1.0 which only has unconditional loops. It is probably not Turing-complete.

# the coder gives alphanumeric characters to the variables
# who barter with each other
# they like the stuff in their names
# they share everything else equally
def run_haczyk(code_string: str, textfile = False):
    code = []       # this holds the code
    pointer = 0     # this points to the line being read
    var_dict = {}   # this holds all the variables
    nested_loop = False     # this checks if it is already in a loop

    # prints out error message
    # is not an error
    class Haczyk_Error():
        def __init__(self, message):
            print('Error:', message, sep="\n")

    # assigns data
    def assign_data(variable, relation, value):
        sign = relation[0]
        times = relation[2]     # must be between 0 and 9
        if variable not in var_dict:
            var_dict[variable] = dict()

        if not times.isdigit():
            return Haczyk_Error(f'Character {times} must be a digit between 0 and 9, inclusive.')
        else:
            times = int(times)
            if times != 0:
                if sign == '+':
                    for ch in value:
                        if ch not in var_dict[variable]:
                            var_dict[variable][ch] = 0
                        var_dict[variable][ch] += times
                        if var_dict[variable][ch] == 0:
                            del var_dict[variable][ch]
                elif sign == '-':
                    for ch in value:
                        if ch not in var_dict[variable]:
                            var_dict[variable][ch] = 0
                        var_dict[variable][ch] -= times
                        if var_dict[variable][ch] == 0:
                            del var_dict[variable][ch]
                else:
                    return Haczyk_Error(f'Sign {sign} has not been implemented yet.')

    # checks if the variable and value contain only letters and numbers
    def good_variable(variable):
        for char in variable:
            if not (char.isdigit() or char.isalpha()):
                return Haczyk_Error(f'"{variable}" has characters which are not allowed.\n'
                                    f'It can only contain letters and numbers.')
        return variable

    if textfile:
        for line in open(code_string, 'r'):
            code.append(line.strip('\n'))
    else:
        code += code_string.split('\n')

    # checks if parentheses are valid
    while_count_dict = {}
    to_open_paren = {}
    to_close_paren = {}
    open_paren_stack = []
    for num, chars in enumerate(code):
        if chars.strip() == '':
            continue
        elif chars.strip()[0] == '?':
            if '(' not in chars or ')' not in chars:
                continue
            while_statement = chars.strip()
            maximum_number = while_statement[while_statement.index('?')+1:while_statement.index('(')].strip()
            if not ((maximum_number.isdigit() and int(maximum_number) >= 0) or maximum_number == '?'):
                return Haczyk_Error(f'"{maximum_number}" is not a valid number of maximum iteration times'
                                    f' in "{while_statement}" at line {num-1}.'
                                    f'Maximum number of times must be a non-negative integer'
                                    f' or "?" which signifies infinite looping.')
            while_count_dict[num] = maximum_number
            open_paren_stack.append(num)
            print(open_paren_stack)
        elif chars.strip() == ')':
            if len(open_paren_stack) == 0:
                return Haczyk_Error(f'")" at line {num} has no corresponding if statement or while loop.')
            to_open_paren[num] = open_paren_stack[-1]
            to_close_paren[open_paren_stack[-1]] = num
            open_paren_stack.pop()
    if len(open_paren_stack) > 0:
        return Haczyk_Error(f'There are unpaired "?" at lines: {open_paren_stack}')

    # actually interprets code
    while pointer < len(code):
        # interprets one line of code
        # bartering happens after each line of code is seen
        line = code[pointer].strip()
        if '//' in line:
            line = line[:line.index('//')]
        if len(line) > 0:
            if line[0] == '?':
                if pointer not in while_count_dict:
                    print(line)
                else:
                    if while_count_dict[pointer] == '0':
                        if nested_loop:
                            while_statement = line.strip()
                            while_count_dict[pointer] = while_statement[while_statement.index('?')+1:
                                                                        while_statement.index('(')].strip()
                        if while_count_dict[pointer] == '0':
                            pointer = to_close_paren[pointer]
                            continue
                    else:
                        nested_loop = True
                # implement if-statement rules
            elif line.strip() == ')':
                repeats_number = while_count_dict[to_open_paren[pointer]]
                if repeats_number != '0':
                    if repeats_number.isdigit():
                        while_count_dict[to_open_paren[pointer]] = str(int(repeats_number)-1)
                    pointer = to_open_paren[pointer] - 1
                nested_loop = False
            elif '<' in line:
                var, val = line.split('<', 1)
                command = f'{var[-1]}<{val[0]}'
                var, val = good_variable(var[:-1].strip()), good_variable(val[1:].strip())
                if isinstance(var, Haczyk_Error):
                    return var
                sanity = assign_data(var, command, val)
                if isinstance(sanity, Haczyk_Error):
                    return sanity
            else:
                if line[-1] == ']' and '[' in line and line[:line.index('[')] in var_dict:
                    var_line = line[:line.index('[')]
                    letter = line[line.index('[')+1:line.index(']')]
                    if letter == '':
                        print(f'{var_line}: {var_dict[var_line]}')
                    elif letter not in var_dict[var_line]:
                        print(f'{var_line}[{letter}]: 0')
                    else:
                        print(f'{var_line}[{letter}]: {var_dict[var_line][letter]}')
                else:
                    print(line)
        pointer += 1

        # begins bartering
        for var1 in [one for one in var_dict][::-1]:
            for var2 in [two for two in var_dict]:
                if var1 != var2:
                    var1_wants = [char for char in var1] + [key for key in var_dict[var1] if var_dict[var1][key] < 0]
                    for char_var1_wants in var1_wants:
                        if char_var1_wants in var_dict[var2]:
                            var2_wants = [char for char in var2] + [key for key in var_dict[var2] if var_dict[var2][key] < 0]
                            for char_var2_wants in var2_wants:
                                if char_var2_wants in var_dict[var1]:
                                    if char_var1_wants == char_var2_wants:
                                        continue
                                    if char_var1_wants not in var_dict[var1]:
                                        var_dict[var1][char_var1_wants] = 0
                                    if char_var2_wants not in var_dict[var2]:
                                        var_dict[var2][char_var2_wants] = 0
                                    num_var1_has = var_dict[var1][char_var2_wants]
                                    num_var2_has = var_dict[var2][char_var1_wants]
                                    if num_var1_has > num_var2_has:
                                        var_dict[var1][char_var1_wants] += num_var2_has
                                        var_dict[var2][char_var1_wants] = 0
                                        var_dict[var1][char_var2_wants] -= num_var2_has
                                        var_dict[var2][char_var2_wants] += num_var2_has
                                    elif num_var2_has > num_var1_has:
                                        var_dict[var1][char_var1_wants] += num_var1_has
                                        var_dict[var2][char_var1_wants] -= num_var1_has
                                        var_dict[var1][char_var2_wants] = 0
                                        var_dict[var2][char_var2_wants] += num_var1_has
                                    else:
                                        var_dict[var1][char_var1_wants] += num_var2_has
                                        var_dict[var2][char_var1_wants] = 0
                                        var_dict[var1][char_var2_wants] = 0
                                        var_dict[var2][char_var2_wants] += num_var1_has

                                    if char_var1_wants in var_dict[var1] and var_dict[var1][char_var1_wants] == 0:
                                        del var_dict[var1][char_var1_wants]
                                    if char_var2_wants in var_dict[var1] and var_dict[var1][char_var2_wants] == 0:
                                        del var_dict[var1][char_var2_wants]
                                    if char_var1_wants in var_dict[var2] and var_dict[var2][char_var1_wants] == 0:
                                        del var_dict[var2][char_var1_wants]
                                    if char_var2_wants in var_dict[var2] and var_dict[var2][char_var2_wants] == 0:
                                        del var_dict[var2][char_var2_wants]

                                    break
                    # another idea I had
                    # var1_not_wants = [key for key in var_dict[var1] if key not in var1_wants]
    return 'File ended'

Trivia

  • Haczyk is possibly the only programming language which isn't alpha-equivalent. If you change a variable name, it has a legitimate and unavoidable effect on how the program runs.
  • The name of this language came from the programming language Crazy, because it was meant to belong to a language based on that language. The idea behind the language came from the communism idea, but a satirization of capitalism instead of communism.