[{"data":1,"prerenderedAt":327},["ShallowReactive",2],{"learn:invaders:06-row":3},{"item":4,"marksAgainst":326},{"slug":5,"number":6,"title":7,"idea":8,"models":9,"body":12,"tryIt":273,"game":308,"cites":309,"program":325},"06-row",6,"A row of invaders","a table of screen addresses, walked with IX and counted with DJNZ",[10,11],3,1,[13,35,39,43,111,114,126,129,143,146,151,153,179,201,204,232,235,239,241,259,262,266,269],{"kind":14,"inlines":15},"p",[16,19,22,24,25,27,29,31,33],{"kind":17,"text":18},"text","One invader becomes eight, side by side on row 2, four cells apart. Chapter 5 kept the invader's place in a byte, ",{"kind":20,"text":21},"code","INVX",{"kind":17,"text":23},"; eight invaders would need eight such bytes and eight routines to draw them. Instead their places go in a table, one entry an invader, and one routine walks down the table and draws each. That is the first chapter that takes a line out: ",{"kind":20,"text":21},{"kind":17,"text":26}," goes, and ",{"kind":20,"text":28},"DRAWINV",{"kind":17,"text":30}," is reworked into ",{"kind":20,"text":32},"DRAWROW",{"kind":17,"text":34},".",{"kind":36,"id":37,"text":38},"h2","what-changed","What changed",{"kind":14,"inlines":40},[41],{"kind":17,"text":42},"Chapter 5's program, with these changes:",{"kind":44,"items":45},"ul",[46,52,70,78,88,100],[47,50],{"kind":48,"text":49},"strong","~",{"kind":17,"text":51}," The comment at the top, lines 1 to 5, now describes chapter 6.",[53,54,56,57,59,60,62,64,66,68],{"kind":48,"text":49},{"kind":17,"text":55}," ",{"kind":20,"text":28},{"kind":17,"text":58}," becomes ",{"kind":20,"text":32},{"kind":17,"text":61},". Its comment and its first lines, lines 97 to 106, are changed, and lines 107 to 116, the rest of its loop, are new; its last two lines, ",{"kind":20,"text":63},"POP BC",{"kind":17,"text":65}," and ",{"kind":20,"text":67},"RET",{"kind":17,"text":69},", stay as they were.",[71,72,74,77],{"kind":48,"text":49},{"kind":17,"text":73}," The game loop's comment: its last line now ends ",{"kind":75,"text":76},"em","the base, the shot, the invaders",{"kind":17,"text":34},[79,80,82,84,85,87],{"kind":48,"text":49},{"kind":17,"text":81}," The two lines in the loop that drew the invader, lines 137 and 138, now draw the row: ",{"kind":20,"text":83},"LD DE,INVADER",{"kind":17,"text":65},{"kind":20,"text":86},"CALL DRAWROW",{"kind":17,"text":34},[89,91,92,94,96,98],{"kind":48,"text":90},"+",{"kind":17,"text":55},{"kind":20,"text":93},"INVS",{"kind":17,"text":95},", after ",{"kind":20,"text":97},"INVADER",{"kind":17,"text":99},", lines 146 to 148: a comment, and the table of the invaders' places.",[101,103,104,105,107,109],{"kind":48,"text":102},"−",{"kind":17,"text":55},{"kind":20,"text":21},{"kind":17,"text":106},", the invader's column, is taken out: the table holds the places now. Below the program, under ",{"kind":75,"text":108},"lines taken out",{"kind":17,"text":110},", it shows struck through.",{"kind":36,"id":112,"text":113},"a-table-of-places","A table of places",{"kind":14,"inlines":115},[116,118,120,122,124],{"kind":17,"text":117},"Each invader's place is its screen address, a word, as the shot's is. Row 2 starts at ",{"kind":20,"text":119},"3C80H",{"kind":17,"text":121},", so an invader in column 14 is at ",{"kind":20,"text":123},"3C80H+14",{"kind":17,"text":125},", and the assembler works out the sum:",{"kind":20,"lang":127,"text":128},"z80","INVS:   DW      3C80H+14,3C80H+18,3C80H+22,3C80H+26\n        DW      3C80H+30,3C80H+34,3C80H+38,3C80H+42",{"kind":14,"inlines":130},[131,133,135,137,139,141],{"kind":20,"text":132},"DW",{"kind":17,"text":134}," with several values lays them down one after another, two bytes each, low byte first: sixteen bytes, eight invaders. The fifth, ",{"kind":20,"text":136},"3C80H+30",{"kind":17,"text":138},", is where chapter 5's invader stood. In JavaScript the table is an array, ",{"kind":20,"text":140},"const invs = [0x3C8E, 0x3C92, …]",{"kind":17,"text":142},", and drawing the row is a loop over it.",{"kind":36,"id":144,"text":145},"ix-walks-the-table","IX walks the table",{"kind":14,"inlines":147},[148,149],{"kind":20,"text":32},{"kind":17,"text":150}," points IX at the table and reads each word through it:",{"kind":20,"lang":127,"text":152},"        LD      IX,INVS         ; IX points at the table's first word\n        LD      B,8             ; eight invaders, counted down by DJNZ\nDRAWONE:\n        LD      L,(IX+0)        ; this invader's screen address: the low byte\n        LD      H,(IX+1)        ; first, then the high, as a DW stores them",{"kind":14,"inlines":154},[155,157,159,161,163,164,165,167,169,171,173,175,177],{"kind":17,"text":156},"IX is a 16-bit register like HL, made for this. ",{"kind":20,"text":158},"(IX+1)",{"kind":17,"text":160}," is the byte one after the one IX points at: the number after the plus is an offset, a signed byte from -128 to 127, fixed when the program is assembled. So ",{"kind":20,"text":162},"(IX+0)",{"kind":17,"text":65},{"kind":20,"text":158},{"kind":17,"text":166}," are the two bytes of the current entry, and after drawing it, two ",{"kind":20,"text":168},"INC IX",{"kind":17,"text":170}," move IX to the next. IX costs time: each IX instruction carries an extra prefix byte, and ",{"kind":20,"text":172},"LD L,(IX+0)",{"kind":17,"text":174}," takes 19 T-states where ",{"kind":20,"text":176},"LD L,(HL)",{"kind":17,"text":178}," takes 7. Here the two loads are 38 of the 117 T-states each invader takes, in a turn of over 134,000.",{"kind":14,"inlines":180},[181,183,184,186,188,189,191,193,195,197,199],{"kind":17,"text":182},"HL now holds where to draw, so the shape moves to DE: the loop loads ",{"kind":20,"text":83},{"kind":17,"text":185},", where chapter 5 loaded HL. Each invader is two bytes copied from (DE) to (HL), with ",{"kind":20,"text":187},"INC HL",{"kind":17,"text":65},{"kind":20,"text":190},"INC DE",{"kind":17,"text":192}," between them, and ",{"kind":20,"text":194},"DEC DE",{"kind":17,"text":196}," after puts DE back at the shape's start for the next one. ",{"kind":20,"text":198},"LDIR",{"kind":17,"text":200}," could copy them, but it counts in BC, and B is counting invaders.",{"kind":36,"id":202,"text":203},"djnz-counts-the-invaders","DJNZ counts the invaders",{"kind":14,"inlines":205},[206,208,210,212,214,216,218,219,221,223,225,226,228,230],{"kind":20,"text":207},"DJNZ DRAWONE",{"kind":17,"text":209}," is ",{"kind":75,"text":211},"decrement B and jump if not zero",{"kind":17,"text":213},": B goes down by 1, and the jump back is taken unless B has reached 0. It is a counted loop in one instruction, ",{"kind":20,"text":215},"do { … } while (--b !== 0)",{"kind":17,"text":217},", and it sets no flags. B is the only register it counts with, so ",{"kind":20,"text":32},{"kind":17,"text":220}," saves BC with ",{"kind":20,"text":222},"PUSH BC",{"kind":17,"text":224}," and puts it back with ",{"kind":20,"text":63},{"kind":17,"text":227},", as ",{"kind":20,"text":229},"DRAWBASE",{"kind":17,"text":231}," does.",{"kind":36,"id":233,"text":234},"the-row-every-turn","The row, every turn",{"kind":14,"inlines":236},[237],{"kind":17,"text":238},"The loop draws the whole row every turn, as chapter 5 drew its one invader, so a shot that passes through an invader's cell is mended over at once:",{"kind":20,"lang":127,"text":240},"        LD      DE,INVADER      ; the row, drawn every turn: a shot passing\n        CALL    DRAWROW         ; through an invader erases a cell, and this mends it",{"kind":14,"inlines":242},[243,245,246,248,250,252,253,255,257],{"kind":17,"text":244},"Drawing eight invaders costs 1,010 T-states a turn: ",{"kind":20,"text":83},{"kind":17,"text":247}," 10, ",{"kind":20,"text":249},"CALL",{"kind":17,"text":251}," 17, and 983 in ",{"kind":20,"text":32},{"kind":17,"text":254},", of which each invader takes 117, 5 fewer for the last, where ",{"kind":20,"text":256},"DJNZ",{"kind":17,"text":258}," does not jump. A turn with no key down is now 134,344 T-states. Fugløy runs the Model III at 2.03 MHz, so that is still about 66 ms.",{"kind":36,"id":260,"text":261},"keys-go-to-the-screen-not-the-editor","Keys go to the screen, not the editor",{"kind":14,"inlines":263},[264],{"kind":17,"text":265},"Click the TRS-80's screen before you press the arrows or the space bar, so that it has the keyboard.",{"kind":36,"id":267,"text":268},"on-the-model-i","On the Model I",{"kind":14,"inlines":270},[271],{"kind":17,"text":272},"The Model I has the same keyboard row and the same screen, so the program runs unchanged. Fugløy runs the Model I at 1.77 MHz, so a turn there takes about 76 ms.",[274,278],{"kind":14,"inlines":275},[276],{"kind":17,"text":277},"Fire without moving the base: the shot rises in column 31, through the fifth invader's right cell, and goes behind it, as in chapter 5.",{"kind":14,"inlines":279},[280,282,283,285,287,289,291,293,295,297,298,300,302,304,306],{"kind":17,"text":281},"Then change the last entry of ",{"kind":20,"text":93},{"kind":17,"text":284},", ",{"kind":20,"text":286},"3C80H+42",{"kind":17,"text":288},", to ",{"kind":20,"text":290},"3C40H+42",{"kind":17,"text":292}," and press Run ▶. Row 1 starts at ",{"kind":20,"text":294},"3C40H",{"kind":17,"text":296},", so the eighth invader now stands a row higher than the others. Nothing else changed: ",{"kind":20,"text":32},{"kind":17,"text":299}," draws whatever places the table holds. Change ",{"kind":20,"text":301},"LD B,8",{"kind":17,"text":303}," to ",{"kind":20,"text":305},"LD B,7",{"kind":17,"text":307}," and the eighth is not drawn at all.",null,[310,314,318,322],{"source":311,"page":312,"about":313},"m3-trm","14","the Model III's keyboard is memory at 3800H-3BFFH, and its screen at 3C00H",{"source":315,"page":316,"about":317},"m1-trh","12","the Model I's keyboard is memory from 3800H, and its screen at 3C00H",{"source":319,"page":320,"about":321},"decker","64","the keyboard's rows are read at 3801H to 3840H, one address a row",{"source":323,"page":324,"about":321},"paay","26","; Build Space Invaders, chapter 6: a row of invaders. Chapter 5's base and\n; shot, and on row 2 eight invaders, four cells apart. Where each one is, is\n; a word in a table, INVS: its screen address. DRAWROW walks the table with\n; IX and draws each; the loop draws the row every turn, so a shot still goes\n; behind the invaders. They stand still for now, and marching comes next.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MOVEBASE: with the left or right arrow down, erase the base, move it a\n; column, and draw it again. Columns 0 and 61 are the edges: there it stays.\nMOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free\n        LD      HL,BLANK        ; erase the base where it is\n        CALL    DRAWBASE\n        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory\n        LD      HL,BASE         ; draw the base there\n        CALL    DRAWBASE\n        RET\n\n; MOVESHOT: the shot, if there is one, moves up a row; past row 0 it is gone.\nMOVESHOT:\n        LD      HL,(SHOT)       ; where the shot is: two bytes from memory into HL\n        LD      A,H             ; 0 is no shot: test HL as the clear tests BC\n        OR      L\n        RET     Z               ; no shot: nothing to do\n        LD      (HL),20H        ; erase the shot where it is\n        LD      DE,-64          ; up a row\n        ADD     HL,DE\n        BIT     2,H             ; still on the screen? 3C00H-3FFFH all have bit 2 of H set\n        JR      NZ,SHOTUP\n        LD      HL,0            ; off the top: no shot\nSHOTUP: LD      (SHOT),HL       ; keep where it is, or 0\n        LD      A,H\n        OR      L\n        RET     Z               ; gone: nothing to draw\n        LD      (HL),21H        ; the shot is an exclamation mark\n        RET\n\n; FIRE: with the space bar down and no shot in the air, a shot starts on\n; row 14, just above the base's middle cell.\nFIRE:   LD      A,(3840H)       ; the space bar is bit 7 of the arrows' row\n        BIT     7,A\n        RET     Z               ; not down: nothing to do\n        LD      HL,(SHOT)\n        LD      A,H\n        OR      L\n        RET     NZ              ; a shot is in the air already: one at a time\n        LD      A,(BASEX)       ; row 14 starts at 3F80H; the base's middle\n        ADD     A,81H           ; is its column plus one: 3F81H plus BASEX\n        LD      L,A\n        LD      H,3FH\n        LD      (HL),21H        ; draw the shot\n        LD      (SHOT),HL       ; and remember where it is\n        RET\n\n; DRAWROW: copy the two bytes DE points at to every invader's place: INVS\n; holds their screen addresses, a word each. IX walks the table and B counts\n; the invaders; BC is kept on the stack, and DE ends where it began.\nDRAWROW:\n        PUSH    BC              ; save BC: B counts the invaders\n        LD      IX,INVS         ; IX points at the table's first word\n        LD      B,8             ; eight invaders, counted down by DJNZ\nDRAWONE:\n        LD      L,(IX+0)        ; this invader's screen address: the low byte\n        LD      H,(IX+1)        ; first, then the high, as a DW stores them\n        LD      A,(DE)          ; the shape's left cell\n        LD      (HL),A\n        INC     HL\n        INC     DE\n        LD      A,(DE)          ; and its right cell\n        LD      (HL),A\n        DEC     DE              ; back to the shape's start, for the next one\n        INC     IX              ; on to the next word of the table\n        INC     IX\n        DJNZ    DRAWONE         ; B minus 1, and the next invader until it is 0\n        POP     BC              ; BC as the caller left it\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them: the base, the shot, the invaders.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        CALL    MOVEBASE        ; the base moves if an arrow is down\n        CALL    MOVESHOT        ; the shot, if there is one, rises a row\n        CALL    FIRE            ; the space bar starts a shot, if there is none\n        LD      DE,INVADER      ; the row, drawn every turn: a shot passing\n        CALL    DRAWROW         ; through an invader erases a cell, and this mends it\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBLANK:  DB      '   '           ; three spaces, to erase it\nINVADER:\n        DB      9EH,0ADH        ; an invader: two cells, a head, arms and legs\n; INVS: the invaders' places, each row 2's start, 3C80H, plus a column.\nINVS:   DW      3C80H+14,3C80H+18,3C80H+22,3C80H+26\n        DW      3C80H+30,3C80H+34,3C80H+38,3C80H+42\nBASEX:  DB      30              ; the base's column, 0 to 61\nSHOT:   DW      0               ; the shot's screen address, or 0 for none\n\n        END     START           ; the program starts at START\n","; Build Space Invaders, chapter 5: one invader. Chapter 4's base and shot,\n; and above them on row 2, at the column INVX holds, an invader: two cells,\n; drawn by DRAWINV as DRAWBASE draws the base. The loop draws it every turn,\n; so that a shot passing through it leaves no hole: the shot goes behind it\n; for now, and hitting it comes later.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MOVEBASE: with the left or right arrow down, erase the base, move it a\n; column, and draw it again. Columns 0 and 61 are the edges: there it stays.\nMOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free\n        LD      HL,BLANK        ; erase the base where it is\n        CALL    DRAWBASE\n        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory\n        LD      HL,BASE         ; draw the base there\n        CALL    DRAWBASE\n        RET\n\n; MOVESHOT: the shot, if there is one, moves up a row; past row 0 it is gone.\nMOVESHOT:\n        LD      HL,(SHOT)       ; where the shot is: two bytes from memory into HL\n        LD      A,H             ; 0 is no shot: test HL as the clear tests BC\n        OR      L\n        RET     Z               ; no shot: nothing to do\n        LD      (HL),20H        ; erase the shot where it is\n        LD      DE,-64          ; up a row\n        ADD     HL,DE\n        BIT     2,H             ; still on the screen? 3C00H-3FFFH all have bit 2 of H set\n        JR      NZ,SHOTUP\n        LD      HL,0            ; off the top: no shot\nSHOTUP: LD      (SHOT),HL       ; keep where it is, or 0\n        LD      A,H\n        OR      L\n        RET     Z               ; gone: nothing to draw\n        LD      (HL),21H        ; the shot is an exclamation mark\n        RET\n\n; FIRE: with the space bar down and no shot in the air, a shot starts on\n; row 14, just above the base's middle cell.\nFIRE:   LD      A,(3840H)       ; the space bar is bit 7 of the arrows' row\n        BIT     7,A\n        RET     Z               ; not down: nothing to do\n        LD      HL,(SHOT)\n        LD      A,H\n        OR      L\n        RET     NZ              ; a shot is in the air already: one at a time\n        LD      A,(BASEX)       ; row 14 starts at 3F80H; the base's middle\n        ADD     A,81H           ; is its column plus one: 3F81H plus BASEX\n        LD      L,A\n        LD      H,3FH\n        LD      (HL),21H        ; draw the shot\n        LD      (SHOT),HL       ; and remember where it is\n        RET\n\n; DRAWINV: copy the two bytes HL points at to the invader's place on row 2,\n; 3C80H plus INVX. BC is kept on the stack, as DRAWBASE keeps it.\nDRAWINV:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(INVX)        ; the invader's column ...\n        ADD     A,80H           ; ... plus 3C80H, row 2: the invader's left cell\n        LD      E,A\n        LD      D,3CH\n        LD      BC,2            ; two bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them: the base, the shot, the invader.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        CALL    MOVEBASE        ; the base moves if an arrow is down\n        CALL    MOVESHOT        ; the shot, if there is one, rises a row\n        CALL    FIRE            ; the space bar starts a shot, if there is none\n        LD      HL,INVADER      ; the invader, drawn every turn: a shot passing\n        CALL    DRAWINV         ; through it erases a cell, and this mends it\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBLANK:  DB      '   '           ; three spaces, to erase it\nINVADER:\n        DB      9EH,0ADH        ; an invader: two cells, a head, arms and legs\nBASEX:  DB      30              ; the base's column, 0 to 61\nSHOT:   DW      0               ; the shot's screen address, or 0 for none\nINVX:   DB      30              ; the invader's column, 0 to 62\n\n        END     START           ; the program starts at START\n",1792464471290]