
So on #sporks today, we discussed Aargh! I compared it to assembler for chess players, and EvilTerran suggested the idea of an esoteric computer language using chess rules/moves.
I subsequently (with the help of #sporks) designed one. Yes it is possible, it is Turing complete and I believe it can be implemented. A particular thank you to Maximinus who contributed a number of useful ideas.
Starting principles:
Your program is represented by the pieces on a chess board and the board itself. There is a two-byte stack providing state.
Pawns are value pieces, all other pieces are operations. White pawns represent 1, Black pawns represent 0. White blocks on the board are 1 black blocks are 0.
When a pawn is taken, the block it is on represents a bit, the pawn itself another, the piece taking it represents an operation performed on those bits. The result goes in the stack.
When there are 8 bits in the stack, the ascii value represented by the byte they make up is placed on the 2-byte stack.
When operational pieces are taken – the operation they represent cannot be used again in the current game.
If a pawn takes a pawn, nothing goes in the stack, but the pawn is no longer available for arithmetic.
A program consists of a series of games. Each game is started by feeding in a set of starting positions for pieces. All pieces move as in normal chess rules.
Once all the pawns are taken (unless pawns take pawns this means 2 bytes have been placed into the stack – but using pawn-take-pawn you could split stack over several games), the ‘game’ ends and you
feed in values for the next game.
Since you have a theoretically infinite amount of games, the language will be Turing complete if all required operations are supported.
The operations pieces (white) are:
Rook: AND
Bishop: OR
Knight: XOR
Queen: ADD
King: SUB
The black operations pieces represent the NOT’s of their white counterparts:
Rook: NAND
Bishop: NOR
Knight: NXOR
Queen: SUB
King: ADD
A game is begun with a call to start and a set of values representing the initial layout of the board for this game.
The values are given as chess coordinates for all pieces.
The first 8 values represent the white operations pieces’ locations.
The next 8 values represent the black operations pieces’ locations.
Basic example:
start A1 A2 A3…H6 H7 H8
(whatever layout you need) However you can NOT place any pieces on the two center-rows.
Then you need to place the pawns, which are used as input. There are 2 ways to do this.
You can call:
const_pawns …
const_pawns takes 16 parameters each a chess coordinate, the first 8 places the white pawns the next 8 places the black pawns. You can place them on
any unused space on the board.
Alternatively you can call:
stack_pawns
Stack_pawns works by itself without any parameters, and places 16 pawns representing the two bytes in the stack.
In this case you may not have a normal chess setup of 8 white and 8 black pawns. The Center rows hold the two stacks as input, it is up to you move the pawns so the values they stand on
represent what you want (initially this is simply a matter of which bit in the byte you have)
The first byte in the stack is placed on the row D1-D8 the second on row E1-E8.
Calling stack_pawns without the stack being full results in an error.
Operating on the stack:
From here on, you write down a set of valid chess moves. Those moves that take a pawn are done as operations and the result added to the output stack.
For example: C7 B4
Means: Piece moves from C7 to B4 (only a knight could do this move btw. But we don’t need to specify the pieces as it’s the interpreter’s job to remember the current location of each piece).
Each operation is written on a new line below the last.
Please note that while you can place any piece ANYWHERE during the start call, you can ONLY make moves for each piece that is allowed under chess rules for during a game.
Once all pawns are removed, you must call start again with a starting position that will allow you to do your next operation. White moves first just like in real chess and moves then take turns.
Some have suggested a variant where games cannot end by merely removing the pawns but require a state of checkmate or a draw to occur – this is still being debated.
Displaying output:
The print command prints out the ascii character represented by a byte from the stack. It takes one argument, either a 0 or a 1.
If it is 0 it prints the first byte in the stack. If it is 1 it prints the second byte in the stack.
Example: print 1
Loops and branches:
The if statement
The program can branch by using the if statement.
If works by performing a boolean test on the two bytes in the stack in the following form:
if OPERATOR then
actions
else
actions.
fi
OPERATOR can be any valid boolean comparison: AND, OR etc. if the result is 00000000 then the if is false, otherwise it is true. It is up to the programmer to place values in the stack that evaluate as he wants it.
Additionally you can also do a boolean operation using the value (0 or 1) of a specific piece (regardless of the type of piece, merely the color determines this).
To do so:
if A5
Where A5 can be any valid chess coordinate. It returns true if the piece on A5 is white, false if it is black or the block is empty.
Actions represent blocks where the programmer can write any valid chesscode commands including nested loops and branches, output or games (which changes the stack).
Calling if without two full bytes in the stack causes an error.
The while loop
Chesscode supports while loops. Like if statements while loops do a boolean operation on the bytes in the stack.
They take the following structure:
while OPERATION
actions
elihw
The actions once more is any valid chesscode commands including games. In fact failing to put games in the loop which will change the stack (and use input from it) to something that ultimately returns false will cause an endless loop.
Like an if statement, calling while on an incomplete stack causes an error.
You can also use a query by coordinates for a while loop e.g.
while C7
In this case, if the piece there is white the loop starts, moving it out or taking it with a black piece leads to a false and ends the loop.
Getting user input.
Like the print command can write a value from the stack to the screen, the read command can read a value from the keyboard to the stack.
It takes a single parameter, which indicates a byte in the stack.
For example: read 1
The user hits a key on the keyboard, the binary representation of the ascii value of this key/letter is then stored in the second byte in the stack.
If you use read 0 instead, then it will go in the first byte of the stack (replacing any value already there).
Ending the program:
Using these structures, you can write all the code to do whatever you need your program to do. When you are finished, call
end
To tell the interpreter/compiler that your program is finished.
Final notes:
Note that all indentation is done for clarity and completely optional. Also note that the EOL character is used as an end of command marker throughout (as opposed to ; for example) so all commands must be placed on a single line.
You are welcome to hate me until the end of time.
Comments are very much desired, and if somebody is up for trying to create a working implementation I would love to know and maybe help.