Zone

From Esolang
Jump to navigation Jump to search

Zone is a programming language wherein instructions are executed in a random order and programs work by modifying their own code.

Specification

Programs are interpreted as an array of characters. A queue is filled with the characters given to the program as input. At each cycle, a random location is chosen within the program, and the character at that position is read. If the character is 'Z' or 'z', a move operation is performed, otherwise nothing happens.

The move operation is executed like this: if the instruction was uppercase 'Z', the next two characters to the right are read; otherwise, they are read towards the left. Letters 'A' to 'Z' are interpreted as numbers 1 - 26, while lowercase letters are interpreted as the negative counterparts, anything else is considered as zero. The character immediately next indicates the source location, while the second character indicates the destination, both relative to the current instruction. Then, the currently executing 'Z' is replaced with 'z' or vice versa, and at this point the move is performed.

When scanning operands, addresses wrap around. However, when performing the move itself, writing outside bounds will output the moved character, while reading from outside bounds will get a new character from the input queue. If it's empty, the program terminates.

Examples

Cat

Due to the nature of the language, this example (a cat program) is particularly simple. A 'Z' instruction reading and writing outside the program array is sufficient:

CCZCC

Print character

This is a more complicated example. Since all instructions in a program are executed randomly, every instruction must be synchronized. First, let us introduce the printing code. This will print a '!' the first time it executes, while the second time it will deactivate itself to avoid printing further characters, overriding the 'Z' with a 'C'. The location at which the character is written is marked with an asterisk.

*______________________.DZCy!C

Once the character has been printed, we need to terminate the program. We can achieve this by reading in a loop from the input stream. This code will do exactly that, once the '+' is replaced with a 'Z'. As before, the active location outside bounds is also marked.

CY+YC#_____________________*

Now we only need to make a connection between the two parts. Continually piping the 'Z' into '+' until it becomes 'C' would be so easy, but here the opposite is required: moving a 'Z' into '+' only once the 'C' is present (note the parallelism with a NOT gate). Hash symbols mark locations that are clobbered by the code, '+' and '*' mark the input and output locations, and arrows below the line indicate how those can be configured.

#_#__________________+_DBeZcZ..Z.._*________________#_#
                     ^ |_|_________^
                     |___|

Putting together these three pieces, we get (note that the underscores are required):

______________________.DZCy!CEBhZcZ..Z..CY.YC________________

Bad "Hello world"

An example to illustrate why synchronization is required for typical programs. This code uses two 'Z' instructions; one acts as a counter, while the other does the actual printing and program termination. Since the two are not synchronized, the code is relatively compact:

..ZCADEFGHIJKLMNOPQRSTUVWXAyZCYHello world!

However, the actual output contains each character repeated zero or more times, at random, e.g.:

HHellowwwor!!
H old
Hlllowwwwld

Implementation

Here is a Python script that implements Zone:

#!/bin/env python3

import random

prog_string = input("Type program:")
prog = []
for c in prog_string:
    prog.append(c)
data = input("Type input:")

def parse(ch):
    if not ch.isalpha() or not ch.isascii():
       return 0
    if not ch.islower():
        return ord(ch) - ord("A") + 1
    else:
        return -(ord(ch) - ord("a") + 1)

print("\nOutput:")
while True:
    ip = random.randint(0, len(prog) - 1)
    instr = prog[ip]
    ip2 = ip3 = ip
    if instr == "Z":
        ip2 += 1
        ip3 += 2
        prog[ip] = "z"
    elif instr == "z":
        ip2 -= 1
        ip3 -= 2
        prog[ip] = "Z"
    else:
        continue
    ip2 = (ip2 + len(prog)) % len(prog)
    ip3 = (ip3 + len(prog)) % len(prog)
    ap = ip + parse(prog[ip2])
    bp = ip + parse(prog[ip3])
    value = None
    if ap < 0 or ap >= len(prog):
        if len(data) < 1:
            break
        value = data[0]
        data = data[1:]
    else:
        value = prog[ap]
    if bp < 0 or bp >= len(prog):
        print(value, end = "")
    else:
        prog[bp] = value