: set-op-p \ save operation ['] + opxt ! ; : set-op-m \ save operation ['] - opxt ! ; : exec-op \ executes operation opxt @ execute ; : get-sub-field ( n1 -- n2 ) 10 mod ; : getField ( n1 -- n2 ) 5 + 10 / ; : get-pos MovX @ MovY @ ; : get-pos-field MovX @ getField MovY @ getField ; : print-pos get-pos swap s" ( " type dec. s" , " type dec. s" )" type ; \ START check if direction is possible : can-go ( flag n1 n2 -- flag ) swap 2dup ( flag n2 n1 n2 n1) 2 exec-op getField 1 exec-op ( flag n2 n1 n2 n3 ) \ get 'X' field after move left/right swap ( flag n2 n1 n3 n2 ) getField ( flag n2 n1 n3 n4) \ get 'Y' field 4 pick ( flag n2 n1 n3 n4 flag ) if swap ( flag n2 n1 n4 n3 ) endif World @ ( flag n2 n1 n5 ) W <> \ check if Wall (flag n2 n1 flag1 ) \ allows use to go to the center of a field, even if in the direction the next field is a wall swap get-sub-field 0 <> ( flag n2 flag1 flag2 ) or ( flag n2 flag3 ) \ checks that we don't jump to another field if we are to far of the center swap get-sub-field 3 8 within false = \ negate the flag ( flag flag3 flag4 ) and nip ( flag5 ) ; : can-go-left-right ( -- ) false MovX @ MovY @ can-go ; : can-go-down-up ( -- ) true MovY @ MovX @ can-go ; : can-go-left ( -- flag ) set-op-m can-go-left-right ; : can-go-right ( -- flag ) set-op-p can-go-left-right ; : can-go-up ( -- flag ) set-op-m can-go-down-up ; : can-go-down ( -- flag ) set-op-p can-go-down-up ; : can-go-dir ( n1 -- flag ) case 0 of can-go-left endof 1 of can-go-down endof 2 of can-go-right endof 3 of can-go-up endof false \ default endcase ; \ END check if direction is possible \ START get random direction : random-move ( n1 flag1 -- n2 ) \ generates new direction swap ( flag1 n1 ) begin ( flag1 n1 ) 2 rand dup 0<> if 1 + endif 2 pick ( flag1 n1 n2 flag1 ) if 1 + \ only for up-down endif ( flag1 n1 n3 ) \ calculated new direction nip dup ( flag1 n3 n3 ) can-go-dir ( flag1 n3 flag2 ) \ check if new direction is feasible until nip ; : random-up-down ( n1 -- n2 ) \ takes old direction and calc new direction can-go-up can-go-down or \ check if up or down is possible 2 rand 0= and \ random out if we change direction if true random-move endif ; : random-left-right ( n1 -- n2 ) \ takes old direction and calc new direction can-go-left can-go-right or 2 rand 0= and if false random-move endif ; \ END get random direction \ START Move Element : move ( n1 n2 flag -- n3 n4 ) if getField 10 * ( n1 n4 ) \ center element swap 2 exec-op ( n4 n3 ) \ move element swap endif ; : move-left-right ( -- ) MovX @ MovY @ ( n1 n2 ) can-go-left-right ( n1 n2 flag ) move ( n3 n4 ) MovY ! MovX ! ; : move-down-up ( -- ) MovY @ MovX @ ( n1 n2 ) can-go-down-up ( n1 n2 flag ) move ( n3 n4 ) MovX ! MovY ! ; : do-left ( -- ) set-op-m move-left-right ; : do-right ( -- ) set-op-p move-left-right ; : do-up set-op-m move-down-up ; : do-down set-op-p move-down-up ; : go-dir ( n1 -- ) case 0 of do-left endof 1 of do-down endof 2 of do-right endof 3 of do-up endof endcase ; : pac-move dup case 0 of lookLeft dup go-dir endof 2 of lookRight dup go-dir endof 3 of lookUp dup go-dir endof 1 of lookDown dup go-dir endof \ default for fallthrough of exit endcase ; \ END Move Element