4DChess

From Esolang
Jump to navigation Jump to search

4DChess is an esoteric programming language designed by User: Zemeckis on 18th November, 2019. It is directly inspired from Brainfuck. Instead of brainfuck's usual one-dimensional memory cell array, 4DChess uses a four-dimensional hypercube-like memory cell array of 8 cells per dimension.

Overview

Unlike most brainfuck derivatives, the memory cell array is intentionally, and specifically, limited in length. Each dimension is limited to 8 cells per the particular dimension. This 8 cell per dimension array is what inspires the name, being reminiscent of a chess board, but in four dimensions. However, the pointer can be freely moved in all 4 dimensions, or axis. referred to as the X axis, the Y axis, the Z axis, and the W axis. This multi-dimensional memory cell array has inspired referring to the memory space as a hypercube, a 4-dimensional cube. The pointer starts at 0, 0, 0, and 0, on the X, Y, Z, and W axis respectively. This means that the pointer starts in a corner of the hypercube.

Limitations

The limitations of 4DChess give the user a memory space of 4,096 bytes. (8^4) This specifically limited memory space means that 4DChess is not Turing-complete as long as you assume the cells are bounded. 4DChess also does not allow array overflows or underflows. Attempting to move the pointer to an array position below 0(1) and above 7(8) on any array axis results in an error. This is referred to "Falling off the hypercube," in whichever particular axis and direction the error occurred. This means that 4DChess programs are very strictly confined to the boundaries of the hypercube.

If you assume the cells are bounded, as the reference interpreter does, it fits the definition of a Linear bounded automaton. The memory is fixed, and if it wasn't, it would be Turing-complete by analogy with Brainfuck.

If you assume the cells are unbounded, the relevant brainfuck proofs of Turing-completeness work directly because they require 3 or 5 unbounded cells in a row, and 4DChess has eight. Basically, the memory wouldn't be fixed because the numbers stored in memory wouldn't be fixed.

Commands

4DChess's commands are similar to brainfuck's, but has included 3 new pairs of pointer controllers, two for the Y axis, two for the Z axis, and two for the W axis.

Command Description
> Increase the pointer's position along the X axis
< Decrease the pointer's position along the X axis
^ Increase the pointer's position along the Y axis
v Decrease the pointer's position along the Y axis
* Increase the pointer's position along the Z axis
o Decrease the pointer's position along the Z axis
@ Increase the pointer's position along the W axis
? Decrease the pointer's position along the W axis
+ Increment the memory cell under the pointer
- Decrement the memory cell under the pointer
. Output the character signified by the cell at the pointer's position on the X, Y, Z, and W axis
, Input a character and store it in the cell at the pointer's position on the X, Y, Z, and W axis
[ Jump past the matching ] if the cell under the pointer is 0
] Jump back to the matching [ if the cell under the pointer is nonzero

Purpose

4DChess was created with the purpose of forcing the user to work within a strict memory array, and with a secondary goal of making sure most normal brainfuck programs will not directly translate.

Examples

Hello World!

The following program utilizes the fourth dimension (W-axis) for printing “Hello World!” to the standard output.

++++++++[@++++[@++@+++@+++@+????-]@+@+@-@@+[?]?-]@@.@---.+++++++..+++.@@.?-.?.+++.------.--------.@@+.@++.

Implementation

A simple interpreter in Common Lisp is produced below:

(deftype octet ()
  "The OCTET type defines a byte composed of eight adjacent bits."
  '(unsigned-byte 8))

(defun interpret-4DChess (code &aux (ip 0))
  "Interprets the piece of 4DChess CODE and returns NIL."
  (declare (type string code) (type fixnum ip))
  (when (plusp (length code))
    (let ((memory  (make-array '(8 8 8 8) :element-type 'octet))  ;; Hypercube.
          (pointer (list 0 0 0 0)))                               ;; Vector (X, Y, Z, W).
      (declare (type (simple-array octet (8 8 8 8)) memory) (type list pointer))
      (symbol-macrolet ((token
                          (when (array-in-bounds-p code ip)
                            (char code ip)))
                        (current-cell
                          (apply #'aref memory pointer)))
        (flet ((move-pointer (by-x by-y by-z by-w)
                (declare (type integer by-x by-y by-z by-w))
                (map-into pointer #'+ pointer (list by-x by-y by-z by-w))
                (unless (apply #'array-in-bounds-p memory pointer)
                  (error "The pointer ~s infringes on the hypercube's bounds." pointer))))
          (loop while token do
            (case token 
              (#\> (move-pointer +1  0  0  0))
              (#\< (move-pointer -1  0  0  0))
              (#\^ (move-pointer  0 +1  0  0))
              (#\v (move-pointer  0 -1  0  0))
              (#\* (move-pointer  0  0 +1  0))
              (#\o (move-pointer  0  0 -1  0))
              (#\@ (move-pointer  0  0  0 +1))
              (#\? (move-pointer  0  0  0 -1))
              (#\+ (incf current-cell))
              (#\- (decf current-cell))
              (#\. (write-char (code-char current-cell)))
              (#\, (format T "~&Please input a character: ")
                   (setf current-cell (char-code (read-char)))
                   (clear-input))
              (#\[ (when (zerop current-cell)
                     (incf ip)
                     (loop with level of-type integer = 0 do
                       (case token
                         (#\[ (incf level))
                         (#\] (if (zerop level)
                                (loop-finish)
                                (decf level)))
                         (otherwise NIL))
                       (incf ip))))
              (#\] (unless (zerop current-cell)
                     (decf ip)
                     (loop with level of-type integer = 0 do
                       (case token
                         (#\] (incf level))
                         (#\[ (if (zerop level)
                                (loop-finish)
                                (decf level)))
                         (otherwise NIL))
                       (decf ip))))
              (otherwise NIL))
            (incf ip)))))))