

 This page uses content from Wikipedia. The original article was at Snake_(video_game). The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)


Snake is a game where the player maneuvers a line which grows in length every time the snake reaches a food source.



Task
Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake.

Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane.

The game ends when the snake attempts to eat himself.




 
/* Snake */
/* Implementing this task in Hopper-FLOW-MATIC++ */
/* The snake must catch a bite before time runs out, which decreases by
   10 points every 800 milliseconds. 
   The remaining time will be added to your total score. */
 
#include <flow.h>
#include <flow-term.h>
#include <keys.h>
 
#enum  1,N,E,S,W
#enum  1,SPACE,FOOD,BORDER
 
DEF-MAIN(argv, argc)
   BREAK-ON
   STACK 16
   CLR-SCR
   MSET(C, quit, nHead, dir, Size, SCORE, counter, T,TPlay,ConsPrey )
   SET( symbol, " $@" )
 
   SET( w, 50 ) //50
   SET( h, 28 ) // 24
   SET( TIME, 100 )
   LET( Size :=  MUL(w,h) )
   SET( TLimit := 100 )
   VOID( big number, numL1, numL2, numL3 )
   GOSUB( set score )
 
   DIM( Size ) AS-ONES( board )
   HIDE-CURSOR
 
   GOSUB( put titles )
   GOSUB( start )
   GOSUB( show )
   GOSUB( ready ), SLEEP(3)
   TIC( T ), TIC( TPlay )
   WHILE( NOT (quit) ) 
      DEVIATE-IF( TLimit ~= TPlay ){
         GOSUB( show )
         WHEN( KEY-PRESSED? ){ 
            SCAN-CODE( C )
            SWITCH( C ) 
               CASE( K_UP )   { dir = N, EXIT }
               CASE( K_RIGHT ){ dir = E, EXIT }
               CASE( K_DOWN ) { dir = S, EXIT }
               CASE( K_LEFT ) { dir = W, EXIT }
               CASE( K_ESC )  { quit = 1, EXIT }
               CASE( 32 )  { PAUSE, EXIT }
            SWEND
         }
         GOSUB( step )
      }
      DEVIATE-IF( 800 ~= T ) {
         TIME-=10, CLAMP(0,100,TIME)
         {TIME, 12, 52} GOSUB( put time )
      }
   WEND
   GOSUB(you lost),   SLEEP(1)
   GOSUB(game over ), SLEEP(2)
   LOCATE(ADD(h,1),1) PRNL
   SHOW-CURSOR
   PRNL
END
 
RUTINES
 
// initialize the board, plant a very first food item
DEF-FUN( start )
   SET( i,1 )
 
   [1:w]                               {BORDER} CPUT(board)  // top
   [ SUB(MUL(h,w),MINUS-ONE(w)) : end] {BORDER} CPUT(board) // bottom
   [1:w:end]                           {BORDER} CPUT(board)  // left
 
   SET(i, 1)
   FOR( LE?(i, h), ++i )
      [ MUL(i, w )]                    {BORDER} PUT(board)  // right
   NEXT
   LET( nHead := MUL( w, SUB( SUB( h, 1 ), MOD(h,2) )) DIV-INTO(2) )
   [ nHead ] {-5} CPUT( board )
   LET( dir := N )
   SRAND( ~SECONDS)
   GOSUB( plant )
RET
 
DEF-FUN( you lost ) 
   SET(i,1), SET(k,0), SET(n,1)
   LOCATE(1,1)
   FOR( LE?(i, h), ++i)
      SET(j,1)
      FOR( LE?(j, w), ++j)
         LET( k := [ n ] GET(board) )
         COND( IS-NEG?( k ))
             LOCATE(i,j)
             PRNL("\033[38;15;3m\033[48;5;9m~\OFF")
         CEND
         ++n
      NEXT
   NEXT
RET
 
DEF-FUN( show ) 
   SET(i,1)
   MSET(j, k)
 
   SET(n,1)
   LOCATE(1,1)
   FOR( LE?(i, h), ++i)
      SET(j,1),
      FOR( LE?(j, w), ++j)
         LET( k := [ n ] GET(board) )
         COND( IS-NEG?( k ))
            PRN("\033[38;5;3m\033[48;5;15m~\OFF")
         ELS-COND( {k} IS-EQ?(BORDER))
               {"\033[38;5;4m\033[48;5;2m"}
               PRN( [k] GET(symbol),"\OFF")
         ELS-COND( {k}IS-EQ?(FOOD) )
               {"\033[38;5;15m\033[48;5;9m"}
               PRN( [k] GET(symbol),"\OFF")
         ELS
               {"\033[48;5;28m"}
               PRN( [k] GET(symbol),"\OFF")
         CEND
         ++n
      NEXT
      PRNL
   NEXT
RET
 
// negative values denote the snake (a negated time-to-live in given cell)
 
// reduce a time-to-live, effectively erasing the tail
DEF-FUN( age )
 
   MSET( r, jAge, jR )
   CART( IS-NEG?( board ) ) »» (r), SET-RANGE(r)
 
   GET( board ) PLUS(1) »» (jAge)
  // this is necessary, because Hopper arrays begining in 1
   CART( IS-ZERO?(jAge) ) »» (jR)
   COND( IS-ARRAY?(jR) )
      SET-RANGE(jR), SET(jAge, 1), SET-RANGE(r) 
   CEND
  // ******
   {jAge} PUT(board), CLR-RANGE
RET
 
DEF-FUN( step )
   SET(len,0)
   LET( len := [nHead] GET(board) )
   SWITCH(dir)
      CASE (N){ nHead -= w, EXIT }
      CASE (S){ nHead += w, EXIT }
      CASE (W){ --nHead, EXIT }
      CASE (E){ ++nHead, EXIT }
   SWEND
   SWITCH( [nHead]CGET(board))
      CASE (SPACE){
          --len, LET( len := IF( IS-ZERO?(len), 1, len) )
          [nHead] { len }, CPUT(board) // keep in mind len is negative
          GOSUB( age )
          EXIT
      }
      CASE (FOOD){
          --len, LET( len := IF( IS-ZERO?(len), 1, len) )
          [nHead] { len }, CPUT(board)
          GOSUB( plant )
          ADD(SCORE,TIME), MOVE-TO(SCORE)
 
          {SCORE, 4, 52} GOSUB( put score )
          LET( TIME := 100 )
          ++counter, COND( GT?( counter, 5 ) )
                        LET( TLimit := SUB( TLimit,5 ))
                        CLAMP(30,100,TLimit)
                        LET( counter := 0 )
                     CEND
          ++ConsPrey
          COLOR-FG(10)
          LOCATE(20,52) PRNL("SPEED: ")
          LOC-ROW(21),  SET-ROUND(2)
                        PRNL( MUL(INV(TLimit),100), " M/S" )
                        SET-ROUND(-1)
          LOC-ROW(23)   PRNL("CONSUMED PREY:")
          LOC-ROW(24)   PRNL(ConsPrey,"\OFF")
 
          TIC( T ),{TIME, 12, 52} GOSUB( put time )
          EXIT
      }
      LET( quit := 1 )
 
   SWEND
RET
 
// put a piece of food at random empty position
DEF-FUN( plant )
   SET(r, 0)
   LOOP( search position )
      LET( r := MOD( CEIL(RAND(MINUS-ONE(Size))), Size ) )
   BACK-IF-NOT-EQ( [r] GET(board), SPACE, search position)
   [r] {FOOD} CPUT( board )
RET
 
DEF-FUN( put titles )
   LOCATE(2,52)   PRNL("\033[38;5;15mSCORE\OFF")
   {SCORE, 4, 52} GOSUB( put score )
   LOCATE(10,52)  PRNL("\033[38;5;11mTIME\OFF")
   {TIME, 12, 52} GOSUB( put time )
 
   COLOR-FG(15)
   LOCATE(26,52) SET-ITALIC, PRNL("  S P E E D")
   LOC-ROW(27)               PRNL("S N A K E!\OFF")
RET
 
DEF-FUN( put time, B, posx, posy )
   MSET( i,j,x )
   MSET( sb, lsb,nB, p4 )
   SET( k,1 )
 
   LOCATE (posx, posy) FILL-BOX(" ",5,20)
   LET( sb := STR(B) )
   LET( lsb := LEN(sb) )
   SET( rx, posy )
   LET( p4 := ADD( posx, 4 ))
 
   {"\033[38;5;11m\ENF"}
   PERF-UP(k, lsb, 1) 
      LET( nB := VAL( MID( 1, k, sb )) ) 
      SET(x, 1), SET( i, posx )
      FOR( LE?(i, p4), ++i )
         SET( j, rx )
         FOR( LE?(j, ADD( rx, 2 ) ), ++j )
            LOCATE(i, j) PRNL( STR-TO-UTF8(CHAR( [ PLUS-ONE(nB), x] CGET(big number) MUL-BY(219) )))
            ++x
         NEXT
       NEXT
       rx += 4
   NEXT
   PRNL("\OFF")
RET
 
DEF-FUN( put score, SCORE, posx, posy )
    MSET( ln,s, sp )
 
    LET( sp := STR( SCORE ))
    LET( ln := LEN(sp))
 
    LOCATE ( posx, posy ) FILL-BOX(" ",4,20)
    SET(i, 1)
    {"\033[38;5;15m"}
    PERF-UP( i, ln, 1)
       LET( s := VAL( MID( 1, i, sp )) )
       [ PLUS-ONE(s) ]   // set interval to read element of arrays
       LOCATE( posx, posy )  
       PRNL ( STR-TO-UTF8( GET(numL1) ))
       LOCATE( PLUS-ONE(posx),posy )
       PRNL ( STR-TO-UTF8( GET(numL2) ))
       LOCATE( PLUS-TWO(posx),posy )
       PRNL ( STR-TO-UTF8( GET(numL3) ))
       posy += 2
    NEXT
    PRNL("\OFF")
RET
 
DEF-FUN( set score )
 
   {"┌┐"," ┐","┌┐","┌┐","┐┐","┌┐","┌┐","┌┐","┌┐","┌┐"} APND-LST(numL1)
   {"││"," │","┌┘"," ┤","└┤","└┐","├┐"," │","├┤","└┤"} APND-LST(numL2)
   {"└┘"," ┴","└┘","└┘"," ┘","└┘","└┘"," ┴","└┘","└┘"} APND-LST(numL3)
 
   {1,1,1,1,0,1,1,0,1,1,0,1,1,1,1} APND-ROW( big number )
   {1,1,0,0,1,0,0,1,0,0,1,0,1,1,1} APND-ROW( big number )
   {1,1,1,0,0,1,1,1,1,1,0,0,1,1,1} APND-ROW( big number )
   {1,1,1,0,0,1,0,1,1,0,0,1,1,1,1} APND-ROW( big number )
   {1,0,1,1,0,1,1,1,1,0,0,1,0,0,1} APND-ROW( big number )
   {1,1,1,1,0,0,1,1,1,0,0,1,1,1,1} APND-ROW( big number )
   {1,0,0,1,0,0,1,1,1,1,0,1,1,1,1} APND-ROW( big number )
   {1,1,1,0,0,1,0,0,1,0,0,1,0,0,1} APND-ROW( big number )
   {1,1,1,1,0,1,1,1,1,1,0,1,1,1,1} APND-ROW( big number )
   {1,1,1,1,0,1,1,1,1,0,0,1,0,0,1} APND-ROW( big number )
 
RET
 
DEF-FUN( ready )
   {"\033[38;5;4m\033[48;5;11m"}
   LOC-COL(16)
   LOC-ROW(13); PRNL( STR-TO-UTF8("  ▄   ▄▄  ▄  ▄▄  ▄ ▄ "))
   LOC-ROW(14); PRNL( STR-TO-UTF8(" █▄▀ █▀  █▄█ █ █ ▀▄▀ "))
   LOC-ROW(15); PRNL( STR-TO-UTF8(" ▀ ▀  ▀▀ ▀ ▀ ▀▄▀  ▀  "))
   PRNL("\OFF")
RET
 
DEF-FUN( game over )
    {"\033[38;5;15m\033[48;5;9m"}
    LOC-COL(17)
    LOC-ROW(12); PRNL( STR-TO-UTF8("  ▄▄  ▄   ▄ ▄   ▄▄ "))
    LOC-ROW(13); PRNL( STR-TO-UTF8(" █ ▄ █▄█ █ █ █ █▀  "))
    LOC-ROW(14); PRNL( STR-TO-UTF8("  ▀▀ ▀ ▀ ▀ ▀ ▀  ▀▀ "))
    LOC-ROW(15); PRNL( STR-TO-UTF8("   ▄  ▄ ▄  ▄▄  ▄   "))
    LOC-ROW(16); PRNL( STR-TO-UTF8("  █ █ █ █ █▀  █▄▀  "))
    LOC-ROW(17); PRNL( STR-TO-UTF8("   ▀   ▀   ▀▀ ▀ ▀  "))
    PRNL("\OFF")
RET
 