-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ X`09movl`09r3, outbuf_qio+qio$_p2`09`09; store length of buffer X`09$qiow_g`09outbuf_qio X`09blbc`09r0, 100$ X`09rsb X100$: X`09bsbw`09error X`09rsb X X X`09.entry`09- Xsnake_screen, `5Em X;+ X;`09CALL SNAKE_SCREEN( array, length ) X;`09BYTE ARRAY( LENGTH ) X;`09copies string to update screen into shared memory X;- X`09movl`09@8(ap), r0`09`09; get length X`09movl`09r0, screen_len`09`09; store length X`09movc3`09r0, @4(ap), screen_buf`09; copy text X`09ret X X`09.entry`09- Xsnake_write, `5Em<> X;+ X;`09CALL SNAKE_WRITE( array, length ) X;`09BYTE ARRAY( LENGTH ) X;`09writes buffer to terminal in noformat mode X;- X`09movl`094(ap), output_qio+qio$_p1`09; store address of buffer X`09movl`09@8(ap), output_qio+qio$_p2`09; store length of buffer X`09$qiow_g`09output_qio X`09blbc`09r0, 100$ X`09ret X100$: X`09bsbw`09error X`09ret X X`09.entry`09- Xsnake_dead, `5Em<> X;+ X;`09CALL SNAKE_DEAD( player # ) X;- X`09subl3`09#1, @4(ap), r0`09`09`09; get # of snake who died X`09bbss`09r0, you_just_died, 100$`09`09; set flag saying he died X100$:`09ret X X X`09.entry - XCANCELTYPEAHEAD, `5Em<> X`09clrl`09r0 X`09tstw`09ttchan`09`09; check channel is open X`09beql`09100$ X`09$qiow_s`09func=#io$_readvblk!io$m_purge!io$m_timed,- X`09`09chan=ttchan, p1=ttbuf`09; do read with 0 length buffer (p2) X100$:`09ret`09`09`09; return with status in r0 X XERROR: X`09blbs`09r0, 100$ X`09pushl`09r0 X`09calls`09#1, G`5Elib$signal X100$: X`09rsb X X`09.entry`09- Xcontrol_c, `5Em<> X`09movb`09#1, control_c_flag X`09ret X X X`09.page X`09.entry`09- XSNAKE_INIT, `5Em`09`09`09`09; snake game X;+ X;`09I = SNAKE_INIT( player # , game ) X;`09returns I = 1 if you are master snake. X;`09returns your player # as a integer X;`09returns game = 1 if there is a game in progress X;- X X`09calls`09#0, G`5Ettinit`09`09`09; open terminal X; X`09$ascefc_s efn=#64, name=snake_desc_2`09; associate event flag cluster X`09bsbw`09error X; X;`09$open`09fab=snake_fab`09`09`09; open section file X;`09bsbw`09error X X`09$deltva_s inadr=map_range`09`09; delete memory were global X`09bsbw`09error`09`09`09`09; memory will be mapped X X`09$crmpsc_s inadr=map_range, flags=#sec$m_gbl!sec$m_wrt!sec$m_pagfil, - X`09`09gsdnam=snake_map_name, -`09; chan=snake_fab+fab$l_stv,- X`09`09pagcnt=#4 X`09bsbw`09error X X`09cmpl`09r0, #ss$_created`09`09; are we first to map section X`09bneq`0950$`09`09`09`09; no X`09movab`09share_data+4, r3 X`09movc5`09#0, (r3), #0, #512-4, (r3)`09; clear everything except count X`09$clref_s efn=#flag$v_game+64`09`09; say not game X`09movl`09#39814571, seed`09`09`09; init random n.g. seed X`09movl`09#snake, r0`09`09`09; 8 snakes X20$: X`09movl`09r0, start_position-4`5Br0`5D`09; init start position X`09sobgtr`09r0, 20$ X50$: X`09blbc`09abort, 60$`09`09`09; if not abort --> 60$ X`09callg`09text_abort, snake_write X`09$exit_s #1 X60$: X`09bsbw`09queue_mbxread`09`09`09; start terminal read X; X`09bbss`09#0, master_flag, 100$`09`09; see if a master snake exists X`09`09`09; this should be interlocked on a multi-processor X;+ X; We will have to be the master snake X;- X`09movb`09#1, master`09`09`09; indicate we are master snake X`09$setef_s efn=#7`09`09`09`09; set for first call X100$: X; X`09clrl`09r1`09`09`09`09; start at player 0 (bit0=1) X150$: X`09bbcs`09r1, players, 200$`09`09; see if this snake is free X`09incl`09r1`09`09`09`09; go to next snake X`09cmpl`09r1, #snake`09`09`09; have we checked all snakes? X`09blss`09150$`09`09`09`09; no --> 150$ X`09mnegl`09#1, r1`09`09`09`09; player = -1 means none X200$: X`09movl`09r1, player`09`09`09; store my snake number (0-7) X`09movl`09player, @4(ap)`09`09`09; and return it X500$: X`09movzbl`09game_going, @8(ap)`09`09; return game going flag X X`09movl`09r1, r3 X`09$getjpi_s itmlst=username_jpi`09`09; get our username X`09mull2`09#name_size, r3`09`09`09; get offset to start of name X`09blss`09600$`09`09`09`09; no snakes available X`09movc5`09username_siz, username_buf, #`5Ea/ /, #name_size, name(r3) X`09`09`09`09`09`09; copy username X600$: X`09$dclexh_s desblk=exit_block`09`09; declare exit handler X`09bsbw`09error X X`09movzbl`09master, r0`09`09`09; return master snake status X`09ret X Xmaster_wait: X;+ X; master snake has to wait some time for other snakes to start playing X; called from SNAKE_START X;- X`09incl`09game_count`09`09`09; say another game being played X220$:`09clrb`09player_bits`09`09`09; no other players X`09bbss`09player, player_bits, 400$`09; say I am playing X400$: X`09$clref_s efn=#flag$v_synch+64 X;+ X;`09randomise starting positions X;- X`09moval`09start_position, r4`09`09; starting position numbers X`09movl`09#1, r2`09`09`09`09; snake index (start at 1) X500$: X`09pushal`09seed`09`09`09`09; random number seed X`09calls`09#1, G`5Emth$random`09`09; random real in r0 X`09addl3`09#1, r2, r3`09`09`09; snake + 1 X`09cvtlf`09r3, r3`09`09`09`09; as real X`09mulf2`09r3, r0`09`09`09`09; get snake to change pos with X`09cvtfl`09r0, r0 X`09movl`09(r4)`5Br0`5D, r1`09`09`09; swap these positions X`09movl`09(r4)`5Br2`5D, (r4)`5Br0`5D X`09movl`09r1, (r4)`5Br2`5D X`09aobleq`09#7, r2, 500$ X; X;`09moval`09start_position, r4 X`09movab`09move, r3 X`09movl`09#snake, r2`09`09`09; number of snakes X600$: X`09movl`09(r4)+, r0`09`09`09; get start position (1-8) X`09movb`09start_direction-1`5Br0`5D, (r3)+`09; copy start direction X`09sobgtr`09r2, 600$ X; X`09$setimr_s efn=#flag$v_game+64,-`20 X`09`09`09daytim=second_1`09`09; wait a time for other snakes X`09$waitfr_s efn=#flag$v_game+64`09`09; say that a game is going X`09movb`09#1, game_going`09`09`09; say game going X`09$clref_s efn=#flag$v_endofgame+64`09; say not end of game X`09$setef_s efn=#7`09`09`09`09; sets event flag for first X`09`09`09`09`09`09; call to snake_wait X`09$setimr_s efn=#flag$v_synch+64,-`09`09 X`09`09`09 daytim=start_wait X`09$waitfr_s efn=#flag$v_synch+64 X`09; this allows other snakes to set bit saying they are playing X X`09rsb X X`09.entry`09- XSNAKE_START, `5Em X;+ X;`09CALL SNAKE_START( PLAYERS , START_POSITION ) X;`09INTEGER PLAYERS, START_POSITION(8) X;`09waits 5? seconds for other players to run game X;`09The master snake is assumed to have waited some additional time X;`09Returns PLAYERS, bit I <> 0 if that player is active X;`09START_POSITION(I) is the starting location of snake I, (1-8) X;- X`09blbc`09master, 500$`09`09`09; are we master snake ? X`09bsbw`09master_wait X`09brb`09800$ X200$: X`09$exit_s #1`09`09`09`09; game aborted so stop X500$: X`09$waitfr_s efn=#flag$v_game+64`09`09; wait until a game starts X`09blbs`09abort, 200$`09`09`09; if game stopped --> 200$ X`09bbss`09player, player_bits, 600$`09; say I am playing X600$:`09$waitfr_s efn=#flag$v_synch+64`09`09; synchronise X`09blbs`09abort, 200$`09`09`09; if game stopped --> 200$ X800$: X`09movzbl`09player_bits, r4`09`09`09; get player bits X`09ashl`09#flag$v_done, r4, other_players ; used by master snake X`09movl`09r4, @4(ap)`09`09`09; store player bits X`09clrl`09chars_left`09`09`09; cancel type ahead X`09clrb`09data_ready`09`09`09; make us do a read X`09$qiow_g read_qio`09`09`09; clear out type-ahead X;`09return starting positions X`09moval`09start_position, r0`09`09; address of new positions X`09movl`098(ap), r2`09`09`09; address of where to put them X`09movl`09#snake, r1`09`09`09; number of snakes X900$: X`09movl`09(r0)+, (r2)+ X`09sobgtr`09r1, 900$ X X`09mnegl`09#1, last_move_count`09`09; invalidate last counter X X`09ret X X XSNAKE_WAIT:: X;+ X;`09BSBW SNAKE_WAIT X; `09wait until we are told to read players command(s) X;- X`09blbs`09master, 200$`09`09`09; are we master snake ? X`09$waitfr_s efn=#flag$v_read+64`09`09; if not then wait for flag X`09rsb X200$:`09; master snake waits and then sets flag for all players X`09$cantim_s reqidt=#check_timer`09`09; cancel checking timer X`09$waitfr_s efn=#7`09`09`09; wait for previous timer X`09$setimr_s efn=#8, daytim=check_wait, - X`09`09astadr=check_ast, reqidt=#check_timer ; set off checking timer X`09$setimr_s efn=#7, daytim=update_wait X`09$clref_s efn=#flag$v_update+64`09`09; clear next flag to wait on X`09movl`09#flag$v_done+64, r2`09`09; clear each players done flag X`09$clref_s efn=r2`09`09`09`09; player 0 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2 X`09incl`09r2 X`09$clref_s efn=r2`09`09`09`09; player 7 X; X`09$clref_s efn=#flag$v_synch+64 X`09$setef_s efn=#flag$v_read+64`09`09; tell everybody to do read X`09rsb X X XSNAKE_READ:: X;+ X;`09BSBW SNAKE_READ X;`09read all users moves and store them into the byte array MOVES(*) X;- X`09bsbw`09ttread`09`09`09`09; read users commands, if any X`09tstb`09r0`09`09`09`09; anything read ? X`09blss`09800$`09`09`09`09; no X500$: X`09movl`09player, r1`09`09`09; get our player number X`09movb`09r0, move(r1)`09`09`09; store our move X`09bneq`09800$`09`09`09`09; if not quit --> 800$ X`09clrl`09score`5Br1`5D`09`09`09; clear score X`09clrl`09n_games`5Br1`5D X`09clrl`09wins`5Br1`5D X`09$exit_s #1`09`09`09`09; and exit program X800$: X`09addl3`09#flag$v_done+64, player, r1 X`09$setef_s efn=r1`09`09`09`09; say that read is complete X900$: X`09blbc`09master, 1000$ X`09$wfland_s efn=#64, mask=other_players`09; wait for all players to read X`09incl`09move_count`09`09`09; onto next move X`09$clref_s efn=#flag$v_read+64`09`09; clear next flag to wait on X`09$setef_s efn=#flag$v_update+64`09`09; tell everybody to update X`09brb`091050$ X1000$: X`09$waitfr_s efn=#flag$v_update+64`09`09; wait for all reads to complete X`09blbs`09master_flag, 1050$`09`09; check for master snake OK X`09movl`09player, r1`09`09`09; get our player number X`09clrb`09move(r1)`09`09`09; store our move ( quit ) X1050$: X`09rsb X X X`09.entry`09- XSNAKE_PLAY, `5Em X;+ X;`09called once at the start of the game. X;`09I then call the Pascal routine ADD_HEAD to perform the moves. X;- X`09blbs`09master, 1000$`09`09; master snake does all the work X100$: X`09bsbw`09snake_wait X`09bsbw`09snake_read X`09$waitfr_s efn=#flag$v_synch+64`09; wait until screen update there X`09bsbw`09snake_update`09`09; update screen X`09brb`09100$ X X900$: X`09clrb`09game_going`09`09; tell other snakes games finished X`09$setef_s efn=#flag$v_synch+64`09; wake other snakes up X`09bsbb`09snake_update`09`09; write out last move X`09ret X X1000$:`09; master snake moves every snake X`09bsbw`09snake_wait X`09bsbw`09snake_read X`09callg`09add_head_par, G`5Eadd_head`09; call Pascal routine X`09`09`09`09`09`09; returns 1 if game still going X`09blbc`09r0, 900$`09`09; game has ended --> 900$ X`09$setef_s efn=#flag$v_synch+64`09; wake other snakes up X`09bsbb`09snake_update`09`09; update our screen X`09brb`091000$ X X X`09.enable local_block X500$: X`09$exit_s #1`09`09`09; game aborted, so exit image X Xsnake_update:: X`09blbs`09abort, 500$ X`09blbs`09dead, 80$`09`09; if we are dead, then no head X;`09replace your snake head with a diamond symbol X`09movc3`09screen_len, screen_buf, outbuf`09; copy update string X`09movl`09player, r2`09`09; get my snake number X`09addw2`09#`5EA/1/+`5EX80, r2`09`09; get number with parity bit set X`09locc`09r2, screen_len, outbuf X`09beql`0950$`09`09`09; could not find it !!! X`09movb`09#`5EA/`60/, (r1)`09`09; change to diamond X50$: X`09callg`09update_par, snake_write X`09blbc`09game_going, 100$`09; bit clear if game has finished X`09bbsc`09player, you_just_died, 60$ ; see if we just died X`09rsb X60$:`09movb`09#1, dead`09`09; say we are dead X`09callg`09text_wait, snake_write`09; tell them to wait for next game_exit, X`09rsb X80$:`09; dont copy buffer if no head to update because we are dead X`09callg`09update_par2, snake_write X`09blbc`09game_going, 100$ X`09rsb X100$: X`09$setimr_s efn=#6, daytim=second_1`09; so we can see last move X`09$waitfr_s efn=#6 X`09ret`09`09`09`09; return from SNAKE_PLAY if end game X`09.disable local_block X X X`09.entry`09- XCHECK_AST, `5Em X;+ X;`09called when check_timer expires (2 seconds) X;`09we should only get here if one of the other snakes has aborted X;`09or `5ES ed . Force the snake out of the game. X;- X`09$readef_s efn=#64, state=cluster_2`09; get done flags X`09extzv`09#flag$v_done, #snake, cluster_2, r2 ; get done flags X;`09movb`09other_players+1, r3`09`09; get other players X`09bicw3`09r2, other_players+1, r3`09`09; find players who have not X`09`09`09`09`09`09; responded X`09bicw2`09r3, other_players+1`09`09; and say they are dead X`09clrl`09r2`09`09`09`09; snake 0 X100$:`09bbc`09r2, r3, 200$ X`09clrb`09move(r2)`09`09`09; say snake has quitted X`09addl3`09#flag$v_done+64, r2, r0`09`09; get event flag X`09$setef_s efn=r0`09`09`09`09; set event flag so I will X`09`09`09`09`09`09; wake up on return from here X200$:`09aoblss`09#snake, r2, 100$`09`09; for all 8 snakes X X`09ret X X X`09.entry`09- XSNAKE_GAME_END, `5Em<> X;+ X;`09synchronizes the end of the game X;- X`09clrb`09dead`09`09`09; we are not dead X`09blbc`09master, 500$`09`09; if not master snake --> 500$ X`09$clref_s efn=#flag$v_game+64`09; say game not in progress X`09clrb`09game_going`09`09; and again X`09$setimr_s efn=#flag$v_endofgame+64, daytim=second_2 X`09clrw`09you_just_died`09`09; reset died flags X500$: X`09$waitfr_s efn=#flag$v_endofgame+64 ; wait for end of game X`09blbs`09abort, 800$`09`09; if we should abort --> 800$ X`09ret X800$:`09; we must abort. Probably because master snake stopped X`09$exit_s #1 X X X`09.entry`09- XSNAKE_EXIT, `5Em X;+ X;`09called as an exit handler X;- X`09$cancel_s chan=mbxchan`09`09; cancel mailbox read X X`09movl`09player, r3`09`09; get my snake number X`09blss`0980$`09`09`09; we never were playing X`09clrb`09move(r3)`09`09; make next move a quit X`09addl3`09#flag$v_done, r3, r2`09; get done bit X`09bbcc`09r2, other_players, 50$`09; stop master snake from waiting for me X50$:`09addl2`09#64, r2`09`09`09; make into event flag X`09$setef_s efn=r2`09`09`09; say input done X`09bbcc`09r3, players, 60$`09; say this snake available X60$: X`09clrl`09score`5Br3`5D`09`09; zero score X`09clrl`09n_games`5Br3`5D`09`09; zero # of games played X80$: X`09blbc`09master, 100$`09`09; are we master snake ? X`09movb`09#1, abort`09`09; tell all other snakes to abort +-+-+-+-+-+-+-+- END OF PART 2 +-+-+-+-+-+-+-+-