Esolang Buffet, round #1

Started at 2022-06-09T20:51:55+00:00; stage 2 since 2022-06-25T20:51:55+00:00. Ended at 2022-07-09T20:51:55+00:00.

Specification

The task for the first round will be sorting lists of integers.

The test cases are as follows:

[] => []
[172] => [172]
[203, 35] => [35, 203]
[18, 13, 94] => [13, 18, 94]
[193, 46, 26, 129] => [26, 46, 129, 193]
[77, 108, 182, 111, 242] => [77, 108, 111, 182, 242]
[88, 159, 106, 233, 87, 30] => [30, 87, 88, 106, 159, 233]
[151, 106, 165, 236, 180, 249, 113] => [106, 113, 151, 165, 180, 236, 249]
[117, 238, 17, 93, 165, 76, 166, 15] => [15, 17, 76, 93, 117, 165, 166, 238]
[115, 7, 181, 141, 13, 205, 86, 231, 135] => [7, 13, 86, 115, 135, 141, 181, 205, 231]
[118, 23, 77, 47, 177, 48, 15, 111, 25, 75] => [15, 23, 25, 47, 48, 75, 77, 111, 118, 177]
[106, 220, 114, 44, 57, 117, 169, 56, 198, 109, 165] => [44, 56, 57, 106, 109, 114, 117, 165, 169, 198, 220]
[30, 15, 164, 86, 18, 200, 93, 145, 224, 249, 134, 160] => [15, 18, 30, 86, 93, 134, 145, 160, 164, 200, 224, 249]
[167, 230, 10, 83, 226, 93, 97, 218, 98, 51, 115, 236, 94] => [10, 51, 83, 93, 94, 97, 98, 115, 167, 218, 226, 230, 236]
[248, 106, 26, 120, 32, 72, 218, 78, 178, 37, 76, 15, 137, 218] => [15, 26, 32, 37, 72, 76, 78, 106, 120, 137, 178, 218, 218, 248]
[214, 158, 209, 243, 75, 148, 216, 195, 223, 137, 169, 90, 142, 109, 1] => [1, 75, 90, 109, 137, 142, 148, 158, 169, 195, 209, 214, 216, 223, 243]

Players

Results

1. olus2000:        +7 -1 = +6
2. SoundOfSpouting: +6 -1 = +5
3. IFcoltransG:     +3 -3 =  0
4. firecubez:       +0 -0 =  0
5. Palaiologos:     +0 -1 = -1
6. umnikos:         +1 -3 = -2
7. Ardemit:         +0 -2 = -2
8. MattiDragon:     +0 -3 = -3
8. RocketRace:      +0 -3 = -3

Solver          => Solved
===================================
olus2000        => Palaiologos
olus2000        => umnikos
olus2000        => Ardemit
olus2000        => SoundOfSpouting
olus2000        => RocketRace
olus2000        => IFcoltransG
olus2000        => MattiDragon
SoundOfSpouting => olus2000
SoundOfSpouting => MattiDragon
SoundOfSpouting => Ardemit
SoundOfSpouting => umnikos
SoundOfSpouting => RocketRace
SoundOfSpouting => IFcoltransG
IFcoltransG     => umnikos
IFcoltransG     => RocketRace
IFcoltransG     => MattiDragon
umnikos         => IFcoltransG

Entries

Entry #1

Written by IFcoltransG

rabbitsfoot.md Unicode text, UTF-8 text, with very long lines (404)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<!--Please note that this specification is written in PLAIN TEXT as per the Esolang Buffet rules-->

# Rabbitsfoot
> “I think that someone will remember us in another time.”
> — Sappho of Lesbos (Lobel & Page, Fragment 147)

The Rabbitsfoot language employs the revolutionary new "rabbitsfoot" paradigm, which some liken to the sweet-spot between blockchain, quantum computing, and big data. It also employs the imperative paradigm, which is counter-revolutionary and old.

It was designed by IFcoltransG in 2022 for the first inaugural Esolangs Buffet event on the Unofficial Esolangs Discord Server. (The first inaugural one, not for any other inaugural ones after that.)

Rabbitsfoot's file extension is `.rtf` for programs, or `.rtfm` for Rabbitsfoot library modules.

## Usage
Run the interpreter on your program from the command line.
```sh
# regular mode
python ./rabbitsfoot.py FILENAME
# verbose mode:
python ./rabbitsfoot.py -v FILENAME
python ./rabbitsfoot.py --verbose FILENAME
```

The interpreter will read from standard input a list of integers.
The integers are separated by whitespace and/or commas, and can have optional `[` and `]` on each end. The list is terminated by a newline.

Output is written like a Python list.

### Example inputs
`1 2 3 4 5`
`[1, 2, 3, 4, 5]`

### Example program
```rabbitsfoot
# cat
,
.
```

### Example output for example inputs into example program
`[1, 2, 3, 4, 5]`

## Execution
The interpreter stores a tuple of W indices called the index tuple, where W is the window size.
The interpreter stores an array of size N called the array, where N is the number of integers in the program input.
The interpreter stores a stack, called the stack.
The interpreter optionally stores a single value, called the cache.

Initially, the array is set to the program input.
Initially, the index tuple is set to (0, ..., 0).
Initially, the stack is empty.

If N is ever 0, the program terminates immediately and outputs its results.

### Input
Whenever input is requested, a list V of size W is pushed onto the stack. The i-th element of V is taken from the array at index j, where j is the i-th element of the index tuple.

For instance, if W=N and the index tuple is (0, 1, ..., N-1), then V has the exact same elements as the array. If W=2, N>0 and the index tuple is (0, 0), then V will be [X, X], where X is the first element of the array.

After the array is initialised, the program input itself is treated as compromised and must no longer be trusted. Subsequent requests for input will treat the array as the only source of truth.

### Basic Loop
The user's program is run, line by line, from the first line, until any control flow statements are reached.

### Stack
The stack can contain integers, lists of integers or strings. However, the stack cannot contain its excitement whenever it sees a bunny rabbit.

If a value is popped from an empty stack, that is undefined behaviour. So don't pop from an empty stack.

### Window size
W is equal to 1 if the program contains no `[`...`]` instructions. Otherwise, it is inferred so that it fits with a `[`...`]` instruction.

## Instructions
All lines must exactly comport to one or more of the following standards.
Except where otherwise noted, commands must take up between 0 and 2 lines (exclusive) with only whitespace left over.

Punctuation that corresponds with endorsed operations have a newline automatically inserted after them, unless they are part of a comment.

### Comments
Any line containing only whitespace is ignored.
Any line beginning with `#` or `REM ` is ignored.
It's nothing personal, and the interpreter ignoring your code doesn't reflect on your value as a person.

### Loop
The `.` command pops a list from top-of-stack, then iterates through each index i in it, storing the i-th value of the list into the array index given by the i-th element of the index tuple. If the value at top-of-stack is not a list, that is undefined behaviour.

(If it helps, imagine the list is a list of rabbits. Then the `.` command pops the list off the stack, and lets all of the rabbits loose, so that they find the value in the index tuple that was at the same position as them, and gnaw at the index in the array given by the value they found, until that array location becomes the value corresponding to that rabbit.)

Then the interpreter increments that the index tuple and then jumps to the start of the program. (Implementations must preserve the stack.)

All programs must contain at least one `.`. Programs that contain only comments are undefined behaviour.

To increment the index tuple, add one to its rightmost value.
Then until no elements of the tuple equal N, pick any element that equals N, set it to exactly 0, then add one to the element to its left in the tuple. If no such element exists, the program terminates immediately and outputs its results.

### Literal
The `[`...`]` command pushes a given list of integers onto the stack. Between the `[` and the `]` are a sequence with length W of whitespace separated integers.

Patent pending.

### Zilch
The `0` command pushes a 0 to the stack.

If both N and W equal 0, or if the index tuple is (0, ..., 0), then it is undefined behaviour to run `0`. That would be too many zeros. It's safer this way.

### Memory
The first time `|` is executed, it peeks at the top value of the stack and saves it to the cache. Any subsequent time it is run, it pops the top-of-stack and pushes a copy of the value saved in the cache.

It is undefined behaviour for `|` to be executed when the stack is empty.

### Addition
The `+` command pops two integers or two lists of integers from the stack, adds them (elementwise in the case of two lists), then pushes the result.

Implementations are free to add the values in any order they choose. However, they should be forewarned that addition is commutative, meaning the implementator's choice is just as meaningless as every other choice they make in their lives.

### Reverse Factorisation
The `*` pops integers or two lists of integers from the stack, and pushes their product or elementwise product, respectively.

Again, implementations may left-multiply or right-multiply. It's their prerogative. Commutativity of multiplication is left as an exercise to the reader.

### Bounce
When the `!` command is run, if the value at top-of-stack is an integer, the interpreter jumps to the next `!`. Otherwise, if the value at top-of-stack is a list or a string, the command is treated as a no-op. It is undefined behaviour for a program to have an odd number of `!`.

The value at top-of-stack is not popped. It is undefined behaviour to run `!` if the stack is empty, or for the interpreter to try to jump to the next `!` when there are not more left.

### Compare
The `-` command pops two integers from the stack and pushes the max of the two integes, then pushes the negative of the min of the two integers. If the first value popped is a list rather than an integer, no second value is popped. Instead, every integer in the list is replaced with 1, 0 or -1 corresponding to if it is positive, zero, or negative, respectively, then the resulting list is pushed again.

Maximum picks closest to ∞ and minimum picks closest to 0.

### Factorial
The `?` command performs a factorial operation on the integer at top-of-stack. If you are wondering why the symbol isn't `!`, it's because that symbol was taken.

It is undefined behaviour for `?` to be run on a string or list, or for the integer to be negative.

### Pack
The `$` command checks if there are exactly W integers on the stack. If so, it pops those integers and pushes a list containing them. If not, that is undefined behaviour.

You can imagine it like having a stack filled with rabbits at nighttime, then when day breaks the rabbits go back to the warren (as long as there are exactly the right amount of rabbits) and the warren is pushed to the stack. It's like that.

### Division
The `/` command elementwise divides the list at top-of-stack by W, rounding down.

If the value at top-of-stack is a string or an integer rather than a list of integers, that is undefined behaviour.

### Input Request
To request input data to process, the programmer needs only leave a line with a lone `,` in it, which strikes me as awfully convenient. Don't you think?

### Eval
The `^` command pops a string from the stack, splits it by newlines, then runs each line of code sequentially. It is illegal for the string to contain a `.` instruction (though it may contain further `^` instructions).

Trying to execute an integer or a list is undefined behaviour.

Imagine that your string is actually a rabbit. Then running `^` causes that rabbit to be popped from the stack and executed. Poor rabbit.

### Exec
The `@` command executes the commands from the first line of the source code. Note that many instructions may be executed in this way if they didn't have newlines following them pre-endorsement.

It is undefined behaviour for `@` to be placed on the first line of the source code.

### Transmogrification
The `~` command pops W lists from the stack and assembles a 2-d grid of integers, where if an integer is at position x of the y-th popped list, it is put at position (x, y-1). Then for each x coordinate χ starting from 0, the interpreter pushes a list of every integer on a grid point that satisfies x=χ, starting from y=0.

It may help understanding if you imagine that there are rabbits arranged in a little grid. (The rabbits are the contents of the popped lists.) Then the rabbits do a dance, and end up in the positions described above. Then the lines of rabbits are pushed onto the stack.

If any value pushed is not a list of integers, that is undefined behaviour.

### Random
The `%` command pops an integer or a list. If an integer is popped, a uniform random integer between 0 and that integer (inclusive) is pushed. If a list is popped, it is pushed shuffled.

Should a negative integer be popped this way, the behaviour is undefined.

### Increment
The `<`...`>` command increments a series of indices. Between the `<` and `>` are a sequence of whitespace-separated non-negative integers. For each number from left to right, the corresponding array element at that index is increased by 1.

### Semantic comments
The `=` command is a little like a macro. It inserts the text of the first comment in the source code into the program at the position of the `=`, uncommented.

It is undefined behaviour for `=` to come before the first comment in the program.

Fun animal fact: the `=` sign looks like two rabbit ears!

## Endorsements and Awards
The following instructions are certified and endorsed by the Rabbitsfoot Lucky-Paw Seal of Approval (RLPoA):
### Arithmetic operators
These symbols deserve respect for their longstanding contribution to the buttons on calculators.
- `+`
- `*`
- `/`
### Other brainfuck symbols
These symbols have contributed meaningfully to the history of esolangs.
- `,`
- `.`
- `[`...`]`
- `<`...`>`
### Who knows really
These symbols are financial benefactors of the Rabbitsfoot programming language.
- `~`
- `|`
- `!`
- `?`

The symbol `-` has received an *honorary* endorsement in appreciation of its substantial contributions to `[`...`]` and to arithmetic. Due to a technicality, `-` alas cannot receive implicit newline privileges, but was awarded a small cash koha instead.

## Rabbitsfoot library modules
Files with the `.rtfm` extension are treated as Rabbitsfoot library modules rather than programs. Rabbitsfoot library modules are executed as if they were programs.
rabbitsfoot.py ASCII text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import pathlib
import itertools
import sys

def cmp(a, b):
    # taken from https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
    return (a > b) - (a < b)

def flip(x):
    # transposes
    return [list(row) for row in zip(*x, strict=True)]

def factorial(n):
    for i in range(1, n):
        n *= i
    return max(n, 1)

def is_comment(line):
    return line.startswith("#") or line.startswith("REM ")

# read command line arguments
if len(sys.argv) < 2:
    print("Please pass filename of code", file=sys.stderr)
    sys.exit(1)
verbose_mode = "-v" in sys.argv or "--verbose" in sys.argv
filename = sys.argv[-1]
code = pathlib.Path(filename).read_text()

if verbose_mode:
    # enable logging to stderr
    log = lambda *a, **k: print(*a, **k, file=sys.stderr)
else:
    # disable logging
    log = lambda *a, **k: None

# read list of integers from stdin
data = [
    int(num)
    for num
    in input()
        .replace(",", " ")
        .strip("[ ]").split()
]

if not code.split("\n"):
    raise SyntaxError("Code has no lines")

# preprocessing
# replace all @ macros with the first line of the program
first_line = code.split("\n")[0]
if "@" in first_line:
    raise SyntaxError("`@` on first line of program")
code = code.replace("@", first_line)
# find first comment for the = command
for line in code.split("\n"):
    if is_comment(line):
        first_comment = line.lstrip("REM ").lstrip("#")
        break
    if "=" in line:
        raise SyntaxError("`=` before first comment")
else:
    first_comment = ""
# remove comments
code = "\n".join(
    line
    for line
    in code.split("\n")
    if not is_comment(line)
)
# insert macros from first comment
if "=" in code:
    code = code.replace("=", first_comment)
# insert newlines after endorsed commands
endorsed = {"+", "*", "/", "~", "|", ",", ".","]", ">", "!", "?"}
for endorsement in endorsed:
    # insert newlines automatically
    code = code.replace(endorsement, endorsement + "\n")

# get window size
window_size = 1
for line in code.split("\n"):
    if line.startswith("[") and line.endswith("]"):
        # found a [...] line
        # so can infer size of window
        window_size = len(line.strip("[ ]").split())
        break
# otherwise default to 1
log(f"{window_size = }")

stack = []
cache = None

ranges = [range(len(data)) for _ in range(window_size)]
for indices in itertools.product(*ranges):
    log(f"Iterating with {indices = }")
    for line in code.split("\n"):
        line = line.strip()
        log(f"  Runnning line: {line}")
        match line:
          case ",":
            # get input from array
            stack.append([data[i] for i in indices])
          case "*":
              # multiply
              top = stack.pop()
              second = stack.pop()
              match (top, second):
                case (int(), int()):
                    stack.append(top * second)
                case (list(), list()):
                    product = [x*y for x,y in zip(top, second, strict=True)]
                    stack.append(product)
                case _:
                    raise TypeError("Mixed-type multiplication is not supported")
          case "+":
              # add
              top = stack.pop()
              second = stack.pop()
              match (top, second):
                case (int(), int()):
                    stack.append(top + second)
                case (list(), list()):
                    summation = [x+y for x,y in zip(top, second, strict=True)]
                    stack.append(summation)
                case _:
                    raise TypeError("Mixed-type addition is not supported")
          case "?":
              # factorial
              top = stack.pop()
              if isinstance(top, int):
                  if top < 0:
                      raise ValueError("Attempted factorial on negative number")
                  product = factorial(top)
                  stack.append(product)
              else:
                  raise TypeError("Factorial on something other than an integer")
          case "-":
              # get max/min of two ints or elementwise get sign
              top = stack.pop()
              if isinstance(top, int):
                  second = stack.pop()
                  stack.append(max(top, second))
                  stack.append(-min(top, second), key=abs)
              else:
                  sign = [cmp(x, 0) for x in top]
                  stack.append(sign)
          case "|":
              # save/load memory
              if cache is None:
                  cache = stack[-1]
                  log(f" -cache set to {cache}")
              else:
                  stack.pop()
                  stack.append(cache)
          case "~":
              # flip about main diagonal
              rows = [stack.pop() for col in range(window_size)]
              cols = flip(rows)
              cols.reverse()
              stack.extend(cols)
          case "0":
              # push 0
              if indices == (0,) * window_size:
                  raise ValueError("Tried to execute `0` when index tuple was all zeros")
              elif len(data) == 0 and window_size == 0:
                  raise ValueError("Tried to execute `0` when window size and input size were both 0. Very dangerous!")
              else:
                  stack.append(0)
          case "$":
              # pack integers into list and push
              integers = []
              while stack:
                  next_integer = stack.pop()
                  if not isinstance(next_integer, int):
                      raise TypeError("Tried to pack non-integer into list of integers")
                  integers.append(next_integer)
              if len(integers) != window_size:
                  raise ValueError("Wrong number of popped integers")
              stack.append(integers)
          case "!":
              # conditional jump
              basic_count = code.replace(" ", "").replace("\t", "").count("\n!\n")
              if code.startswith("!") != code.endswith("!"):
                  basic_count += 1
              if basic_count % 2 == 1:
                  raise SyntaxError("Odd number of `!`")
              if isinstance(stack[-1], int):
                  # this code path shouldn't happen
                  raise NotImplementedError()
          case "^":
              # eval
              eval_code = stack.pop()
              if isinstance(code, str):
                  for eval_line in eval_code.split("\n"):
                      if eval_line == "":
                          continue
                      if eval_line.strip() == ".":
                          raise ValueError("Tried to execute a `.` within a `^` evaluation")
                      # this code path shouldn't happen
                      raise NotImplementedError()
              else:
                  raise TypeError("Tried to execute something other than a string")
          case "/":
              # divide
              top = stack.pop()
              quotient = [num // window_size for num in top]
              stack.append(quotient)
          case "%":
              # randomise
              top = stack.pop()
              match top:
                case int():
                    if top < 0:
                        raise ValueError("Random integer from empty set")
                    stack.append(random.randrange(0, top + 1))
                case list():
                    top = list(top)
                    random.shuffle(top)
                    stack.append(top)
          case x if x.startswith("[") and x.endswith("]"):
              # push literal
              values = [
                  int(num)
                  for num
                  in x.strip("[ ]").split()
              ]
              if len(values) != window_size:
                  raise SyntaxError("Literal does not match window size")
              stack.append(values)
          case x if x.startswith("<") and x.endswith(">"):
              # increment indices of array
              if "-" in x:
                  raise ValueError("Negative integer in indices to increment")
              values = [int(num) for num in x.strip("< >").split()]
              for index in values:
                  data[index] += 1
          case ".":
              # end program
              break
          #case ":":
          #    # deprecated duplicate
          #    top = stack.pop()
          #    stack.append(top)
          #    stack.append(top)
          #case ";":
          #    # deprecated swap
          #    top = stack.pop()
          #    second = stack.pop()
          #    stack.append(top)
          #    stack.append(second)
          case "":
              # empty line
              continue
          case _:
              raise SyntaxError(f"Got malformed line: {line}")
        log(f"  {stack = } <-TOS")
    else:
        # program didn't end with "."
        raise SyntaxError("Program does not contain a `.` instruction")
    # this iteration, we replace all chosen values
    # with new values calculated by the program
    new_values = stack.pop()
    log(f"Replacing values at indices {indices} with {new_values}")
    for index, value in zip(indices, new_values, strict=True):
        data[index] = value
    log(f"{cache = }")
    log(f"{data = }")
    log()

print(data)
log()
log("---")
log("Program terminated successfully.")

Entry #2

Written by olus2000

interpreter.py ASCII text, with CRLF line terminators
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from sys import argv

'''
list -> quotation
int -> number
str -> operator
'''


# Will break on 999-deep nested quotations, but I think that's reasonable.
def parse_program(p: str, i: int = 0) -> (list, int):
    program = []
    while i < len(p) and p[i] != ']':
        if p[i] in '~!+':
            program.append(p[i])
        elif p[i] == '[':
            start = i
            quote, i = parse_program(p, i + 1)
            if i >= len(p) or p[i] != ']':
                raise Exception(f'Unclosed quotation at {start}')
            program.append(quote)
        i += 1
    return program, i

def parse_input():
    return [int(s) for s in input().split()]


# When popping two items 'a' will be the leftmost value, 'b' the rightmost.
def reduce(p, dat):
    ret = [p]
    ip = [0]
    while ret:
        if ip[-1] >= len(ret[-1]):
            ret.pop()
            ip.pop()
        else:
##            print(ret, ip, dat, sep='\n')
##            print()
            com = ret[-1][ip[-1]]
            ip[-1] += 1
            match com:
                case int() as i:
                    dat.append(i)
                case list() as q:
                    dat.append(q)
                case '~':
                    if len(dat) > 1:
                        match dat.pop(), dat.pop():
                            case int(a), int(b):
                                if a < b:
                                    dat.append(a)
                                    dat.append(b)
                                else:
                                    dat.append(b)
                                    dat.append(a)
                            case a, b:
                                dat.append(a)
                                dat.append(b)
                case '!':
                    if len(dat) < 2 or not isinstance(dat[-1], list):
                        dat = []
                    else:
                        a, b = dat.pop(), dat.pop()
                        ret.append(a)
                        ip.append(0)
                case '+':
                    if len(dat) < 2 or not isinstance(dat[-1], list):
                        dat = []
                    else:
                        a, b = dat.pop(), dat.pop()
                        dat.append([b] + a)
                        dat.append(a + [b])
                case _:
                    raise Exception(f'Unexpected item in the program: {com}')
    ans = []
    for i in reversed(dat):
        if isinstance(i, int):
            ans.append(i)
        else:
            break
##    print(ans)
##    print(dat)
    return list(reversed(ans))


if __name__ == '__main__':
    if len(argv) != 2:
        raise Exception(f'Wrong number of arguments: {len(argv) - 1}')
    with open(argv[1], 'r') as f:
        program, _ = parse_program(f.read())
    out = reduce(program, parse_input())
    for i in out:
        print(i, end=' ')
    print()
                
specs.md ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Stack sorter

Stack sorter is a concatenative language based on the concatenative calculus.
It operates via the means of expression rewriting.
Expressions may consist of:
    - operators
    - quotations
    - numbers (only during runtime, not representable in code)


### Operation

The program is parsed into an expression according to the rules explained
below. Input is parsed as a string of whitespace-separated decimal numbers
ending in a newline and prepended to the expression. Any parsing errors may
produce undefined behavior.

The expression is scanned for patterns related to words. The right-most
match is replaced with another expression according to the rule for that
pattern. This match-replace cycle is repeated until there are no matches.

Trailing numbers in the resulting expression are the output of the program.
Only numbers that are outside quotations count for output.


### Operators and patterns

IMPORTANT: patterns don't match within quotations.

There are several words that can be used in the stack sorter, every one
coming with a pattern and a substitution rule. In the examples letters
`X` and `Y` represent arbitrary quotations or numbers, letters `N` and `M`
represents numbers and letter `A` represents an arbitrary expression.
Spaces represent any non-zero number of whitespace delimiters.

    - `NM~`   -> `NM`      if N <= M, else `MN`
    - `XY~`   -> `YX`      if X or Y is not a number, else the rule above matches.
    - `X~`    -> `X`      if previous two rules didn't match.
    - `X[A]+` -> `[XA][AX]`
    - `X[A]!` -> `A`

Any characters except `[]~!+` in the program are discarded.


### Quotations

In code quotations are represented as expressions in brackets: `[]`.
Quotations can be manipulated using operators. Patterns don't match
inside quotations, and numbers contained within them don't count as
trailing numbers.

If brackets in the program don't match it's a parsing error which
produces undefined behavior.


### Examples

Program `[]![]+~!` with input `1 2` will output `1`.

I'm too lazy to write more.


### Interpreter

Interpreter expects one parameter: a file with the program. It will parse the program,
parse one line of input and print out the output if no errors occur.

Entry #3

Written by MattiDragon

README.md ASCII text, with CRLF line terminators
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Three Stack Bit Math
This esolang has three stacks; A, B and X. The first two, A and B, are used for data storage. A will automatically contain any command line arguments after the program name. X is used for calculations. 

The main logic will be performed using bit magic as comparison operators don't exist. Blocks can be used for limited conditional logic. I haven't confirmed, but it seems to me like this esolang isn't turing complete.

## Blocks
Blocks are the main conditional element in the language. The work by infinetly looping until a stack access is attempted on an empty stack. 

## Instructions
### Block
 * `{`: Opens a block
 * `}`: Closes a block

### Constants
 * `0`: Loads the constant 0 to the X 
 * `1`: Loads the constant 1 to the X 

### Move
 * `a`: Moves one value from A to X
 * `b`: Moves one value from B to X
 * `c`: Moves one value from X to A
 * `d`: Moves one value from X to B
 * `e`: Copies all values from B to A
 * `f`: Copies all values from A to B
 * `g`: Reverses A
 * `h`: Reverses B

### Misc
 * `!`: Pops one value from X
 * `%`: Swaps the top two values of X
 * `.`: Pops and prints the top value of X
 * `$`: Dupelicates the top value of X

### Math and Bit Magic
 * `+`: Adds together the top two values of X
 * `&`: Performs a bitwise AND operation on the top two values of X
 * `|`: Performs a bitwise OR operation on the top two values of X
 * `^`: Performs a bitwise XOR operation on the top two values of X
 * `-`: Performs a bitwise NOT operation on the top value of X
 * `<`: Performs a bitshift left on the top two values of X
 * `>`: Performs a bitshift right on the top two values of X

### Debug
 * `@`: Forces the program to exit
 * `=`: Dumps the stacks' contents

## Usage
Run the interpretter using python 3.10 or newer with the program as the first argument and the data as the rest
interpretter.py ASCII text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
import sys

INSTRUCTIONS = list("abcdefgh01!%.+&|^-<>$=@")

Program = list[str | type("Program")]
Stacks = tuple[list[int], list[int], list[int]]

class ExecutionError(RuntimeError):
    pass

def main():
    filename, *data = sys.argv[1:]
    try:
        with open(filename, "r") as file:
            program = compile(file.read())
        run(program, [int(value) for value in data])
    except ExecutionError as e:
        print("Error while executing:", e)
        sys.exit(2)

def compile(program: str) -> Program: 
    stack: list[Program] = [[]]

    for char in program:
        if char in INSTRUCTIONS:
            stack[-1].append(char)
        elif char == "{":
            stack.append([])
        elif char == "}":
            stack[-2].append(stack.pop())
    if len(stack) > 1:
        raise ExecutionError("Not all blocks closed!")
    return stack[0]
    
def run(program: Program, data: list[int]):
    run_block((data, [], []), program, main=True)
    
def run_block(stacks: Stacks, block: Program, main: bool = False):
    a, b, x = stacks
    index: int = 0
    max_index = len(block) - 1
    try:
        while True:
            #print("Executing:", block[index], stacks)
            match block[index]:
                case "a":
                    x.append(a.pop())
                case "b":
                    x.append(b.pop())
                case "c":
                    a.append(x.pop())
                case "d":
                    b.append(x.pop())
                case "e": # Copy content only, no changing references
                    a[:] = b[:]
                case "f": # Copy content only, no changing references
                    b[:] = a[:]
                case "g":
                    a.reverse()
                case "h":
                    b.reverse()
                case "0":
                    x.append(0)
                case "1":
                    x.append(1)
                case "!":
                    x.pop()
                case "%":
                    x += (x.pop(), x.pop())
                case ".":
                    print(x.pop())
                case [*content]:
                    run_block(stacks, content)
                case "+":
                    x.append(x.pop() + x.pop())
                case "&":
                    x.append(x.pop() & x.pop())
                case "|":
                    x.append(x.pop() | x.pop())
                case "^":
                    x.append(x.pop() ^ x.pop())
                case "-": # Bitwise not, not mathematical negation
                    x.append(~x.pop())
                case ">": # Because of the stack, the order is reversed. For these operations order matters
                    second, first = x.pop(), x.pop()
                    x.append(first >> second)
                case "<":
                    second, first = x.pop(), x.pop()
                    x.append(first << second)
                case "$":
                    x.append(x[-1])
                case "=":
                    print("Stacks:", *stacks)
                case "@":
                    raise ExecutionError("Debug exit")

            if index >= max_index:
                if main: 
                    return
                index = 0
            else:
                index += 1
    except IndexError as e:
        if main:
            raise ExecutionError("Index out of bounds in main body!") from e

if __name__ == "__main__":
    main()
tsbm_io.txt ASCII text
1
The integers are passed as arguments to the interpreter, placing them on the A stack. The integers are printed using the `.` operator in sorted order.

Entry #4

Written by SoundOfSpouting

build.sh ASCII text
1
gcc -o interpreter interpreter.c
compiler.py ASCII text
1
2
3
4
5
6
7
#!/usr/bin/python3

# // Code by SoundOfSpouting#6980 (UID: 151149148639330304)
# Supplementary program for interpreter, compiles ordered pairs (a, b)(c, d) or list [1, 2, 3, 4] into raw bytes
# Usage: ./compiler.py [input file] [output file]

import sys;import re;open(sys.argv[2],"wb").write(bytes(map(int,re.sub("[^0123456789\s]","",re.sub("[\[\]{}(),]", " ", open(sys.argv[1],"r").read())).split())))
interpreter.c ASCII text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// Code by SoundOfSpouting#6980 (UID: 151149148639330304)
// Usage: interpreter.exe [input file] [program file]

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

const int debug = 0;

int randInt (int m, int M) {
	return 4; // stub
}
void doBetter () {
	puts ("Please Just Do Better");
	exit (randInt (1, 69420));
}

void printList (int* list, int length) {
	printf ("[");
	for (int i = 0; i < length - 1; i++) printf("%d, ", list[i]);
	if (length < 1) puts ("]");
	else printf ("%d]\n", list[length - 1]);
}
void printDisks (int** disks, int* tops, int pegs) {
	puts ("{");
	for (int i = 0; i < pegs; i++) {
		printf ("    %d ", i);
		printList (disks[i], tops[i] + 1);
	}
	puts ("}");
}

int listToDisks (const int* list, const int length, int*** _disks, int** _tops) {
	int pegs = 2;
	for (int i = 0; i < length - 1; i++) if (list[i] > list[i + 1]) pegs++;

	int** disks = (int**) malloc (pegs * sizeof (int*));
	int* tops = (int*) malloc (pegs * sizeof (int));
	for (int i = 0; i < pegs; i++) {
		tops[i] = -1;

		disks[i] = (int*) malloc (length * sizeof (int));
		for (int j = 0; j < length; j++) disks[i][j] = -1; // Not necessary
	}

	int i = pegs - 2, j = 0;
	for (int k = length - 1; k > 0; k--) {
		disks[i][j] = list[k];
		if (list[k-1] > list[k]) {
			tops[i] = j;
			i--;
			j = 0;
		} else j++;
	}
	disks[i][j] = list[0];
	tops[i] = j;

	*_disks = disks;
	*_tops = tops;
	return pegs;
}
void disksToList (int* list, int** disks, const int* tops, const int pegs) {	
	for (int j = 0; j < pegs; j++) for (int k = tops[j]; k >= 0; k--) (list++)[0] = disks[j][k];
}
int move (int** disks, int* tops, const int pegs, const int length, int i, int j) {
	i = i % pegs;
	j = j % pegs;

	if (i == j || tops[i] < 0 || tops[j] > length - 2 || tops[j] > -1 && (disks[i][tops[i]] > disks[j][tops[j]])) return 0;

	tops[j]++;
	disks[j][tops[j]] = disks[i][tops[i]];
	disks[i][tops[i]] = -1; // Not necessary
	tops[i]--;

	return 1;
}

int loadBytes (char* file, int** _list) {
	FILE* fp = fopen (file, "rb");
	if (fp == NULL) doBetter ();

	fseek (fp, 0, SEEK_END);
	const int length = ftell (fp);
	fseek (fp, 0, SEEK_SET);

	int* list = (int*) malloc (length * sizeof (int));
	for (int i = 0; i < length; i++) list[i] = fgetc (fp);
	fclose (fp);

	*_list = list;
	return length;
}

void execute (int* list, int length, int* program, int programLength) {
	if (debug > 5) printList (list, length);

	int** disks;
	int* tops;
	const int pegs = listToDisks (list, length, &disks, &tops);

	if (debug > 6) printDisks(disks, tops, pegs);

	for (int i = 0; i < programLength - 1; i += 2) {
		int s = move (disks, tops, pegs, length, program[i], program[i+1]);
		if (debug > 7) {
			printf ("(%d, %d)%s\n", program[i], program[i+1], s ? "" : " invalid");
			if (s) printDisks (disks, tops, pegs);
		}
	}

	disksToList (list, disks, tops, pegs);

	for (int i = 0; i < pegs; i++) free (disks[i]);
	free (disks);
	free (tops);
}
int isSorted (int* list, int length) {
	int sorted = 1;
	for (int i = 0; i < length - 1; i++) if (list[i] > list[i+1]) {
		sorted = 0;
		break;
	}
	return sorted;
}
void sort (int* list, int length) {
	for (int i = 0; i < length; i++) for (int j = 0; j < length; j++) if (list[i] < list[j]) {
		int x = list[i];
		list[i] = list[j];
		list[j] = x;
	}
}

int* tests[] = {
	(int[]) {},
	(int[]) {172},
	(int[]) {203, 35},
	(int[]) {18, 13, 94},
	(int[]) {193, 46, 26, 129},
	(int[]) {77, 108, 182, 111, 242},
	(int[]) {88, 159, 106, 233, 87, 30},
	(int[]) {151, 106, 165, 236, 180, 249, 113},
	(int[]) {117, 238, 17, 93, 165, 76, 166, 15},
	(int[]) {115, 7, 181, 141, 13, 205, 86, 231, 135},
	(int[]) {118, 23, 77, 47, 177, 48, 15, 111, 25, 75},
	(int[]) {106, 220, 114, 44, 57, 117, 169, 56, 198, 109, 165},
	(int[]) {30, 15, 164, 86, 18, 200, 93, 145, 224, 249, 134, 160},
	(int[]) {167, 230, 10, 83, 226, 93, 97, 218, 98, 51, 115, 236, 94},
	(int[]) {248, 106, 26, 120, 32, 72, 218, 78, 178, 37, 76, 15, 137, 218},
	(int[]) {214, 158, 209, 243, 75, 148, 216, 195, 223, 137, 169, 90, 142, 109, 1}
};
void TRAILS (int* list, int length, int** subprograms, int* subprogramsLengthJ, int subprogramsLengthI) {
	const int requiredComplete = 3;

	int** cases[] = {
		(int*[]) { (int[]) {2,3,0,1}, (int[]) {1,3,0,2}, (int[]) {1,2,0,3}, (int[]) {0,3,1,2}, (int[]) {0,2,1,3} },
		(int*[]) { (int[]) {0,0,1,0,0}, (int[]) {0,1,0,1,0}, (int[]) {0,1,1,1,0}, (int[]) {0,1,2,1,0}, (int[]) {0,2,1,2,0}, (int[]) {1,0,0,0,1}, (int[]) {1,0,1,0,1}, (int[]) {1,0,2,0,1}, (int[]) {1,1,0,1,1}, (int[]) {1,2,0,2,1}, (int[]) {2,0,1,0,2}, (int[]) {2,1,0,1,2} },
		(int*[]) { (int[]) {} }
	};
	int* casesLengthK[] = {
		(int[]) {4,4,4,4,4}, (int[]) {5,5,5,5,5,5,5,5,5,5,5,5}, (int[]) {0}
	};
	int casesLengthJ[] = {5,12,1};
	int casesLengthI = 3;

	int randCase = randInt (0, 14);
	cases[2][0] = tests[randCase];
	casesLengthK[2][0] = randCase;
	
	int complete = 0;
	for (int i = 0; i < casesLengthI && i < subprogramsLengthI; i++) {
		if (debug > 4) printf ("TRAIL %d Begins\n", i);
		int flag = 1;
		for (int j = 0; j < casesLengthJ[i]; j++) {
			for (int k = i; k >= 0; k-=2) execute (cases[i][j], casesLengthK[i][j], subprograms[i], subprogramsLengthJ[i]);
			for (int k = i; k >= 0; k-=2) {
				if (debug > 5) {
					printf(" :: ");
					printList (cases[i][j], casesLengthK[i][j]);
				} if (!isSorted (cases[i][j], casesLengthK[i][j])) {
					if (debug > 4) printf ("You Have Failed TRAIL %d\n", i);
					flag = 0;
					break;
				}
			}
			if (flag == 0) break;
			if (i > 1) {
				execute (subprograms[i], subprogramsLengthJ[i], subprograms[i], subprogramsLengthJ[i]);
				if (debug > 5) {
					printf(" :: ");
					printList (subprograms[i], subprogramsLengthJ[i]);
				} if (!isSorted (subprograms[i], subprogramsLengthJ[i])) {
					if (debug > 4) printf ("You Have Failed TRAIL %d\n", i);
					flag = 0;
					break;
				}
			}
			if (flag == 0) break;
		}
		if (flag) {
			if (debug > 4) printf ("You Have Passed TRAIL %d\n", i);
			complete++;
		}
	}
	if (debug > 4) for (int i = subprogramsLengthI; i < casesLengthI; i++) printf ("You Have Failed TRAIL %d By Default\n", i);

	if (complete >= requiredComplete) {
		if (debug > 4) puts ("You Have Completed The TRAILS\nThe Input Will Now Be Sorted");
		sort (list, length);
	} else if (debug > 4) printf ("You Have Not Completed Enough TRAILS\nPlease Complete %d More TRAILS", requiredComplete - complete);
	return;
}
int main (int argc, char** argv) {
	if (argc != 3) doBetter ();

	int* list;
	const int length = loadBytes (argv[1], &list);

	int* program;
	const int programLength = loadBytes (argv[2], &program);

	if (programLength > 100) doBetter ();

	if (program[0] == 255) {
		if (debug > 5) printList (list, length);
		if (debug > 4) puts ("TRAILS MODE ENGAGED");

		int subprogramsLengthI = 0;
		for (int i = 0; i < programLength; i++) if (program[i] == 255) subprogramsLengthI++;

		int** subprograms = (int**) malloc (subprogramsLengthI * sizeof (int*));
		int* subprogramsLengthJ = (int*) malloc (subprogramsLengthI * sizeof (int));
		
		int j = programLength - 1, k = subprogramsLengthI - 1;
		for (int i = j; i >= 0; i--) if (program[i] == 255) {
			subprograms[k] = program + i + 1;
			subprogramsLengthJ[k] = (j - i);
			k--;
			j = i - 1;
		}
		
		TRAILS (list, length, subprograms, subprogramsLengthJ, subprogramsLengthI);

		free (subprograms);
		free (subprogramsLengthJ);
	} else execute (list, length, program, programLength);

	printList (list, length);

	int notSorted = 1 - isSorted (list, length);
	if (notSorted && debug > 5) {
		puts ("Not Sorted!");
		if (debug > 8) {
			sort (list, length);
			printList (list, length);
		}
	}

	free (list);
	free (program);
	return notSorted;
}
run.sh ASCII text
1
2
3
./compiler.py ${1-inp.HNI} inp.BIN &&
./compiler.py ${2-prg.HNI} prg.BIN &&
./interpreter inp.BIN prg.BIN
specification.txt ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
The program inputs a list of integers from 0 to 255 (represented as bytes from the first file provided)
The last line of output will be a visual representation of the same list but with elements in a different order (e.g. \x02\x00\x01\x03 -> [0, 1, 2, 3])

A program is a sequence of integers from 0 to 255 (represented as bytes from the second file provided)
There may be at most 100 integers

If the program starts with the value 255, see the TRAILS section
Otherwise, the following occurs:
  The input list of integers is converted into an array of pegs, each of which holds a stack of disks (integers)
  In each peg, disks must be sorted in strictly-not-ascending order at all times
  The list is split into consecutive strictly-not-descending sub-lists, and sub-lists are placed into consecutive pegs from top to bottom
  There will be an empty peg after all of the sub-lists are placed

  For each pair of integers in the program (x, y) in order, the top disk from peg x is attempted to be moved to the top disk of peg y, where x and y are modulo the number of pegs
  Any extra integer not in a pair is ignored
  After the program is executed, the list is reconstructed - for each peg in order, all disks from top to bottom are added to the list

Example program - sorts the list [193, 46, 26, 129] or \xc1\x2e\x1a\x81
  (0, 3)(2, 0)
  \x00\x03\x02\x00

TRAILS
  There are many TRAILS (challenges) that a program can solve. It if solves at least all 3 of them, the input list is sorted automatically for you! Isn't that just dandy?
  The first 255 value is removed from the program, and the remaining values are split over the value 255 into several sub-programs
  Each sub-program corresponds to one TRAIL. The sub-program is executed with some inputs, and the outputs must all be sorted. A sub-program may be empty

  TRAIL 0. SMALL BLIND.
    This TRAIL requires you to sort all lists [a, b, c, d] where a < b > c < d
  TRAIL 1. BIG BLIND.
    This TRAIL requires you to sort all palindromes of length 5
  FINAL TRAIL.
    This TRAIL requires you to sort a random list from the test cases. Muahahaha
    Also your sub-program will be run twice
    And then the sub-program is run on itself and must sort itself

Entry #5

Written by firecubez

slay.md ASCII text, with very long lines (426)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# SLAY Specification

## SLAY Programs

Programs consist of a sequence of bytes.

## Execution
To execute, programs are hashed using the SHA3-512 algorithm. The next step depends on the architecture.

On x86_64:
- The resulting 64 byte array is XORed by the following byte array: `[182, 18, 146, 93, 235, 245, 110, 160, 61, 229, 102, 93, 222, 36, 70, 4, 240, 1, 32, 73, 205, 58, 249, 12, 229, 165, 212, 84, 66, 121, 185, 174, 150, 114, 145, 83, 200, 55, 190, 107, 182, 154, 30, 162, 176, 113, 56, 59, 64, 212, 77, 228, 146, 113, 70, 178, 97, 57, 34, 103, 220, 225, 38, 154]`. To XOR 2 arrays, each item `i` in `a` is set to `a[i] ^ b[i]`.
- The result is interpreted as a x86_64 machine code function in the Microsoft x64 calling convention (even on other platforms) with 2 arguments. The first argument is a pointer to the input and the second argument is the length of the input. The signature is as follows: `void(char*, int)`.
- This function is called with the proper arguments.

On ARM64:
- The resulting 64 byte array is XORed by the following byte array: `[10, 236, 147, 82, 232, 79, 111, 244, 28, 237, 39, 188, 219, 100, 204, 193, 117, 254, 101, 72, 32, 56, 188, 158, 10, 219, 88, 66, 232, 109, 248, 210, 132, 182, 149, 226, 219, 54, 66, 72, 192, 90, 39, 52, 202, 174, 253, 237, 163, 160, 159, 30, 32, 229, 214, 27, 208, 173, 178, 102, 115, 113, 178, 225]`. The method of XORing is described above.
- The result is appended to a list C.
- The result of the XOR is XORed again with the following byte array: `[222, 250, 255, 37, 168, 252, 255, 96, 225, 11, 95, 135, 4, 4, 0, 145, 132, 0, 1, 139, 225, 3, 0, 170, 37, 0, 128, 82, 34, 0, 64, 57, 35, 4, 64, 57, 95, 0, 3, 107, 137, 0, 0, 84, 5, 0, 128, 82, 35, 0, 0, 57, 34, 4, 0, 57, 33, 4, 0, 145, 63, 0, 4, 235]`.
- The first twelve bytes of the result are appended to the end of list C.
- The bytes of list C are interpreted as an ARM64 machine code function in the C calling convention with 2 arguments, as above.
- This function is called with the proper arguments.

After this, the (now modified) input is printed to standard output.
slay.rs ASCII text, with very long lines (310)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use sha3::Digest;
use std::{fs, env};

fn main() {
	let mut args = env::args();
	args.next();
	let program = fs::read(args.next().unwrap()).unwrap();
	let mut input = args.next().unwrap()
		.split(",")
		.map(|x| x.parse::<u8>().unwrap())
		.collect::<Vec<_>>();
	let mut h = sha3::Sha3_512::new();
	h.update(&program);
	let mut r = h.finalize();
	let r = &mut r[..];
	let carve;
	#[cfg(target_arch = "x86_64")] {
		x(r, &[182, 18, 146, 93, 235, 245, 110, 160, 61, 229, 102, 93, 222, 36, 70, 4, 240, 1, 32, 73, 205, 58, 249, 12, 229, 165, 212, 84, 66, 121, 185, 174, 150, 114, 145, 83, 200, 55, 190, 107, 182, 154, 30, 162, 176, 113, 56, 59, 64, 212, 77, 228, 146, 113, 70, 178, 97, 57, 34, 103, 220, 225, 38, 154]);
		let mut cartography = memmap2::MmapMut::map_anon(r.len()).unwrap();
		cartography.copy_from_slice(r);
		carve = cartography.make_exec().unwrap();
		unsafe {
			std::mem::transmute::<_, extern "win64" fn(*mut u8, u32)>(carve.as_ptr())(input.as_mut_ptr(), input.len() as u32);
		}
	};
	#[cfg(target_arch = "arm64")] {
		x(r, &[10, 236, 147, 82, 232, 79, 111, 244, 28, 237, 39, 188, 219, 100, 204, 193, 117, 254, 101, 72, 32, 56, 188, 158, 10, 219, 88, 66, 232, 109, 248, 210, 132, 182, 149, 226, 219, 54, 66, 72, 192, 90, 39, 52, 202, 174, 253, 237, 163, 160, 159, 30, 32, 229, 214, 27, 208, 173, 178, 102, 115, 113, 178, 225]);
		let mut cartography = memmap2::MmapMut::map_anon(76).unwrap();
		cartography[..64].copy_from_slice(r);
		x(r, &[222, 250, 255, 37, 168, 252, 255, 96, 225, 11, 95, 135, 4, 4, 0, 145, 132, 0, 1, 139, 225, 3, 0, 170, 37, 0, 128, 82, 34, 0, 64, 57, 35, 4, 64, 57, 95, 0, 3, 107, 137, 0, 0, 84, 5, 0, 128, 82, 35, 0, 0, 57, 34, 4, 0, 57, 33, 4, 0, 145, 63, 0, 4, 235]);
		cartography[64..].copy_from_slice(r[..12]);
		carve = cartography.make_exec().unwrap();
		unsafe {
			std::mem::transmute::<_, extern "C" fn(*mut u8, u32)>(carve.as_ptr())(input.as_mut_ptr(), input.len() as u32);
		}
	}
	println!("{:?}", input);
}

fn x(s: &mut [u8], b: &[u8]) {
	for (a, b) in s.iter_mut().zip(b) {
		*a ^= *b;
	}
}

Entry #6

Written by Ardemit

docs.txt Unicode text, UTF-8 text, with CRLF line terminators
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
Psst. You can read a nicely formatted version of this document here -> https://esolangs.org/wiki/Rings

Rings is a simple programming language designed around the idea of working with rotating memory strips.

# Language overview
The language revolves around turnable rings of varying length (or capacity if you want to picture them as all being the same size). Each ring can store up to 255 unsigned 8 bit integers
(but cannot be zero-length) and can rotate counter-clockwise up to 255 steps at once (rotary right shift). == NB: Due to a bug in the interpreter, this is not accurate. See below. ==
All operations working with values stored on the rings only use the currently selected value, usually represented on a state diagram as being the leftmost value on the ring.
Imagine looking at a vertical rod, on which the rings are stacked. You are the interpreter and can only see the values in front of you. If you want to access other ones, you need to
rotate the rings around. There can be at most 256 rings.

The language's interpreter represents a ring as a list of integers along with an index representing where the current value is. To rotate a ring of length L by N steps, the new value of the index
should be (index+N)%L. However, there is a bug in the source code that causes this math to be done with integers that are too small. The end result is that the new value of the index becomes
((index+N)%256)%L instead. This causes rotations to act erroneously in some cases. It also means that the current value of the index, which should be a mere implementation detail, affects the result.

## Table of instructions
Arguments are represented in the form <number of arguments><signed: i, unsigned: u><number of bits> – similar to Rust.
| HumanRings  Rings      Arguments  Description
| mkr         0x0        1u8        Creates a new ring. The argument specifies the length.
| put         0x1        2u8        The first argument specifies a ring, the second a literal value, that will be put onto said ring.
| rot         0x2        2u8        The first argument specifies a ring, the second a literal value, that will tell the ring how many steps to rotate.
| swp         0x3        2u8        Both arguments represent rings. The values of these rings will be swapped.
| inp         0x4        1u8        Reads a value from stdin and puts it onto the ring specified by the argument.
| out         0x5        1u8        Writes the value on the ring specified by the argument to stdout.
| err         0x6        1u8        Writes the value on the ring specified by the argument to stderr.
| add         0x7        3u8        All arguments represent rings. Add the values of the first two rings and put them onto the third. (A+B=C)
| sub         0x8        3u8        All arguments represent rings. Subtract the second ring's value from the first ring's value and put them onto the third. (A-B=C)
| mul         0x9        3u8        All arguments represent rings. Multiply the values of the first two rings and put them onto the third. (A*B=C)
| div         0xA        3u8        All arguments represent rings. Divide the first ring's value by the second ring's value and put them onto the third. (A/B=C)
| jmp         0xB        1u16       The argument is an instruction pointer, that the compiler unconditionally jumps to.
| jeq         0xC        2u8 1u16   The first two arguments represent rings, the third an instruction pointer. If the ring's values are equal, jump to the pointer. (A=B)
| jgt         0xD        2u8 1u16   The first two arguments represent rings, the third an instruction pointer. If the first ring's value is greater than the second ring's, jump to the pointer. (A>B)
| jlt         0xE        2u8 1u16   The first two arguments represent rings, the third an instruction pointer. If the first ring's value is less than the second ring's, jump to the pointer. (A<B)
| hlt         0xF        1u8        Halts the program, with the argument representing an exit code literal. Special behavior with the argument being 0xFE and 0xFF.

## The hlt instruction
The hlt instruction has special behavior when it's argument is 0xFE (254) or 0xFF (255). In all other cases, the argument simply represents the program's exit code. The two special cases are used for
debugging purposes and shouldn't be included in programs intended for release. When the compiler encounters either of these instructions, it prints the current Rings working environment to the default
terminal, regardless of the intended method of handling stdout. Specific purpose interpreters can ignore this special behavior. The interpreter starts with the first ring (index 0) and continues up,
printing one ring per line in the following format:

 0x<ring index>: (+<ring rotation offset>)[<selected value>][<previous value>]<..>[<next value>]

Example 'hlt 254' output at one point during the execution of a sorting program (all numbers are in hex):

 0x00: (+00)[FF][FF][FF][D6][D8][DF][F3][FF][FF][FF][FF][FF][FF][FF][FF]
 0x01: (+00)[08][00]
 0x02: (+01)[0F][01][0C]
 0x03: (+08)[00][D1][C3][A9][9E][94][89][5A][4B][00][00][00][00][00][00]

The only difference between 'hlt 254' and 'hlt 255' is that 'hlt 255' halts and returns 255 as exit code, while 'hlt 254' continues with execution and is useful to debug loops for example.

## Source code structure
The competition imposed several restrictions on the language, on of them being, that a program sorting a list of integers must be 100 bytes at a maximum. As such, readability has been sacrificed for
compression.

Rings uses '.rn' files as the source code. The entire file is in Big-endian. Since the instruction opcodes are only 4 bits, the first byte contains two instruction opcodes. The first 4 bits represent
the instruction that is executed first (first instruction). The second instruction are the remaining 4 bits.

 instr1 = byte & 0b1111;
 instr2 = byte >> 4;

Following are the arguments for the first instruction, then the second instruction. Since the interpreter knows how many arguments the instructions take, there is no terminator at the end of a block.
Consider this Rings source code (each pair represents a byte):

 10 08 00 05

Because programming directly in native Rings would be very difficult, there is a human-readable variant called HumanRings that compiles into native Rings source code. The code above can be represented
in HumanRings as:

 mkr 8
 put 0 5

## HumanRings
HumanRings is a dialect of Rings that is meant to be programmed in by humans and compiles into Rings source code that the interpreter can execute. A HumanRings compiler should be included standard with
general purpose Rings interpreters. HumanRings programs should use the '.hrn' file extension, but the file is written in plain text, so '.txt' can also be used.

In HumanRings, each line corresponds to a single instruction. Leading and trailing whitespaces are ignored, but arguments must be separated by a single regular space (U+0020). HumanRings use all the
instructions from native Rings as seen in the table above, but assign a human-readable three-letter name to each. In addition, there is a HumanRings exclusive instruction that declares labels. In native
Rings, jump instructions use 16 bit instruction pointers that represent a specific instruction index from the start of the file. If a programmer were to change the previous instructions, the pointer
(and all the ones that follow) would start pointing towards wrong instructions. Instead of this system, HumanRings use labels to mark specific instructions and use them in jump instructions instead of
absolute values.

Labels are defined using the ':' (colon) character, followed by the name of the label. Names must not contain any whitespaces, so ':lbl_test' is a valid label, but ': lbl_test' or ':lbl test' are not.
Jump instructions are then passed the label names (including the colon) instead of instruction pointers.

Literal values are defined using prefixes. Hexadecimal values can use both uppercase and lowercase characters, but the prefix must be lowercase.

| System        Prefix    Example     Decimal value
| Decimal                 182         182
| Hexadecimal   0x        0xB6        182
| Octal         0         0266        182
| Binary        0b        0b10110110  182

Any lines beginning with the '#' character are considered comments and are ignored.

Short HumanRings example program using all the rules described in this section:

 # Declare a ring for no reason and put 241 on it
 mkr 13
 put 0 0xF1

      # Still a comment. Leading and trailing whitespaces are removed!
   #Also, noone cares there isn't a space after the hashtag.
 # Infinite loop
 :go_here
 jmp :go_here

This program compiles into the following Rings source code:

 10 0D 00 F1 0B 00 02

## Computational class
Rings was meant to participate in the aforementioned competition. As such, there are several restrictions imposed upon it. One of them is, that it must be possible to write a program for sorting
lists of integers in under 100 bytes. For this reason, Rings is internally limited to 8 bit ring addresses, 8 bit ring lengths and 8 bit unsigned values.

If there weren't any of these restrictions and all of the aforementioned would be unbounded, Rings would be Turing complete. But since these restrictions are in place, Rings is much closer to being
a linear bounded automaton.

## Notable problems
* Rings doesn't have a straightforward way of handling EOF, because it only works with unsigned 8-bit integers and thus cannot distinguish what is a valid input and when EOF has been reached. In most
  cases, 0xFF should be considered EOF.
* Rings has no error handling mechanism, so the programmer must take care to handle all possible problems before executing instructions. One of the most common problems are invalid arithmetic operations,
  that would put an invalid value onto a ring.

## Example programs
All examples are written in HumanRings.

## Count 11 to 20
 mkr 1
 mkr 2
 put 0 10
 put 1 1
 rot 1 1
 put 1 20

 :loop
     rot 1 1
     add 0 1 0
     out 0
     rot 1 1
     jlt 0 1 :loop

## Cat
A simple cat program. Takes bytes until EOF (0xFF) and outputs them.

 mkr 1
 mkr 1

 put 1 0xFF

 :loop
     inp 0
     out 0
     jlt 0 1 :loop

## External resources
The author, has created an interpreter for Rings, that can be found at https://github.com/marekmiklenda/Rings.
impl.txt ASCII text
1
Rings is implemented at https://github.com/marekmiklenda/Rings.
rings_io.txt ASCII text
1
The interpreter uses standard IO for both input and output. The qualification program takes 8 bit unsigned integers (15 at most, one per byte) terminated by 0xFF and outputs them in ascending order, terminated by 0xFF.

Entry #7

Written by umnikos

job-offer-letter.txt ASCII text, with very long lines (777)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Hello there,

I am pleased to offer you the postion of Junior UwUmanic Engineer at UwUmanics Technologies. You will be starting on June 26th 2022 as per our agreement.

You have been assigned to work on one of our cutting edge uwuputers (uwumanic computer) that is still in active research and development. In case you are not familiar with those, they're a brand new type of computer that, unlike a quantum computer, can store an infinite amount of data in a single register! Our uwuputers have a whopping 8 registers to work with, more than those of any of our competitors.

As you haven't listed expertise in uwumanics on your resume and you might need a tl;dr before jumping into the books, here's a quick rundown of everything known in the field: A single register can either store a single integer (unbounded, so that alone can store an infinite amount of information) or a list. A list of what? Nobody knows, as the lists are completely unindexable. As the lists can be compared we think the items inside the lists can also be compared to each other. That would also mean that they can be sorted, but no one has been able to demonstrate that. The only things that have been done are merging two lists into one (the uwu operation) and splitting a list into two (the manic operation). The details of those I will leave it to you to familiarize with.


Please confirm your acceptance of this offer by signing and returning a copy of this letter to lyricly@uwumanics-tech.com

We look forward to welcoming you on board.

Sincerely,
Alex Stefanov
CEO
UwUmanics Technologies
uwumanics-for-dummies.py Unicode text, UTF-8 text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# name is short for "uwumanic computer"
#
# cheat sheet:
# 8 registers
# they can only store either a list of ??? or an integer (can be repurposed)
# assembly-like syntax with destination commonly being the first argument
#
# note for the jump instruction: instead of labels it accepts a line number,
# and the first line of the file is number 0.
# blank lines and comments also count as lines.

import sys

def uwu(first, second):
    assert(type(first) is list)
    assert(type(second) is list)
    res = []
    while True:
        if first == []:
            res += second
            return res
        if second == []:
            res += first
            return res
        if first[0] <= second[0]:
            res.append(first[0])
            del first[0]
        else:
            res.append(second[0])
            del second[0]

def manic(integer, array):
    assert(type(array) is list)
    assert(type(integer) is int)
    if integer<0:
        array = array[::-1]
        integer *= -1
    if integer > len(array):
        integer = len(array)
    return (array[:integer], array[integer:])

if __name__ == "__main__":
    filename = sys.argv[1]
    program = open(filename, 'r').read()
    lines = program.splitlines()
    instructions = [line.split() for line in lines]

    pc = 0
    registers = {}
    registers_count = 8
    for i in range(registers_count):
        # no uppercase for you.
        registers[chr(ord('a')+i)] = 0
    def get(s):
        try:
            return int(s)
        except:
            return registers[s]

    while True:
        #print(registers)
        ins = instructions[pc]
        if ins == []: # blank line, ignore
            pc += 1
            continue
        op = ins[0]
        # switch statements are only in python 3.10 and I have 3.9 #debianmoment
        if op == 'cmp' or op == 'compare' or op == '>': # works on arrays as well!
            a = registers[ins[1]]
            b = get(ins[2])
            c = get(ins[3])
            if b<c:
                registers[ins[1]] = -1
            elif b>c:
                registers[ins[1]] = 1
            else:
                registers[ins[1]] = 0
        elif op == 'jmp' or op == 'jump' or op == 'j':
            if len(ins) == 2: # unconditional jump
                a = get(ins[1])
                pc = a+0
            elif len(ins) == 4: # conditional jump
                a = get(ins[1])
                b = get(ins[2])
                c = get(ins[3])
                assert(type(a) is int)
                if a == 0:
                    pc = b+0
                else:
                    pc = c+0
            else:
                raise Exception("incorrect number of arguments to jump instruction")
            continue
        elif op == 'add' or op == '+':
            a = registers[ins[1]]
            b = get(ins[2])
            registers[ins[1]] = a+b+0
        elif op == 'neg' or op == 'negate': # no subtraction
            a = registers[ins[1]]
            registers[ins[1]] = 0-a
        elif op == 'mul' or op == '*' or op == 'multiply':
            a = registers[ins[1]]
            b = get(ins[2])
            assert(type(a) is int)
            assert(type(b) is int)
            registers[ins[1]] = a*b
        elif op == 'hlt' or op == 'halt' or op == 'h':
            break
        elif op == '#' or op == '//' or op == '--' or op == ';' : # comment
            pass
        elif op == 'uwu' or op == '🥺':
            a = registers[ins[1]]
            b = registers[ins[2]]
            registers[ins[1]] = uwu(a,b)
        elif op == "manic" or op == "mnc":
            a = registers[ins[1]]
            b = registers[ins[2]]
            registers[ins[1]], registers[ins[2]] = manic(a,b)
        elif op == 'len' or op == 'length' or op == 'l':
            a = registers[ins[1]]
            b = registers[ins[2]]
            registers[ins[1]] = len(b)
        elif op == 'mov' or op == 'move' or op == 'copy' or op == "=": # it does indeed copy
            a = registers[ins[1]]
            b = get(ins[2])
            registers[ins[1]] = b
        elif op == 'in' or op == 'inp' or op == 'read' or op == 'input' or op == 'i':
            a = registers[ins[1]]
            line = input()
            arr = list(map(int,line.split()))
            registers[ins[1]] = arr
        elif op == 'out' or op == 'print' or op == 'output' or op == 'o':
            a = registers[ins[1]]
            assert(type(a) is list)
            for item in a:
                print(f"{item} ", end="")
            print("")
        else:
            raise Exception("invalid instruction")
        pc += 1

Entry #8

Written by Palaiologos

esolangs.py ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Read the file passed in args to a string.

import sys

# Maximum amount of memory. Tweak if needed.
MEM = 65536

with open(sys.argv[1], 'r') as f:
    code = f.read().split('\n')

magic, code = int(code[0]), code[1]

if len(code) > 105:
    print("Code too long.")
    exit()

conversions = {
    'R':'BBB8B25BGf', 'P':'558545C5F5535E', 'O':'FB04001058039BBB',
    'N':'455E4D09988F87213E656060', 'M':'Gj369Gf825Gl471AGzGzGzGy',
    'L':'12GeF0Hi5BBB8BGfHh4BBB7BBBA1GfBBB444Hg66BBB3BB9Gf8BBB888',
    'K':'F73619D1253F15651565FE8F2F2E620B320F73E232357576A3B4342A',
    'J':'10151512234334533535906165151510572322324454545824350353'
}

for key in conversions:
    code = code.replace(key, conversions[key])

new_code = ''
i = 0
while i < len(code):
    if code[i] == 'G':
        new_code = new_code + "0" * (ord(code[i + 1]) - ord('a'))
        i = i + 1
    elif code[i] == 'H':
        new_code = new_code + "B" * (ord(code[i + 1]) - ord('a'))
        i = i + 1
    elif code[i] == 'I':
        new_code = new_code + "F" * (ord(code[i + 1]) - ord('a'))
        i = i + 1
    else: new_code = new_code + code[i]
    i += 1

# The magic algorithm.
T = [ord(c) for c in new_code]
TL = len(T)
C = [0] * 256
i = p = length = half = 0
A = [0] * TL
for c in new_code: C[ord(c)] += 1
for c in range(256):
    p = C[c]; C[c] = i; i += p
for i in range(magic):
    A[C[T[i]]] = i
    C[T[i]] += 1
for i in range(magic, TL):
    A[C[T[i]]] = i + 1
    C[T[i]] += 1
p = magic
for i in range(TL):
    c = 0
    length = 256
    half = length >> 1
    while 0 < length:
        # ...
        if C[c + half] < p:
            c += half + 1
            half -= (length & 1) ^ 1
        length = half
        half = half >> 1
    T[i] = c
    p = A[p - 1]

def brk(s, n):
    return [s[i:i+n] for i in range(0, len(s), n)]

def convert(s):
    num = int(s, 16)
    if num > 2048:
        return num - 4096
    else:
        return num

a = list(map(convert, brk(''.join([chr(c) for c in T]), 3)))

a += [0] * (MEM - len(a))

i = 0
while i >= 0:
    if a[i] == -1:
        a[a[i + 1]] = int(input())
    elif a[i + 1] == -1:
        print(str(a[a[i]]) + " ", end="")
    else:
        a[a[i + 1]] -= a[a[i]]
        if a[a[i + 1]] <= 0:
            i = a[i + 2]
            continue
    i += 3
spec.txt ASCII text, with very long lines (361)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# XY Machine

The program is a file with exactly two lines. The first line is a decimal number (subsequently called the _magic_ number) and the second line is the code. The code may not exceed 105 octets, or an error message will be printed and the interpreter will terminate.

First, the following substitutions are made on the code line:

```
R => BBB8B25BGf
P => 558545C5F5535E
O => FB04001058039BBB
N => 455E4D09988F87213E656060
M => Gj369Gf825Gl471AGzGzGzGy
L => 12GeF0Hi5BBB8BGfHh4BBB7BBBA1GfBBB444Hg66BBB3BB9Gf8BBB888
K => F73619D1253F15651565FE8F2F2E620B320F73E232357576A3B4342A
J => 10151512234334533535906165151510572322324454545824350353
```

Then, every instance of the letter G followed by a lowercase letter is replaced with the amount of zeroes corresponding to the position of the letter in the lowercase alphabet (0-indexed). For example, `Gg` becomes `000000`. The same rule holds for the uppercase letters H and I, except H produces `B`s and I produces `F`s, so for example `Ig` becomes `FFFFFF`.

After these transformations are performed, the code becomes a a sequence of hexadecimal digits. Then, the magic algorithm of the code is performed.

The magic "encryption" algorithm steps follow:
- Consider T the array of ASCII codepoints of the input. Consider TL the length of it.
- Create an array called C with 256 zeroes.
- Create an array called A with TL zeroes.
- For each element E of the T array, increment the E-th cell of C.
- Given I=0, for each number N in range `<0, 256)`, set the N-th element of C to I and increment I by the previous value of the N-th element of C.
- For each I in `<0, magic number)`, take the I-th element of T and call it X. Use X to index into C and then A. Set the value in the A array to I. Increment X-th element of C. 
- For each I in `<magic number, TL)`, take the I-th element of T and call it X. Use X to index into C and then A. Set the value in the A array to I + 1. Increment X-th element of C. 
- For each I in range `<0, TL)`:
  - Consider c = 0, length = 256, half = 128.
  - While length is non-zero:
    - If the (c+half)-th element of C is smaller than the magic number, add half+1 to c and subtract the inverted least significant bit of length from half.
    - Set length to half and halve half.
  - Set the I-th element of T to c.
  - Set take the (magic number - 1)-th element of the A array. Make it the new magic number.
- Turn every element of the T array to a character value and concatenate them all to return a code string.

Then, break up the code string into three byte-long pieces. Then, interpret every three byte long piece as a hexadecimal number. If the number is greater than 2048, subtract 4096 from it. Finally, yield it. This process will turn the code into an array of signed integers.

Then, pad the resulting array (call it the memory) with zeroes to MEM entries (implementation defined, the supplied interpreter assumes MEM=65536). Then enter the evaluation loop. Assuming, initially, i=0:
- if memory[i] = -1: set memory[memory[i + 1]] to the number read from standard input.
- if memory[i + 1] = -1: print memory[memory[i]] as a number to the standard output.
- Otherwise, subtract in-place memory[memory[i]] from memory[memory[i + 1]]. If the value of memory[memory[i + 1]] becomes less than or equal to 0, set i=memory[i + 2] and enter the next iteration of the evaluation loop.
- Finally, increment i by 3.
xy_io.txt ASCII text
1
Reads a number N, then reads N numbers comprising the list and writes them in sorted order.

Entry #9

Written by RocketRace

example-input ASCII text, with no line terminators
1
(C)((S)((S)(Z)))((C)((S)(Z))(E))
io.md ASCII text
1
Given the definitions `NZ|SN` and `LE|CNL`, the input and output are given as linked lists of Peano numerals. See `example-input`.
run_tflite.sh ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#/bin/bash
if [ "$#" -ne 2 ]; then
    echo "usage: $0 source input" >&2
    exit 1
fi
if ! [ -e "$1" ]; then
    echo "$1: not found" >&2
    exit 1
fi
if ! [ -e "$2" ]; then
    echo "$2: not found" >&2
    exit 1
fi
cat $2 | python3 -c "$(cat $1 | python3 ./tflite.py)"
specification.md ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# TFLite

A Tiny Functional Language (lite).

## Declarations

Newlines and semicolons delimit. Leading characters name.

## ADTs

Uppercase names define ADTs. Bar denotes sums, juxtaposition products.

* `FA|BF|CFF` <=> `data F = A | B F | C F F`

## Functions

Lowercase names are functions. Numbers denote arity. An expression follows arguments.

* `k2xyx` <=> `k x y = x`

## Pattern matching

Argments are matched structurally. Uppercase destructures ADTs.
Lowercase binds. Underscore ignores. Bar delimits patterns.

* `BT|F;a2TTT|Txx|_TF` <=> `data B = T | F`; `a T T = T`; `a T x = x`; `a _ T = F`

## Expressions

Juxtaposition applies. Parentheses group. Brackets form anonymous functions.

* `[1Sxx|ZSZ](S(SZ))` is `(SZ)` is `SZ`

## Main

Caret denotes an entry point.

* `^1xx` <=> `main x = x`

## I/O

Input and output are shell standard. Both form expressions of ADTs. Newlines delimit inputs.
Output is singular. Equivalence is expressionwise rather than bytewise.

* `S(SZ)\nSZ` ~> `^2SxSy^xy|ZSxx|SxZx|ZZZ` ~> `SZ` is `S Z` is `S(Z)` is `(S)(Z)` is ...

## Whitespace

Spaces and tabs are insignificant. Empty declarations vanish.

* ` f    3g    x  y             gy  x ;  ;;;;` is `f3gxygyx`

## Legal

The rules disallow disallowing exploiting transpiler bugs. Exploits are discouraged.
All material is served as is. All rights are reserved.
tflite.py ASCII text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# Many qualities of this transpiler are inspired by V
import textwrap, sys

def pattern(rest, datas):
    name = rest[0]
    rest = rest[1:]
    if name.isupper():
        out = [name]
        for _ in range(datas[name]):
            pat, rest = pattern(rest, datas)
            out.append(pat)
        return out, rest
    elif name.islower():
        return name, rest
    elif name == "_":
        return None, rest
    else:
        raise SyntaxError

def expr(rest, datas, stack):
    call = []
    while rest:
        c = rest[0]
        rest = rest[1:]
        match c:
            case ")":
                assert stack.pop() == "("
                break
            case "]":
                assert stack.pop() == "["
                break
            case "|":
                rest = "|" + rest
                break
            case "(":
                stack.append("(")
                e, rest = expr(rest, datas, stack)
                call.append(e)
            case "[":
                stack.append("[")
                f, rest = func(rest, datas, stack)
                call.append(f)
            case _:
                call.append(c)
    return call, rest

def func(rest, datas, stack):
    count = int(rest[0])
    return branch(rest[1:], datas, count, stack)

def branch(rest, datas, count, stack):
    branches = []
    start = True
    while start or (rest and rest[0] == "|"):
        if not start:
            rest = rest[1:]
        patterns = []
        for _ in range(count):
            p, rest = pattern(rest, datas)
            patterns.append(p)
        e, rest = expr(rest, datas, stack)
        branches.append((patterns, e))
        start = False
    return {'':branches}, rest

def transpile(code):
    if len(code) > 100:
        raise SystemExit("golf it!")
    lines = sorted(filter(None, code.replace("\n",";").replace(" ","").replace("\t","").split(";")))
    datas = {}
    fns = {}
    for line in lines:
        name = line[0]
        rest = line[1:]
        if name.isupper():
            for branch in rest.split("|"):
                tag = branch[0]
                count = len(branch) - 1
                datas[tag] = count
        else:
            if name == "^":
                name = "main"
            fn, rest = func(rest, datas, [])
            fns[name] = fn
    return write_header() + write_datas(datas) + write_fns(fns) + write_footer(datas)

def write_header():
    return textwrap.dedent('''
    # generated by the TFLite transpiler version {}
    import enum, re
    class Data(list):
        # todo: static typing
        def __call__(self, arg):
            return Data(self + [arg])
    def output(value):
        if isinstance(value, Data):
            if len(value) == 1:
                return output(value[0])
            return "".join(f"({output(x)})" for x in value)
        elif isinstance(value, _data):
            return value.name
        return value.__name__
    '''[1:])

def write_datas(datas):
    members = "\n".join(f"    {c}=object()" for c in datas) if datas else "    pass"
    kind = f"class _data(enum.Enum):\n{members}\n"
    constants = "\n".join(f"{c}=Data([_data.{c}])" for c in datas)
    return kind + constants + "\n"

def write_fns(fns):
    return "\n".join(write_fn(name, fn) for name, fn in fns.items())

def write_pattern(pattern):
    return f"[{', '.join('_' if p is None else (f'_data.{p}' if p.isupper() else p) if isinstance(p, str) else write_pattern(p) for p in pattern)}]"

def find_anons(expr, anons):
    for e in expr:
        if isinstance(e, dict):
            anons.append(e)
            for (_, branch) in e['']:
                find_anons(branch, anons)
        elif isinstance(e, list):
            find_anons(e, anons)
    return anons

def write_expr(expr, anons, ids):
    out = ""
    for e in expr:
        e = "main" if e == "^" else e
        if isinstance(e, str):
            out+=f"({e})"
        elif isinstance(e, list):
            out +=f"({write_expr(e, anons, ids)})"
        elif isinstance(e, dict):
            out +=f"(anon_{ids[anons.index(e)]})"
    return out

def write_fn(name, fn):
    fn = fn['']
    out = ""
    n = len(fn[0][0])
    if n == 0:
        expr = fn[0][1]
        anons = find_anons(expr, [])
        ids = [(abs(hash(str((i, anon, fn))))) for i, anon in enumerate(anons)]
        for id, anon in zip(ids, anons):
            out += textwrap.indent(write_fn(f"anon_{id}", anon), n*'    ')
        out += f"{name}={write_expr(expr, anons, ids)}\n"
    else:
        for i in range(n):out+=f"{i*'    '}def {name}{i*'_'}(_{i}):\n"
        out+=f"{n*'    '}match [{', '.join(f'_{i}'for i in range(n))}]:\n"

        for pattern, expr in fn:
            out += f"{(n + 1)*'    '}case {write_pattern(pattern)}:\n"
            anons = find_anons(expr, [])
            ids = [(abs(hash(str((i, anon, fn))))) for i, anon in enumerate(anons)]
            for id, anon in zip(ids, anons):
                out += textwrap.indent(write_fn(f"anon_{id}", anon), (n + 2) * '    ')
            out += f"{(n +2)*'    '}return {write_expr(expr, anons, ids)}\n"
        out += f"{(n + 1)*'    '}case _: raise RuntimeError('Bad arguments')\n"

        for i in range(n - 1): out += f"{(n-i-1)*'    '}return {name}{(n-i-1)*'_'}\n"

    return out

def write_footer(datas):
    chars = "".join(datas)
    return textwrap.dedent(f'''
    if __name__ == "__main__":
        args = []
        for arg in open(0):
            arg = re.sub("\\\\s", "", arg)
            assert len(re.findall("[\\\\(\\\\){chars}]", arg)) == len(arg), "Bad character"
            assert not re.findall("\\\\(\\\\)", arg), "Bad format"
            try:
                args.append(eval(arg))
            except SyntaxError as e:
                raise SyntaxError("Bad format") from e
            except Exception as e:
                raise RuntimeError("Bad input") from e
        try:
            value = main
            for arg in args:
                value = value(arg)
            print(output(value))
        except Exception as e:
            raise RuntimeError("Bad program") from e
    '''[1:])

print(transpile(sys.stdin.read()))