"One of the best ways to get yourself a reputation as a dangerous citizen these days is to go about repeating the very phrases which our founding fathers used in the great struggle for independence." --Charles Austin Beard
Published by: siliconjesus, on 2008-06-22 22:02:53
Introduction
This article is intended as a supplement to apples’ article on beginning redcode. I plan to delve more deeply into the MARS system and more advanced techniques with redcode to produce able warriors. So, let’s get into it.
MARS
The Memory Array Redcode Simulator (or MARS for short) is, as it sounds, a simulated memory stack. This memory stack, also referred to as the core, as we will refer to it, is where our warriors reside. We will be using a core size that is 8000 memory units in length, as is the basic standard. A note on the structure of the MARS stack is that each location in the core has enough room for an instruction, the a-field, and the b-field of the instruction. As it is, each memory location houses those three things. That is important to keep in mind.
As apples explained in the previous article, the addressing of memory positions in this stack is relative to the position referencing the location. This means that a MOV $1, $-1 call in one location won’t necessarily have the same effect as the same call in a different location. Also, make sure to remember that the memory wraps around, and as such, locations that can be referenced are $0 to $(CORESIZE – 1). Really, you can go beyond the coresize, but it’s rather pointless to do (in code).
Starting Small
All of this is a lot to handle, so let’s go slow. To get into programming warriors in redcode, you need to download yourself a MARS. If you’re on windows, go with CoreWin, anywhere else, go with pMARS. I suggest using CoreWin if you can because the GUI on CoreWin can help you visualize what your warrior is actually doing.
Once you have CoreWin, open it up, and select the Setup button. When that dialog opens, click the New button by the warrior list. A warrior edit window will open, and this is where you will program your first warrior!
The Imp:
CODE :
;redcode-94
;name Imp
;author A.K. Dewdney
imp: mov $0, $1
end imp
As you can see, this warrior is very short; in fact, it’s only one instruction that copies itself to the location in front of it. This means that this warrior will almost never hit a DAT instruction that will terminate its process, but it also means that it won’t win. In fact, the imp, attempting to overwrite other programs, will often turn that program into an Imp, and therefore cause a tie. Now, let’s go through that program.
The directive ;redcode-94 tells the MARS that we’re using the ’94 specification. ;name directive shows the name of our warrior, and the author directive, well, its self explanatory now. We list a label where we want our warrior to start (imp:), and we specify that we want the warrior to start here with the end instruction at the end of the program.
After you type in the code for the warrior, save it as imp.red, and hit compile. If you throw an error, recheck your code. Afterwards, add a second imp to the warrior list, and set tournament type to Melee. Then hit okay. CoreWin will automatically set up a battle for you, and you can see that represented in the GUI. Adjust the speed setting and hit “Start” and you’ll see the battle between two imps start. As you can see, all that happens is a block of instructions being copied, as expected.
Continuing on with The Dwarf
The imp warrior is the beginning of a series of warriors called replicators or papers. We’ll go more deeply into types of warriors later, but let’s continue on with our focus. The basic dwarf is a simple concept. All it does is place DAT instructions at various intervals in the core. The hope is that using this bomber technique will cause an enemy to execute the DAT command. Of course, we need to make sure that the Dwarf does not hit itself. So…let’s look at the basic dwarf:
The Dwarf:
CODE :
;redcode-94
;name Dwarf
;strategy Bomb the core at different points
;assert CORESIZE % 4 == 0
loop: add #4, @3
mov $2, @2
jmp loop
dat #0, #0
end loop
As you can see, the directives work as before, and we added a new directive, the strategy directive. We also added an assertion. We’ll discuss why we did this particular assertion after looking at the code.
The dwarf’s program is simple, but effective. As you can see, the program starts by adding 4 to the B-field of the instruction 3 spots ahead of the ADD, which is the DAT instruction. It then copies the DAT instruction how every many spots in front of it as determined by the B-field of the DAT instruction. Then, the program loops back. So, each time the program loops, the DAT is copied four spots ahead of the last spot.
This also means that when the dwarf wraps around the core, it’ll write the DAT over the DATs already in place, meaning the dwarf avoids bombing itself. This also means that the core size needs to be divisible by four evenly, or else the dwarf can, and probably will, bomb itself, leading to its destruction. As you can see, the assertion we added makes sure that our dwarf will only run when it won’t kill itself. After you type out the code, you can save it and compile it and try it out in a battle on CoreWin. You’ll see it run as expected.
Multi-Process warriors
Now comes the hard part. I should say the harder part. In order to make an effective warrior, we need to master the use of separate processes to give our warriors more of an edge.
Understanding SPL
The SPL command is one of the harder commands to understand when programming for the MARS. The format is as follows:
CODE :
SPL A, B
Now, as with the conditional jumps, the destination for the SPL jump is in the B-field. If you’ve looked up anything on ’94 redcode you also know that SPL defaults with the .B modifier, so saying something like:
CODE :
SPL $1
is the same as using:
CODE :
SPL $0, $1
In any case, the SPL command is used to split a process off your warrior, and create a new one. Of course, your warrior can only execute one instruction on one process each turn you have, so the more processes you have, the slower your overall warriors will execute.
Now, SPL is used a lot in a class of warriors called replicators. Of course, replicators aren’t the only warriors that use this technique, but they are a good place to start.
The Basic Replicator:
As always, we’ll start with a code listing, and work through it.
CODE :
;redcode-94
;name Replicator
;author Siliconjesus
;strategy Replicate warrior over many locations, hopefully overwrite their programs
cnt equ (lst – src) ;number of lines to be copied
src mov #cnt, @0 ;set B-field of this instruction to #cnt
mov <src, <dst
jmn $-1, @src
dst spl @0, $1222 ;split off a process, run at address in B-field
sub #23, @dst ;subtract 23 from B-field of dst
jmz $src, $src ;jump to src if B-field of src is 0 (should always)
lst end src
Explanation:
Okay, so this one is a lot more complicated than the last ones, and as a result it runs a lot more complicated as well. Also, note that there are a lot of addressing indicators in there that wouldn’t need to be there if I used instruction modifiers (in fact once the program is compiled, the MARS automatically adds those modifiers!), so it looks more confusing than it is. Let’s go through it line by line.
The first line is simple; it sets the constant cnt equal to the number of instructions in our program. The line started with the label src is also simple, though it seems a bit confusing. All it does is set the B-field of the MOV instruction to the number #cnt. This is used in the replication of our warrior.
The actual replication only uses two lines in our warrior. The second MOV instruction in our warrior is critical to the operation. This instruction first decrements the B-field of the src instruction and the dst instruction. Then it copies the full instruction located at the address stored in the B-field of src (our “counter”) to the location specified in the B-field of the dst instruction. Then the JMN instruction checks to see if the B-field of src is 0. If not, it jumps back to the previous instruction.
Once again, it should be noted that all of these B-field references would be made without explicitly using the B-field indirect addressing mode (@) but we want to keep our code clean so, be explicit.
It’s subtle, but these two lines, plus the counter and destination are actually a loop that ends up copying our warrior. Once the lines are copied (B-field of src is equal to $0), our warrior creates a new process and sends it to the address of the beginning of the copy. Then the warrior subtracts 23 from the B-field of the dst (put room between the copies), then jumps back to src, as long as the B-field of src is 0 (which it should be if our program ran). So now, our warrior has two copies of itself running. And those two will become four. And those four will become 8, and so on.
As you may have noted, this warrior has not DATs in it. That’s quite correct. The way the paper disrupts other warriors is by potentially corrupting their running by copying over parts of their enemies. Now, this warrior code listing is obviously very primitive and won’t hold its own against larger more developed warriors. However as an example and starting place, it is excellent.
Major Types of Warriors
We’ve looked at three types of warriors: Imps, Dwarfs, and replicators. Now we’ll take a broader look at types, and sub-types of warriors. We’ll start with the Trilogy of basic types.
Stone warriors
Stone warriors, or dwarf warriors, are based on our basic dwarf. They are designed small in order to give them a chance against bigger warriors. They operate from a single module (no splits). Bombers fall into this category. Our version of a dwarf was a simple bomber.
Paper warriors
Paper warriors, or replicators, are only in the core to increase their process numbers. They aim to insure their survival as much as possible. They also eventually can take over the core, and this leads to their wins. Not only do they run separate modules, but they also copy themselves in many locations, often one for each process the program runs.
It is crucial to note that when the number of split processes increases, the speed of the replicator overall decreases.
Scissor warriors
These warriors are the anti-paper warrior. Their goal is to try and stall and then destroy the replicator. They cannot, under normal circumstances, catch a speedy dwarf however. Falling in this cateogory are scanners and vampires.
Scanners are warriors that check the core at certain intervals. If they find an enemy warriors module, they will attempt to disrupt it there. And once the disruption has taken place, they switch into a process creation mode, where they increase their process number as fast as they can. There are two major types of scanners, Bishot and CMP. Bishot scanners find any foreign instruction and bomb around it, where as CMP actually compares the instruction found to itself to make sure its dealing with a foreign instruction.
Vampires are interesting warriors. They first lay out traps, waiting for a paper to potentially execute the trap. When that occurs, the replicators process is sent to the trap part of the vampire program. The process trapped there, the vampire goes through its replication phase. Eventually, the hope is that the vampire will catch multiple processes and in their running in the vampire that they overwrite each other and lead to each others demise.
Hybrid warriors
There is no real set formula for what warrior will kill another type of warrior. However, each has their own advantage over others. In order to maximize the effectiveness, we create hybrid warriors to try and do what one type of warrior alone cannot.
What’s next?
Well, really, the only thing left is for you to start making warriors yourself. Don’t feel constrained by the examples here or the examples you find on the net. If you have an idea, try to implement it! Once you get it to do what you want, test it out against your other warriors, and if you decide to try stuff live, head over to http://koth.org
KoTH, or King of the Hill, is a site that is devoted to Core War. Each of the “Hills” has 20 positions. To get on the hill you need to do better than the 20th person. Once you get onto KoTH, you notice there are a few different hills. We’re interested in the standard ’94 hill. To submit a warrior, you submit the source code via email. Email your src code to koth@koth.org , and the server will do everything for you. However, you need to make sure you have some stuff in your directives
CODE :
;redcode-94
;name Warrior Name
;author Your Name
;assert 1
The most important parts of these are the redcode directive (tells the server what hill to put you on) and the assertion. If your warrior compiles fine, it will be put against the warriors on the server. You will fight each warrior on the server, 1v1, for 250 matches. You’ll get a score from each warrior. Your average score will determine if you stay on the server or not.
A note on CoreWin:
When writing your own warriors, you may find it easier to understand what’s going on if you step through the program using the core view and single step functions in CoreWin. I’ve found it extremely beneficial while learning how exactly examples I’ve found work.
Conclusion
Core War, while relatively simple, is still extremely difficult to comprehend in the grand scheme of things at first. But once everything runs together, and you actually work with your programs, seeing what they do, you’ll get it.
This article pretty much ran through the basics of using redcode in more varied techniques, as well as looking at what these programs actually do. The applications are quite endless. There is one last thing that neither I, nor apples have gone through, and that is using P-space. But this article is already long enough. Hope you survived!
Cast your vote on this article 10 - Highest, 1 - Lowest
Comments: Published: 4 comments.
HackThisSite is the collective work of the HackThisSite staff, licensed under a CC BY-NC license.
We ask that you inform us upon sharing or distributing.