Do you know of quirky.com ?
Either way, take a look, and maybe vote in one of my ideas (or all 3 !)
Have you heard of Corewars ? Originally proposed by A.K. Dewdney in his popular Scientific American column, almost 30 years ago, it consists of pitting 2 assembly-like (Redcode) programs against each other in a virtual battlefield. The winner will be the last one standing, or to put it in another way, a program fails / aborts when it can’t decode / interpret the next instruction. Successful programs will then have to implement more or less complex strategies of data corruption against the opponents…
Over all those years there have been many implementations of Corewars (like pMARS), mostly for popular platforms like DOS, Windows, Unix, etc. To my knowledge they all implemented the simultaneous fight between the 2 programs in a typical, time-shared, round-robin fashion. What I bring here is a truly multiprocessor implementation, where each virtual player runs from its own CPU.
For that I used the revolutionary Propeller microcontroller from Parallax. If you’re new to it, inside there are 8 completely independent 32-bit CPUs (called Cogs), each with its own video generation logic and a small amount of RAM. There’s also 32K more of RAM and another 32K of ROM globally available, besides 32 I/O lines and a few more goodies. What I have is the USB Protoboard, which adds VGA, mouse and keyboard connectors; a 64Kb EEPROM, a power supply and room to build small circuits. To this I added an LCD monitor and an old PS2 keyboard for user interaction.
It can be programmed in a high level language called Spin, assembler, or a mix of both. The resulting program it’s completely coded in Spin and uses all 8 available Cogs as follows:
- 0 – supervisor duties
- 1 – keyboard controller
- 2,3 – VGA generator
- 4 – Random generator, and afterwards score keeper
- 5,6 – the actual Redcode players
Visually, it’s very simple with just a text interface, but the essential is there. Each player actions are denoted by its number appearing across the play / battlefield. Each new number means an additional memory location written by the player.
The actual code for each player is written as a txt file (with extension RCI) that is read into the application during compile time. These txt files are defined as simple declarations near the beginning of the code. Afterwards, when the program starts up, random locations are assigned to each player. The logic guarantees that no 2 players are less than 1000 memory locations apart.
To interact with the system, we use LOD; for loading a particular player into the battlefield (0 loads them all at once); STA; for starting / running a player; STO; for stopping, and finally INI for initializing the program. This clears the battlefield and assigns new random locations for each player. In the print screen above, you can see in the status line that one of the programs is still running (the winner !) while the other has already stopped.
Below is the simple Redcode instruction set and addressing modes used in the system. This is the most simple and earliest set of instructions and addressing modes. Later, some extensions were added. You can read about them here.
- DAT – Initialize location to value B.
- MOV – Move A into location B.
- ADD – Add operand A to contents of location B and store result in location B.
- SUB – Subtract operand A from contents of location B and store result in location B.
- JMP – Jump to location B.
- JMZ – If operand A is 0, jump to location B; otherwise continue with next instruction.
- DJZ – Decrement contents of location A by 1. If location A now holds 0, jump to location B; otherwise continue with next instruction.
- CMP – Compare operand A with operand B. If they are not equal, skip next instruction; otherwise continue with next instruction.
- END – Signals the end of the program. Not actually an instruction.
- Immediate (#) – The number following this symbol is the operand.
- Relative – The number specifies an offset from the current instruction. The interpreter adds the offset to the address of the current instruction; the number stored at the location reached in this way is the operand.
- Indirect (@) – The number following this symbol specifies an offset from the current instruction to a location where the relative address of the operand is found. The interpreter adds the offset to the address of the current instruction and retrieves the number stored at the specified location; this number is then interpreted as an offset from its own address. The number found at this second location is the operand.
Beware that not all addressing modes make sense, depending on the instruction, used as part of operand A or B, although the compiler puts no restrictions. Use your good sense.
The code will shortly be freely available from the Parallax OBEX forum, but in the meantime you can also find it here. It is reasonably commented, but not much… and there’s still an insidious bug that sometimes causes programs to lose an instruction when loaded. Maybe you can find it…
Included in the package are two of the earliest fighter programs conceived: Imp and Dwarf. When going through the code if sometimes the logic proves hard to follow you can drop me an email to pjrebordao at gmail dot com. I’ll try to reply.
Happy fighting !
Check the video on the right column of my home-made turntable turning and singing in all its glory.