001: ; genius.g
002: 
003: ; a variant of brilliant.g
004: ; avoid following another [lower-numbered] ghost
005: 
006: 
007: ;;; constant: scatter period, scatter mode time is 1 over this period
008:         %scatter_period :: 10
009: 
010: ;;; variables
011: %lastx :: [1]
012: %lasty :: [2]
013: %clkl :: [3]
014: %clkh :: [4]
015: %curmode :: [5]        ; 0 = chase, 1 = scatter
016: %scatterx :: [6]
017: %scattery :: [7]
018: %principal :: [8]
019: %secondary :: [9]
020:         %uturn :: [10]
021:         %test_dir :: [11]
022: 
023: ;;; declarations for check_presence
024:         %return_eq :: [245]
025:         %return_neq :: [246]
026: 
027: ;;; declarations for follow
028:         %ghost_index :: [247]
029: %good_dir_val     :: [248]
030: %good_dir_num     :: [249]
031: %current_x   :: [250]
032: %current_y   :: [251]
033: %current_dir :: [252]
034: ;;; %follow_return :: [253]
035: 
036: ;;; declarations for next
037: ;;; %next_arg_dir :: [254]
038: ;;; %next_return :: [255]
039: 
040: ; clock
041:   add %clkl, 10               ; clock high period 128/10 = 10 moves
042:   jlt clock_done, %clkl, 128
043:   inc %clkh
044:   mov %clkl, 0
045: clock_done:
046: 
047: ; detect sudden jumps in position and reset the clock
048:   int 3
049:   int 5
050:   sub a, %lastx
051:   sub b, %lasty
052:   add a, b
053:   add a, 1
054:   jlt detect_done, a, 3
055: ;;; sudden jump detected. if we are in invisible mode, that means
056: ;;; we were just eaten and in that case we don't reset the clock
057:         int 3
058:         int 6
059:         jeq detect_done, a, 2
060:   mov %clkl, 0
061:   mov %clkh, 0
062: detect_done:
063:   int 3
064:   int 5
065:   mov %lastx, a
066:   mov %lasty, b
067: 
068: ; decide between chase and scatter
069: 
070: ; if panic mode, scatter
071: 
072:   int 3
073:   int 6
074:   jeq scatter, a, 1    ; panic mode -> scatter
075:   jeq chase, a, 2      ; invisible mode -> chase
076:                        ; normal mode -> scatter/chase according to clock
077: 
078: ; if clock-high = 0 mod %scatter_period, then scatter
079:         mov d, %clkh
080:         div d, %scatter_period
081:         mul d, %scatter_period
082:         mov c, %clkh
083:         sub c, d
084:         ;; mov e, %clkh            ; debug
085:         ;; mov f, %clkl            ; debug
086:         ;; int 8                   ; debug
087:         jgt chase, c, 0
088: 
089: scatter:
090:   jeq scatter_continue, %curmode, 1
091:   mov %curmode, 1
092:   mov c, %clkh
093:   div c, 8
094:   int 3
095:   add a, c
096:   mov %scatterx, a
097:   div a, 2
098:   mov %scattery, a
099:   and %scatterx, 1
100:   and %scattery, 1
101:   mul %scatterx, 30
102:   mul %scattery, 30
103:   sub %scatterx, 15
104:   sub %scattery, 15
105:   int 3
106:   int 1
107:   add %scatterx, a
108:   add %scattery, b
109:   jlt clipxdone, %scatterx, 128
110:   mov %scatterx, 0
111: clipxdone:
112:   jlt clipydone, %scattery, 128
113:   mov %scattery, 0
114: clipydone:
115: scatter_continue:
116:   mov a, %scatterx
117:   mov b, %scattery
118:   jmp go_to
119: 
120: chase:
121:   mov %curmode, 0
122:   int 1     ; get lman's coordinates in A and B
123: 
124: go_to:
125:         mov c, a  ; c = lman.x
126:   mov d, b  ; d = lman.y
127:   int 3     ; get this ghost's index
128:   int 5
129:   mov e, a  ; e = my.x
130:   mov f, b  ; f = my.y
131: 
132: ; compute direction
133: 
134:   mov a, 1     ; alpha
135:   mov b, 1     ; phi
136:   mov g, c
137:   sub g, e     ; absx = dx  = lman.x - my.x
138:   mov h, f
139:   sub h, d     ; absy = -dy = my.y - lman.y
140: 
141:   jgt l1, c, e     ; if lman.x =< my.x then
142:     add a, 6
143:     mov g, e
144:     sub g, c   ; absx = -dx
145:     xor b, 254 ; phi := -phi
146: l1:
147:   jlt l2, d, f     ; if lman.y >= my.y then
148:     xor a, 2
149:     mov h, d
150:     sub h, f   ; absy = dy
151:     xor b, 254 ; phi := -phi
152: 
153: 
154: l2:
155: ; from now on, c and d are the main and secondary direction
156:   mov c, a
157:   mov d, a
158: 
159:   jlt l3, g, h    ; if absx >= absy then
160:     xor b, 254    ; phi := -phi
161: l3:
162:     sub c, b      ; add phi for main direction
163:     add d, b      ; subtract phi for secondary direction
164: 
165: l4:
166:   div c, 2        ; main direction of lambda-man
167:   div d, 2        ; secondary direction
168:   and c, 3
169:   and d, 3
170: test:
171:   int 3
172:   int 5
173:   mov %principal, c
174:         and %principal, 3
175:   mov %secondary, d
176:         and %secondary, 3
177:   int 3
178:   int 6           ; get ghost current direction
179:   add b, 2        ; reverse the direction
180:   and b, 3        ; reverse the direction, cont.
181:         mov %uturn, b
182: 
183: ;;; check for a wall in the principal direction
184:         int 3
185:         int 5
186:         mov [254], %principal
187:         mov [255], ret1
188:         mov PC, next    ; get coordinates of square in direction c
189: ret1:
190:         int 7           ; get square
191:         jeq secondary, a, 0    ; if wall, go check secondary direction
192: 
193:   jeq secondary, %uturn, %principal ; go to secondary if principal is forbidden
194:   int 3
195:   int 5
196:   mov %current_dir, %principal
197:   mov [253], testing_if_good_path
198:   mov PC, follow
199: testing_if_good_path:
200:         jeq go, a, 0
201: 
202: secondary:
203:         mov a, %secondary
204: ;;; check if secondary direction is valid
205: ;;; check for wall
206:         int 3
207:         int 5                   ; get my coordinates
208:         mov [254], %secondary
209:         mov [255], ret2
210:         mov PC, next
211: ret2:
212:         int 7                   ; get square
213:         jeq random_dir, a, 0    ; secondary direction is a wall
214: ;;; check for u-turn
215:         jeq random_dir, %uturn, %secondary ; secondary is forbidden
216: ;;; check for dead-end
217:         int 3
218:         int 5
219:         mov %current_dir, %secondary
220:         mov [253], ret3
221:         mov PC, follow
222: ret3:
223:         jeq go_secondary, a, 0
224: 
225: random_dir:
226: ;        mov %test_dir, %secondary
227: ;        inc %test_dir           ;first test the opposite of secondary
228:         int 3
229:         mov %test_dir, a
230: random_loop:
231:         inc %test_dir
232:         and %test_dir, 3
233:         jeq random_loop, %test_dir, %principal
234:         jeq random_loop, %test_dir, %secondary
235:         jeq random_loop, %test_dir, %uturn
236:         int 3
237:         int 5
238:         mov [254], %test_dir
239:         mov [255], ret4
240:         mov PC, next
241: ret4:
242:         int 7
243:         jeq random_loop, a, 0
244: 
245: ;;; go in direction %test_dir
246:         mov %secondary, %test_dir
247:         ;; fall through
248: 
249: go_secondary:
250:   mov %principal, %secondary        ; go in secondary direction
251: 
252: go:
253:   mov a, %principal
254:   int 0           ; direction is in a
255:   hlt
256: 
257: 
258: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
259: ; follow a <- X, b <- Y, %current_dir<- DIR, [253] <- RETURN
260: ; return 0 in a if it is a good choice, and something else otherwise
261: follow:
262:    ;; MOV C, %current_dir          ; debug
263:    ;; MOV H, 42                    ; debug
264:    ;; int 8                        ; debug
265:    MOV [254], %current_dir
266:    MOV [255], lfollow1
267:    MOV PC, next
268: lfollow1:
269:   ; we are in the first tile of the path
270:   ;; MOV H, 43
271:   ;; INT 8
272:   MOV %good_dir_num, 0
273:   MOV %current_x, a
274:   MOV %current_y, b
275: 
276: ; check for the presence of lambda-man
277:   int 1
278:         mov %return_eq, return_ok_lambda
279:         mov %return_neq, checklamdone
280:         jmp check_presence
281: checklamdone:
282:         ;;  check for the presence of another (lower-numbered) ghost
283:         int 3
284:         mov %ghost_index, a
285: checkghostloop:
286:         dec %ghost_index
287:         jeq checkghostdone, %ghost_index, 255
288:         mov a, %ghost_index
289:         int 5
290:         mov %return_eq, not_ok_ghost
291:         mov %return_neq, checkghostloop
292:         jmp check_presence
293: checkghostdone:
294:         mov a, %current_x
295:   mov b, %current_y
296:   MOV [254], %current_dir      ; prepare the call to next for current dir
297:   MOV [255], lwalling0         ; prepare the call...
298:   MOV PC, next
299: lwalling0:
300:   ;; MOV H, 44
301:   ;; INT 8
302:   INT 7
303:   JEQ lwalling1, A, 0
304:   MOV %good_dir_val, %current_dir
305:   INC %good_dir_num
306: lwalling1:
307:   INC %current_dir
308:   AND %current_dir, 3
309:   MOV a, %current_x
310:   MOV b, %current_y
311:   ;; mov c, %current_dir           ; debug
312:   ;; mov h, 45                     ; debug
313:   ;; INT 8                         ; debug
314:   MOV [254], %current_dir      ; prepare the call to next for current dir
315:   MOV [255], lwalling2         ; prepare the call...
316:   MOV PC, next
317: lwalling2:
318:   ;; MOV H, 44
319:   ;; INT 8
320:   INT 7
321:   JEQ lwalling3, A, 0
322:   MOV %good_dir_val, %current_dir
323:   INC %good_dir_num
324: lwalling3:
325:   ADD %current_dir, 2
326:   AND %current_dir, 3
327:   MOV a, %current_x
328:   MOV b, %current_y
329:   MOV [254], %current_dir      ; prepare the call to next for current dir
330:   MOV [255], lwalling4         ; prepare the call...
331:   MOV PC, next
332: lwalling4:
333:   ;; MOV H, 44
334:   ;; INT 8
335:   INT 7
336:   JEQ lwalling5, A, 0
337:   MOV %good_dir_val, %current_dir
338:   INC %good_dir_num
339: lwalling5:
340:   JEQ not_ok, %good_dir_num, 0
341:   JEQ continue, %good_dir_num, 1
342: return_ok_lambda:
343: return_ok:
344:   MOV A,0
345:   MOV PC, [253]
346: not_ok_ghost:
347: not_ok:
348:   MOV A,1
349:   MOV PC, [253]
350: continue:
351:   MOV %current_dir, %good_dir_val
352:   MOV A, %current_x
353:   MOV B, %current_y
354:   MOV PC, follow
355: 
356: ;; return_ok_lambda:     ; debug
357: ;;   int 8               ; debug
358: ;;   jmp return_ok       ; debug
359: 
360: ;; not_ok_ghost:                   ; debug
361: ;;         int 8                   ; debug
362: ;;         jmp not_ok              ; debug
363: 
364: 
365: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
366: ;;; check equality of (a,b) with (%current_x,%current_y)
367: ;;; jump to %return_eq if they are equal
368: ;;; jump to %return_neq if they are not equal
369: ;;; preserve the value of all registers and memory
370: check_presence:
371:         jeq same_x, a, %current_x
372:         jmp %return_neq
373: same_x:
374:         jeq same_y, b, %current_y
375:         jmp %return_neq
376: same_y:
377:         jmp %return_eq
378: 
379: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
380: ; next a <- X, b <- Y, [254] <- DIR, [255] <- RETURN
381: ;;  this function has zero bug.
382: next:
383:         MUL [254], 2
384:         ADD [254], 3
385:         MOV H, PC
386:         ADD H, [254]
387:         MOV PC, H
388:         SUB B, 1                ; code for 0
389:         JMP next_end
390:         ADD A, 1                ; code for 1
391:         JMP next_end
392:         ADD B, 1                ; code for 2
393:         JMP next_end
394:         SUB A, 1                ; code for 3
395: next_end:
396:         MOV PC, [255]
397: