ZeroGrid2D

From Esolang
Jump to navigation Jump to search

ZeroGrid2D is a 2D grid-based esoteric programming language developed in March 2026 to explicitly prove Turing-completeness in response to doubts about the computational power of its predecessor, ZeroStack2D. Unlike ZeroStack2D (which uses a 2D code grid but linear stack for data), ZeroGrid2D unifies both code and data into dynamic 2D grids (a "dual 2D grid" design):

  • Code grid: The program is a 2D grid of commands traversed by the interpreter;
  • Data grid: All memory operations use a 2D grid of "Box" cells (each with 4-directional adjacency), directly mapping to Minsky machine registers and Turing machine tape.

This design eliminates indirect data mapping, making ZeroGrid2D's Turing-completeness transparent and easy to verify—while retaining the core 2D grid paradigm of ZeroStack2D.


Core Concepts

Grid Program

The program is stored as a plain text file, where each line of the file represents a row in a 2D grid of commands. The interpreter starts execution at grid coordinates (x=0, y=0) (the top-left corner of the grid).

Box (Memory Cell)

The language's core memory unit is the "Box", which consists of:

  • An integer data value (default: 0)
  • References to adjacent Boxes (left/right/up/down), dynamically created when navigation commands are executed

Direction Encoding

The interpreter maintains a movement direction (encoded as an integer) that controls both grid pointer movement and Box navigation:

Direction Encoding
Code Direction Coordinate Change
0 Right x += 1
1 Up y -= 1
2 Left x -= 1
3 Down y += 1

Instruction Set

All valid commands are single characters; any unrecognized character is treated as a no-op (no operation).

ZeroGrid2D Instruction Set
Command Behavior
> Set movement direction to Right (0)
< Set movement direction to Left (2)
^ Set movement direction to Up (1)
v Set movement direction to Down (3)
) Navigate to the adjacent Box in the current direction (create a new Box if none exists)
( Navigate to the adjacent Box in the opposite direction (create a new Box if none exists)
+ Increment the current Box's data by 1
- Decrement the current Box's data by 1
? Read a single character input; store its ASCII value in the current Box
~ Read an integer input; store it in the current Box
$ Reset the current Box's data to 0
. Print the current Box's data as an integer (with newline)
, Print the current Box's data as an ASCII character (no newline)
| Conditional vertical direction: set to Up (1) if data ≠ 0, else Down (3)
_ Conditional horizontal direction: set to Right (0) if data ≠ 0, else Left (2)
@ Terminate the program immediately
(other) No operation; continue moving in the current direction

Execution Rules

  1. The interpreter initializes at (x=0, y=0) with a single Box (data = 0) and direction set to Right (0).
  2. For each execution step:
    • Read the command at the current grid coordinates (treat out-of-bounds access as a no-op)
    • Execute the command (if valid)
    • Move the grid pointer one cell in the current direction
  3. Execution terminates only when the @ command is encountered.

Implementation

Dependencies

  • Python 3.x (no external libraries required)

Usage

To run a ZeroGrid2D program:

python ZeroGrid2D.py [path/to/program.txt]

Reference Implementation

The reference interpreter is written in Python 3 and follows the language specification exactly:

#!/usr/bin/python3
import sys, argparse

# Initialize command-line argument parser to accept the grid program file
arg_parser = argparse.ArgumentParser(description="ZeroGrid2D: 2D Grid Esoteric Language Interpreter")
arg_parser.add_argument("input_file", help="Path to the text file containing the ZeroGrid2D grid program")

# Box class: Represents a data cell in the language's memory model
# Each Box holds an integer value and references to adjacent Boxes (left/right/up/down)
class Box():
    def __init__(self, data=0):
        # Integer data stored in the Box (default: 0)
        self.data = data
        # Reference to adjacent Box on the left (initially None)
        self.left = None
        # Reference to adjacent Box on the right (initially None)
        self.right = None
        # Reference to adjacent Box above (initially None)
        self.up = None
        # Reference to adjacent Box below (initially None)
        self.down = None

# Load the grid program from the input file
try:
    # Parse command-line arguments and get the input file path
    args = arg_parser.parse_args()
    input_file_path = args.input_file
    
    # Read the program file and convert it into a 2D list (grid)
    # Each line becomes a list of characters (one per grid cell)
    with open(input_file_path, "r") as f:
        program_raw = f.readlines()
        program = []
        for line in program_raw:
            program.append(list(line))  # Convert each line to a char list
except (IndexError, FileNotFoundError):
    # Exit silently if file not found or argument error (per original behavior)
    sys.exit(0)

# Initialize interpreter state
current_box = Box()  # Active Box (data cell) being manipulated
x = 0                # Current horizontal position (column) in the grid (starts at 0)
y = 0                # Current vertical position (row) in the grid (starts at 0)
direction = 0        # Current movement direction (0=right,1=up,2=left,3=down)

# Main interpreter loop (runs until @ command is encountered)
while True:
    # Get the current command from the grid; default to space (no-op) if out of bounds
    try:
        cmd = program[y][x]
    except IndexError:
        cmd = " "  # Treat out-of-bounds as empty command (no operation)

    # --------------------------
    # Direction control commands
    # --------------------------
    if cmd == ">":
        direction = 0  # Set direction to RIGHT (x increases by 1)
    elif cmd == "<":
        direction = 2  # Set direction to LEFT (x decreases by 1)
    elif cmd == "^":
        direction = 1  # Set direction to UP (y decreases by 1)
    elif cmd == "v":
        direction = 3  # Set direction to DOWN (y increases by 1)

    # --------------------------
    # Box navigation commands
    # --------------------------
    # ) : Move to/create adjacent Box in CURRENT direction
    elif cmd == ")":
        if direction == 0:  # Current direction: RIGHT
            if not current_box.right:
                current_box.right = Box()  # Create new Box if none exists
            current_box = current_box.right  # Switch to the right Box
        elif direction == 1:  # Current direction: UP
            if not current_box.up:
                current_box.up = Box()
            current_box = current_box.up
        elif direction == 2:  # Current direction: LEFT
            if not current_box.left:
                current_box.left = Box()
            current_box = current_box.left
        elif direction == 3:  # Current direction: DOWN
            if not current_box.down:
                current_box.down = Box()
            current_box = current_box.down
    # ( : Move to/create adjacent Box in OPPOSITE direction
    elif cmd == "(":
        if direction == 2:  # Opposite of LEFT is RIGHT
            if not current_box.right:
                current_box.right = Box()
            current_box = current_box.right
        elif direction == 3:  # Opposite of DOWN is UP
            if not current_box.up:
                current_box.up = Box()
            current_box = current_box.up
        elif direction == 0:  # Opposite of RIGHT is LEFT
            if not current_box.left:
                current_box.left = Box()
            current_box = current_box.left
        elif direction == 1:  # Opposite of UP is DOWN
            if not current_box.down:
                current_box.down = Box()
            current_box = current_box.down

    # --------------------------
    # Data manipulation commands
    # --------------------------
    elif cmd == "+":
        current_box.data += 1  # Increment current Box's data by 1
    elif cmd == "-":
        current_box.data -= 1  # Decrement current Box's data by 1
    elif cmd == "?":
        # Read a single character input, store its ASCII value in current Box
        current_box.data = ord(input())
    elif cmd == "~":
        # Read an integer input, store it in current Box
        current_box.data = int(input())
    elif cmd == "$":
        current_box.data = 0  # Reset current Box's data to 0

    # --------------------------
    # Output commands
    # --------------------------
    elif cmd == ".":
        # Print current Box's data as an integer (with newline)
        print(current_box.data)
    elif cmd == ",":
        # Print current Box's data as an ASCII character (no newline)
        print(chr(current_box.data), end='')

    # --------------------------
    # Conditional direction commands
    # --------------------------
    elif cmd == "|":
        # Vertical conditional: UP (1) if data !=0, else DOWN (3)
        if current_box.data:
            direction = 1
        else:
            direction = 3
    elif cmd == "_":
        # Horizontal conditional: RIGHT (0) if data !=0, else LEFT (2)
        if current_box.data:
            direction = 0
        else:
            direction = 2

    # --------------------------
    # Termination command
    # --------------------------
    elif cmd == "@":
        sys.exit(0)  # Exit the interpreter immediately

    # --------------------------
    # Move grid pointer based on current direction
    # --------------------------
    if direction == 0:
        x += 1  # Move right (increase column)
    elif direction == 1:
        y -= 1  # Move up (decrease row)
    elif direction == 2:
        x -= 1  # Move left (decrease column)
    elif direction == 3:
        y += 1  # Move down (increase row)

See Also