--- title: "Core Wars" type: "article" slug: "core-wars" url: "http://localhost/article/core-wars/" markdown_url: "http://localhost/article/core-wars.md" published_at: "2025-11-26T19:57:51+00:00" modified_at: "2026-06-21T23:20:36+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "A while back I took a week off from work to spend time at home finishing some programming projects (hey, I had plenty of leave stored up). One of the projects that I finished was in implementation of Core Wars for the QL. Below is the documentation that I wrote for the program. It details…" category: - name: "QL Hacker's Journal" slug: "ql-hackers-journal" taxonomy: "category" url: "http://localhost/category/periodicals/ql-hackers-journal/" post_tag: - name: "C (programming language)" slug: "c-programming-language" taxonomy: "post_tag" url: "http://localhost/tag/c-programming-language/" - name: "Full Text" slug: "fulltext" taxonomy: "post_tag" url: "http://localhost/tag/fulltext/" - name: "QL" slug: "ql" taxonomy: "post_tag" url: "http://localhost/tag/ql/" - name: "Type-in program" slug: "type-in-program" taxonomy: "post_tag" url: "http://localhost/tag/type-in-program/" model: - name: "Sinclair QL" slug: "sinclair-ql" taxonomy: "model" url: "http://localhost/model/sinclair-ql/" indiv: - name: "Tim Swenson" slug: "tim-swenson" taxonomy: "indiv" url: "http://localhost/indiv/tim-swenson/" publication_r: id: 33686 title: "QL Hacker’s Journal" type: "periodical" url: "http://localhost/periodical/ql-hackers-journal/" authors_r: - name: "Tim Swenson" slug: "tim-swenson" taxonomy: "indiv" url: "http://localhost/indiv/tim-swenson/" issue: "7" issues_articles: - id: 61543 title: "QL Hacker’s Journal 7" type: "issue" url: "http://localhost/issue/ql-hackers-journal-7/" pubdate: "January 1992" archive_link: true --- # Core Wars A while back I took a week off from work to spend time at home finishing some programming projects (hey, I had plenty of leave stored up). One of the projects that I finished was in implementation of Core Wars for the QL. Below is the documentation that I wrote for the program. It details the whole program. ### INTRODUCTION Core Wars is a game where programs that the user’s write, battle with each other in the computer. This game is taken from the Computer Receations column of Scientific American. The game was conceived by A. K. Dewdney. Two programs are loaded into “memory” and then each program is executed in turn, one line at a time. When the computer can not execute a command from one of the programs, it declares that program to be the loser. Programs are written in an assembly-like language called REDCODE. The syntax of REDCODE will be explained later. ### HOW TO RUN THE PROGRAM Use LRUN to load and run the SuperBasic version. When the program starts you will be asked to enter the file name of the first program. All REDCODE programs are stored in a separate file and then loaded by the program. Enter the name file containing one of the REDCODE programs you want to run. You must include the drive name (flp1_, mdv1_, etc). A number of sample programs are included on the distribution disk. They have the _CW extention. You will be prompted for the file name of the second REDCODE program you want to run. You man run any combination of REDCODE program. The screen will clear and two different windows will appear. As each program executes, the current line of the program will be printed in the window designated for it. It will also print the memory location at which that line is stored. An example is: ``` 392 MOV -1 0 ``` This shows that the command MOV -1 0 was executed a memory location 392. These windows will allow you to see each program as they execute. Below these windows is an area that will display the results of each program as they move through memory. Memory consists of 1000 memory locations. A graphics display of memory had been broken down to two lines of 500 pixels. As each program affects memory, it will be reflected in this graphics display. You will not see the display at first, since empty memory locations are black. Memory locations affected by Program 1 will appear as green, where as those affected by Program 2 will appear as red. This display will vividly show you how the progams are moving through memory and where they stand in relation to each other. When a REDCODE program line can not be executed, the word “ERROR” will be printed in the window of the losing REDCODE program and the Core Wars program will stop and return you to QDOS. ### REDCODE PROGRAMMING REDCODE is an assembly-like language consisting of commands and operands. Each line of the program has one command and one or two operands, depending on the specific command. Below are the REDCODE commands: ``` MOV A B - Move Move contents of address A to address B ADD A B - Add Add contents of address A to the contents of address B and store results in address B SUB A B - Subtract Subtract contents of address A from contents of address B and store results in address B JMP A - Jump Transfer control (goto) to address A JMZ A - Jump Zero Jump to address A if contents of address B are equal to zero JMG A - Jump Greater Than Zero Jump to address A if contents of address B are greater than zero JMN A - Jump Not Zero Jump to address A if contents of address B are not equal to zero DJZ A B - Decrement Jump Zero Subtract (decrement) 1 from the contents of address B and jump to address A if the contents of address B are equal to zero DJN A B - Decrement Jump Not Zero Decrement 1 from the contents of address B and jump to address A if the contents of address B are not equal to zero CMP A B - Compare Compare contents of address A and B then skip the next instruction if not equal DAT A - Data Non-executing statement. Used to make a memory location useable for storage of data ``` All REDCODE addresses are relative. PC is the Program Counter. The Program Counter controls the execution of the programs and is equivilent to the memory location of the current program line. MOV 0 1 means to put the contents of address PC+0 (the current line) and put it in address PC+1 (the next line). Negative numbers are used to mean lines before the PC. REDCODE does make provisions for direct and indirect addressing. A # before a number is direct addressing and an @ is used for indirect. MOV #0 1 means to put the number 0 in the address PC+1. The indirect commands: ``` DAT 20 MOV 0 @-1 ``` means to put the contents of address PC+0 and store it at the address pointed at by the number at PC-1 (the previous line). This will put the MOV 0 @-1 line at PC+20. Note that you must use a DAT statment and not just store the number 20 at that memory location. This is what the DAT statement is for. Indirect addressing may be used for both A and B operands, direct may be used for A, and direct may only be used for B with the CMP command. All other commands may not use direct addressing of B. The MOV and DAT commands interact differently together. If you MOV #0 20 and address PC+20 is a DAT statement, the DAT 0 is stored at address PC+20. If there is no DAT steatement, the only 0 is stored at PC+20. This second case is used to put “logic bombs” into other programs, so that when the 0 is reached, the Core Wars program has reached an unexecutable command line and that program loses. ### REDCODE PROGRAM FILES REDCODE programs are stored in a separate file and loaded at runtime. The file is an ASCII file created with an ASCII editor, like ED, or The Editor. Each command line is on a separate line. No blank lines are allowed in the file. The commands must start in the first column. Only 1 space may separate commands and operands. Comments are allowed by using a # in the first column. With a # comment, the entire line is commented out and is ignored by the Core Wars program. See the example REDCODE programs included on the distribution disk to help clarify any questions you may have. ``` ** Program Name: CoreWars ** Version: 2.0 ** Author: Timothy Swenson ** Date Created: 17 Oct 1990 ** Date Revised: 19 Oct 1990 ** The is an implementation of Core Wars as found in the ** Computer Recreations column in Scientific American. top_mem=1000 DIM memory$(top_mem,14) @label pc_prg1 = RND(1 TO 1000) pc_prg2 = RND(1 TO 1000) IF ABS(pc_prg1-pc_prg2)=100 THEN GO TO @label OPEN #3,con_512x256a0x0_32 PAPER #3,0 : INK #3,4 : CLS #3 title PRINT #3 PRINT #3,TO 30;"Version 2.0" PRINT #3,TO 26;"By Timothy Swenson"\\ load_prg(pc_prg1) load_prg(pc_prg2) CLS #3 title OPEN #4,scr_200x150a51x51 OPEN #5,scr_200x150a262x51 BORDER #4,2,4 : BORDER #5,2,4 PAPER #4,2 : INK #4,1 PAPER #5,2 : INK #5,1 CLS #4 : CLS #5 CURSOR #3,70,40 PRINT #3," P R O G R A M # 1" CURSOR #3,300,40 PRINT #3," P R O G R A M # 2" REPeat main_loop pc_main = pc_prg1 prog=1 cmd$=memory$(pc_main) PRINT #4,pc_main;" ";cmd$ sep_line evaluate plot_mem pc_prg1 IF pc_prg1=pc_main THEN pc_prg1=pc_prg1+1 ELSE pc_prg1=pc_main END IF pc_main = pc_prg2 prog=2 cmd$=memory$(pc_main) PRINT #5,pc_main;" ";cmd$ sep_line evaluate plot_mem pc_prg2 IF pc_prg2=pc_main THEN pc_prg2=pc_prg2+1 ELSE pc_prg2=pc_main END IF IF pc_prg1>top_mem THEN pc_prg1=pc_prg1-top_mem IF pc_prg2>top_mem THEN pc_prg2=pc_prg2-top_mem END REPeat main_loop STOP DEFine PROCedure title LOCal x,y x=150 : y=10 CSIZE #3,3,1 OVER #3,1 INK #3,2 FOR z = 1 to 5 CURSOR #3,x-z,y-z PRINT #3,"CORE WARS" NEXT z INK #3,4 CURSOR #3,x-6,y-6 PRINT #3,"CORE WARS" CSIZE #3,0,0 END DEFine title DEFine PROCedure load_prg (location) INPUT #3,"Enter file name for Program : ";file_name$ OPEN_IN #6,file_name$ REPeat loop1 INPUT #6,in$ IF EOF(#6) THEN EXIT loop1 IF in$(1)="#" THEN END REPeat loop1 memory$(location)=in$ location=location+1 END REPeat loop1 CLOSE #6 END DEFine load_prg DEFine PROCedure plot_mem (num) LOCal x,y,c IF prog=1 THEN c=4 IF prog=2 THEN c=2 IF num>500 THEN x=num-500 y=235 ELSE x=num y=225 END IF BLOCK #3,1,2,x,y,c END DEFine plot_mem DEFine FuNction get_num(address) LOCal temp$ temp$=memory$(address) IF temp$="" THEN goto_error IF temp$(1 TO 3) <> "DAT" THEN goto_error RETurn temp$(5 TO) END DEFine get_num DEFine PROCedure sep_line LOCal blank IF LEN(cmd$)<5 THEN goto_error arg2 = 0 opcode$=cmd$(1 TO 3) cmd$=cmd$(5 TO) opmodea=1 : opmodeb=1 IF cmd$(1)="#" THEN opmodea=0 IF cmd$(1)=CHR$(64) THEN opmodea=2 IF opmodea<>1 THEN cmd$=cmd$(2 TO) IF (opcode$="JMP") OR (opcode$="DAT") THEN arg1=cmd$ : RETurn blank = " " INSTR cmd$ arg1 = cmd$(1 TO blank-1) cmd$=cmd$(blank+1 TO) IF cmd$(1)="#" THEN opmodeb=0 IF cmd$(1)=CHR$(64) THEN opmodeb=2 IF opmodeb<>1 THEN cmd$=cmd$(2 TO) arg2=cmd$ END DEFine sep_line DEFine PROCedure evaluate IF opmodea=0 THEN a=arg1 IF opmodea=1 THEN a=pc_main+arg1 IF opmodea=2 THEN a=pc_main+get_num(pc_main+arg1) IF opmodeb=0 AND opcode$<>"CMP" THEN PRINT #0,"Direct mode not allowed to second argguement ": STOP IF opmodeb=0 THEN b=arg2 IF opmodeb=1 THEN b=pc_main+arg2 IF opmodeb=2 THEN b=pc_main+get_num(pc_main+arg2) IF a>top_mem THEN a=a-top_mem IF b>top_mem THEN b=b-top_mem IF opcode$="MOV" THEN MOV: RETurn IF opcode$="ADD" THEN ADD: RETurn IF opcode$="SUB" THEN SUBT: RETurn IF opcode$="JMP" THEN JMP: RETurn IF opcode$="JMZ" THEN JMZ: RETurn IF opcode$="JMG" THEN JMG: RETurn IF opcode$="JMN" THEN JMN: RETurn IF opcode$="DJZ" THEN DJZ: RETurn IF opcode$="DJN" THEN DJN: RETurn IF opcode$="CMP" THEN CMP: RETurn IF opcode$="DAT" THEN RETurn goto_error END DEFine evaluate DEFine PROCedure goto_error IF prog=1 THEN PRINT #4," E R R O R" IF prog=2 THEN PRINT #5,"E R R O R" FOR xx = 1 to 4 BEEP 1000,10 NEXT xx STOP END DEFine goto_error DEFine PROCedure MOV IF opmodea=0 THEN temp$=memory$(b)&" " IF temp$(1 TO 3)="DAT" THEN memory$(b)="DAT "&a ELSE memory$(b)=a END IF ELSE memory$(b)=memory$(a) END IF plot_mem b END DEFine MOV DEFine PROCedure ADD LOCal temp IF opmodea=0 THEN temp=get_num(b)+a ELSE temp=get_num(b)+get_num(a) END IF memory$(b)="DAT "&temp END DEFine ADD DEFine PROCedure SUBT LOCal temp IF opmodea=0 THEN temp=get_num(b)-a ELSE temp=get_num(b)+get_num(a) END IF memory$(b)="DAT "&temp END DEFine SUBT DEFine PROCedure JMP pc_main = a END DEFine JMP DEFine PROCedure JMZ LOCal temp temp = get_num(b) IF temp=0 THEN JMP END DEFine JMZ DEFine PROCedure JMG LOCal temp temp = get_num(b) IF temp>0 THEN JMP END DEFine JMG DEFine PROCedure JMN LOCal temp temp = get_num(b) IF temp<>0 THEN JMP END DEFine JMN DEFine PROCedure DJZ LOCal temp temp = get_num(b) temp=temp-1 memory$(b)="DAT "&temp IF temp=0 THEN JMP END DEFine DJZ DEFine PROCedure DJN LOCal temp temp = get_num(b) temp=temp-1 memory$(b)="DAT "&temp IF temp<>0 THEN JMP END DEFine DJN DEFine PROCedure CMP LOCal tempa,tempb IF opmodea=0 THEN tempa=a ELSE tempa=get_num(a) END IF IF opmodeb=0 THEN tempb=b ELSE tempb=get_num(b) END IF IF tempa<>tempb THEN pc_main=pc_main+2 END DEFine CMP DEFine PROCedure list_memory FOR x=1 TO top_mem PRINT memory$(x) NEXT x END DEFine list_memory ``` Example Core War Programs: (indented only for publication. Code must start in the first column) ``` IMP_CW: MOV 0 1 DWARF_CW: DAT -1 ADD #5 -1 MOV #0 @-2 JMP -2 GEMINI_CW: DAT 0 DAT 99 MOV @-2 @-1 CMP -3 #9 JMP 4 ADD #1 -5 ADD #1 -5 JMP -5 MOV #99 93 JMP 93 ```