{Object_Title_and_Purpose} {Object_Title_and_Purpose} con { timing } CLK_FREQ = 200_000_000 ' system freq as a constant MS_001 = CLK_FREQ / 1_000 ' ticks in 1ms US_001 = CLK_FREQ / 1_000_000 ' ticks in 1us BR_TERM = 115_200 ' terminal baud rate _clkfreq = CLK_FREQ ' set system clock con { fixed io pins } RX1 = 63 { I } ' programming / debug TX1 = 62 { O } SD_SCK = 61 { O } ' sd card SD_CS = 60 { O } SD_SDO = 59 { O } SD_SDI = 58 { I } SDA1 = 57 { IO } ' i2c (optional) SCL1 = 56 { IO } VAR long symbol OBJ io: "jm_fullduplexserial" var long tmp pub Snake1() io.start(RX1, TX1, %0000, BR_TERM) ' start terminal io ' wait until any key has been pushed. This way you can switch from Propeller Tool ' to PST without a hurry. At least during development all my terminal-based programs ' use this loop. tmp:=-1 repeat while tmp==-1 io.str( string( "Snake",$0d,"== please press key to start ==",$0d ) ) tmp:=io.rxtime( 1000 ) ' clear terminal screen and go home :o) (PST special) io.tx( 0 ) io.tx( 1 ) io.str( string("Welcome to Snake!",$0d) ) io.str( string("Please set the terminal window to full size and after that press a key again!") ) io.rx() printFrame() printAt( 5,5, string("And now, resize the window as you like") ) printAt( 8,6, string("but showing the square and the score!") ) printAt( 7,8, string(".. and press a key to start") ) printScore() printAt( 7,10, string("Use a,s,w,y for left, right, up, down") ) printAt( 7,11, string(" ... enjoy ;o)") ) io.rx() 'start key-COG, which reads the key-code and sets some global variables accordingly cogspin( NEWCOG, readKey(), @stack ) ' endless game-loop. No way out ;o) repeat ' init screen printFrame() ' reset all variables, to start fresh ' head and tail are the pointers in the ring-buffer which contain ' the index of .. hmmm ... head and tail of the snake?! head := 0 ' tail indeed is pointing to the position to be deleted tail := 998 ' set current length of the snake size := 1 ' set snake head to start position. All even indizes store the x-position, ' all odd indizes store the y-position snake[head] := 25 snake[head+1] := 13 ' define the start direction dx := -1 dy := 0 ' here comes the main-game-loop. The gameLoop variable is set to 0 if any ' game-over condition is detected (run into wall or byte into own body) gameLoop := 1 repeat while gameLoop ' get the current head-position headx := snake[head] heady := snake[head+1] ' move the head-pointer to the next index head := head + 2 if head==1000 head:=0 ' remember the tail pointer oldtail := tail ' and move the tail-pointer to the next index tail := tail + 2 if tail==1000 tail:=0 ' if the key-COG has detected a key-press, takeover the delta values for x and y if kflag==1 dx := kdx dy := kdy kflag := 0 ' calculate next head-position headx := headx + dx heady := heady + dy ' and store it in the ring buffer snake[ head ] := headx snake[ head+1 ] := heady ' check if one of the end-conditions is true check() ' print new header and remove old tail printSnake() ' print food. This includes a countdown to move the food after a while printTarget() ' print score. printScore() ' slow down the snake a bit waitms( 125 ) ' game-loop finished kflag:=1 repeat 5 printAt( 5,13, string( "Game over!" ) ) waitms( 250 ) printAt( 5,13, string( " " ) ) waitms( 250 ) printAt( 5,13, string( "Game over!" ) ) io.rx() pub check() | i,pos ' if one of these conditions is true, the snake hit the wall if headx==0 or headx==49 or heady==0 or heady==26 gameLoop:=0 ' snake needs at least a length of 5 to be able to bite itself if size>5 ' start checking with the head pos := head ' fast forward because the first 4 pieces can't bite themselves repeat i from 1 to 5 pos := pos - 2 if pos<0 pos:=998 ' from 5th piece on, check that the head did not bite (same position) repeat i from 5 to size if headx==snake[ pos ] and heady==snake[pos+1] gameLoop:=0 return pos := pos - 2 if pos<0 pos := 998 ' in case the head finds the food, set tail back to the old tail ' which means that the snake is one piece longer if headx==targetx and heady==targety tail := oldtail ' set target values to 0 to trigger finding a random value for the next position tcounter := 0 targetx := 0 targety := 0 size++ score += 100 pub charAt( x,y,c ) ' output a character if it's in screen-range and if it's a printable character if x>0 and x<49 and y>0 and y<26 and c>31 and c<128 posbuf[1]:=x posbuf[2]:=y posbuf[3]:=c io.str(@posbuf) pub printAt( x, y, text) ' set cursor position and print string posbuf[1]:=x posbuf[2]:=y posbuf[3]:=0 io.str(@posbuf) io.str( text ) dat ' a buffer to assemble the bytestream for positioning posbuf byte 2, 0, 0, 0, 0 pub printTarget() ' find a new target if countdown is done if tcounter==0 ' delete old target charAt( targetx, targety, space ) ' create new target-position tcounter := 100 targetx := (getrnd() & $ff // 48) + 1 targety := (getrnd() & $ff // 24) + 1 ' and print new target charAt( targetx, targety, "X" ) tcounter-- pub readKey() | in repeat repeat while kflag == 1 in := io.rx() case in 97: if dx<>1 kdx := -1 kdy := 0 kflag := 1 115: if dx<>-1 kdx := 1 kdy := 0 kflag := 1 121: if dy<>-1 kdx := 0 kdy := 1 kflag := 1 119: if dy<>1 kdx := 0 kdy := -1 kflag := 1 pub printSnake() ' simply print one new head-piece charAt( snake[ head ], snake[ head+1 ], stars ) ' and delete tail-piece charAt( snake[ tail ], snake[ tail+1 ], space ) VAR long oldLeft, oldRight, left, right, score, tcounter word head,tail,oldtail,size, gameLoop byte snake[1000] byte headx, heady byte targetx, targety byte dx, dy, kdx, kdy, kflag long stack[200] pub printScore() printAt( 55,1, string( "Score: " ) ) dec( score ) pub printFrame() io.tx( 0 ) io.tx( 1 ) io.str( @stars ) score:=0 repeat 25 io.tx( $0d ) io.tx( "*" ) io.str( 2+@space ) io.tx( "*" ) io.tx( $0d ) io.str( @stars ) PUB dec( val ) | i i:=10 if val>0 repeat while val<>0 i-- num[i]:="0"+val//10 val:=val/10 else io.tx( "0" ) io.str( (10-i)+@zero ) io.str( @num+i ) dat num byte 0[11] zero byte "000000",0 DAT stars byte "**************************************************",0 space byte " ",0