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: