TITLE "MP4 by Douglas Jones" ; program to make a worm crawl randomly over the screen USE "hawk.h" USE "monitor.h" ; basic variables describing a worm WORMLEN = 10 ; length of the worm MEANTURN= 5 ; mean distance between worm turns MARGIN = 1 ; screen margin (both x and y) DIRBITS = 2 ; number of bits in (maxdir - 1) MAXDIR = (1<= wormlen) { LIS R6,0 ; current = 0 ADVOK: ; } STORE R6,R5,CURRENT ; -- save result LOADS R1,R2 JUMPS R1 ; return SUBTITLE "RANTURN -- occasionally turn the worm" ; activation record for RANTURN ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address RANTURN:; wipes out R3 to R7 STORES R1,R2 ADDI R2,R2,ARSIZE ; -- optimized from here ; first, should we change direction? JSR R1,RANDOM ; r = random() ; -- parameter: dividend = r LIS R5,MEANTURN ; -- parameter: divisor = MEANTURN LIL R1,DIVIDEU JSRS R1,R1 ; q = r / 5 ; r = r % 5 TESTR R4 BZR RANSNO ; if (r = 0) { ; -- turn TRUNC R3,1 ; -- just two possibilities, left and right MOVESL R4,R3,1 ADDSI R4,1 ; lr = (q & 1) * 2 + 1 -- that is, 1 or 3 LIL R5,WORM LOAD R3,R5,DIR ADD R3,R3,R4 TRUNC R3,DIRBITS STORE R3,R5,DIR ; dir = (dir + lr) % MAXDIR RANSNO: ; } ADDI R2,R2,-ARSIZE ; -- optimized to here LOADS R1,R2 JUMPS R1 SUBTITLE "SPIN -- change current worm direction" ; activation record for SPIN unneeded because it doesn't call anything SPIN: ; wipes out R3 to R7 LIL R5,WORM LOAD R6,R5,DIR ADDSI R6,1 TRUNC R6,DIRBITS STORE R6,R5,DIR ; dir = (dir + 1) mod maxdir JUMPS R1 ; return SUBTITLE "RANSPIN -- randomize the worm direction" ; activation record for RANSPIN ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address RANSPIN:; wipes out R3-7 STORES R1,R2 ADDI R2,R2,ARSIZE JSR R1,RANDOM ADDI R2,R2,-ARSIZE TRUNC R3,DIRBITS ; r = random() mod maxdir LIL R5,WORM STORE R3,R5,DIR ; dir = r LOADS R1,R2 JUMPS R1 ; return SUBTITLE "TRYMOVE -- suggest a new place based on current direction" ; activation record for TRYMOVE ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address TRYMOVE:; returns R3 = new x ; R4 = new y ; wipes out R5 to R7 STORES R1,R2 LIL R5,WORM LOAD R6,R5,CURRENT ADDSL R6,R5,3 ; -- r6 points to worm[current] LOADS R3,R6 ; x = worm[current].x LOAD R4,R6,Y ; y = worm[current].y LIL R5,WORM LEA R7,DIRECTIONS LOAD R6,R5,DIR ADDSL R6,R7,3 ; -- r6 points to directions[dir] LOADS R7,R6 ADD R3,R3,R7 ; x = x + directions[dir].x LOAD R7,R6,Y ADD R4,R4,R7 ; y = y + directions[dir].y LOADS R1,R2 JUMPS R1 ; return SUBTITLE "LEGAL -- test legality of suggested move" ; activation record for LEGAL ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address LEGAL: ; expects R3 = x ; coordinates of proposed move ; R4 = y ; returns R3 = x ; if move would be illegal, x = -1 ; R4 = y ; else unchanged ; wipes out R5 to R7 STORES R1,R2 ; -- first, check proposal against margins CMPI R3,MARGIN BLT LEGNOT ; if ((x >= MARGIN) CMPI R4,MARGIN BLT LEGNOT ; && (y >= MARGIN) LIL R5,WORM LOAD R6,R5,MAXX CMP R3,R6 BGT LEGNOT ; && (x <= MAXX) LOAD R6,R5,MAXY CMP R4,R6 BGT LEGNOT ; && (y <= MAXY) { ; -- second, check proposal against worm LIS R7,WORMLEN ; i = wormlen ; j = 0 LEGLP: ; do { LOADS R6,R5 ; -- optimized code, increments worm not j CMP R3,R6 BNE LEGLOK ; if ((x = worm[j].x) LOAD R6,R5,Y CMP R4,R6 BEQ LEGNOT ; && (y = worm[j].y)) break, coord bad LEGLOK: ADDSI R5,8 ; j = j + 1 ADDSI R7,-1 ; i = i - 1 BGT LEGLP ; } while (i > 0) BR LEGOK LEGNOT: ; } else { -- proposed coords are not OK LIS R3,-1 ; x = -1 LEGOK: LOADS R1,R2 JUMPS R1 ; return SUBTITLE "MOVE -- make one legal move, if possible" ; activation record for MOVE ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address ALLOC SVR8, 4, ARSIZE ; save R8 MOVE: ; returns R3 = x ; if move is impossible, x = -1 ; R4 = y ; else unchanged ; wipes out R5 to R7 STORES R1,R2 STORE R8,R2,SVR8 ; first, try moving onward in current direction ADDI R2,R2,ARSIZE JSR R1,TRYMOVE ; (x,y) = trymove() JSR R1,LEGAL ; (x,y) = legal(x,y) ADDI R2,R2,-ARSIZE TESTR R3 BGE MOVEOK ; if not legal { ADDI R2,R2,ARSIZE JSR R1,RANSPIN ; ranspin() to change direction ADDI R2,R2,-ARSIZE LIS R8,4 ; count = 4 MOVELP: ; do { ADDI R2,R2,ARSIZE JSR R1,SPIN ; spin() JSR R1,TRYMOVE ; (x,y) = trymove() JSR R1,LEGAL ; (x,y) = legal(x,y) ADDI R2,R2,-ARSIZE TESTR R3 BGE MOVEOK ; if legal break; ADDSI R8,-1 ; count = count - 1 BGT MOVELP ; if (count = 0) LIL R1,EXIT JSRS R1,R1 ; break; MOVEEL: ; } MOVEOK: ; } LOAD R8,R2,SVR8 LOADS R1,R2 JUMPS R1 ; return SUBTITLE "MAIN program" ; activation record for MAIN ARSIZE = 0 ALLOC RETAD, 4, ARSIZE ; return address INT MAIN S MAIN MAIN: ; expects R3 = w -- screen width ; expects R4 = h -- screen height STORES R1,R2 ; basic initialization LIL R5,WORM ; -- get handle on worm data structure SR R3,1 ADDI R3,R3,-MARGIN STORE R3,R5,MAXX ; maxx = width/2 - margin ADDI R4,R4,-MARGIN STORE R4,R5,MAXY ; maxy = height - margin LIS R3,0 STORE R3,R5,DIR ; dir = 0 (that is, west) STORE R3,R5,CURRENT ; current = 0 ; now put the initial worm on the screen LOAD R3,R5,MAXX ; start the worm near the screen center SR R3,1 ; -- parameter maxx/2 LOAD R3,R5,MAXY SR R4,1 ; -- parameter maxy/2 ADDI R2,R2,ARSIZE JSR R1,PLOT ; plot( maxx/2, maxy/2 ) ADDI R2,R2,-ARSIZE ADDI R2,R2,ARSIZE ; -- optimized LIS R8,WORMLEN-1 ; i = wormlen - 1 INITLP: ; do { JSR R1,MOVE ; (x,y) = move() JSR R1,ADVANCE ; (x,y) = advance(x,y) JSR R1,PLOT ; plot( x, y ) ADDSI R8,-1 ; i = i - 1 BGT INITLP ; } while i > 0 ADDI R2,R2,-ARSIZE ; -- optimized ; main loop, running the worm until it dies RUNLP: ; do { ADDI R2,R2,ARSIZE JSR R1,RANTURN ; ranturn() JSR R1,MOVE ; (x,y) = move() JSR R1,ADVANCE ; (x,y) = advance(x,y) JSR R1,UNPLOT ; (x,y) = unplot(x,y) JSR R1,PLOT ; plot(x,y) ADDI R2,R2,-ARSIZE BR RUNLP ; } forever LOADS R1,R2 JUMPS R1 ; return END