Snake: Difference between revisions

34,762 bytes added ,  3 months ago
m
(J)
 
(42 intermediate revisions by 12 users not shown)
Line 15:
 
=={{header|Ada}}==
<syntaxhighlight lang="ada">
<lang Ada>
-- This code is a basic implementation of snake in Ada using the command prompt
-- feel free to improve it!
Line 304:
Snake.run;
end;
</syntaxhighlight>
</lang>
 
{{out}}
Line 325:
=={{header|Amazing Hopper}}==
{{trans|C}}
<syntaxhighlight lang="amazing hopper">
<lang Amazing Hopper>
/* Snake */
/* Implementing this task in Hopper-FLOW-MATIC++ */
Line 335:
#include <flow-term.h>
#include <keys.h>
 
#define LIMIT_TIME 120
#define INF_TIME 80 //70
#define ONE_SECOND 1000
#define TOTAL_TIME 100
#define DECREMENT_TIME 10
#define COLOR_FOOD 232
#define BACK_FOOD 255
#define TIME_LEVEL 90000 //90000 // un minuto y medio
#define TIME_CHALLENGE 40000 // 40 segundos
#define TIME_LOST 30000
#define COLUMNA_PRINT 55
#define SIZE_INITIAL -7
 
#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, " $@" )
 
MSET(C, quit, nHead, dir, Size, SCORE, counter, T, TPlay,TSound, ConsPrey,Consumed stage )
SET( w, 50 ) //50
 
SET( h, 28 ) // 24
SET(len,0)
SET( w, 50)
SET( h, 28)
SET( color food, COLOR_FOOD )
SET( back food, BACK_FOOD )
SET( TIME, 100 )
LET( Size := MUL(w,h) )
SET( TLimit := 100LEVEL,1 )
SET( REAL LEVEL,1 )
FALSE(swPierde)
TRUE(swExtra1,swExtra2)
TRUE( tiles )
SET( back tiles,1 ), MSET(tile1, tile2)
VOID( head back tiles )
MEM("\033[48;5;28m","\033[48;5;29m","\033[48;5;62m","\033[48;5;63m","\033[48;5;70m","\033[48;5;71m","\033[48;5;4m","\033[48;5;27m" )
MEM("\033[48;5;99m","\033[48;5;97m","\033[48;5;17m","\033[48;5;18m","\033[48;5;62m","\033[48;5;63m")
APND-LST(head back tiles)
[back tiles] GET(head back tiles), MOVE-TO(tile1)
[PLUS-ONE(back tiles)] GET(head back tiles), MOVE-TO(tile2)
VOID( big number, numL1, numL2, numL3 )
 
VOID( sounds ), SET( sound index, 1 )
MEM("Snake_music.wav","Snake_music_l3.wav","Snake_music_l5.wav","Snake_music_l4.wav","Snake_music_l6.wav")
APND-LST(sounds)
GOSUB( set score )
 
MSET(tBoard1,tmpLimit,Maze,wM,hM,SizeM)
DIM( Size ) AS-ONES( board )
DIM( Size ) AS-ONES( board ), {board} MOVE-TO(tBoard1)
 
// load and prepare maze for challenge stage:
SET(i,1)
LET( Maze := REPLICATE("3",50) )
PERF-UP(i,26,1)
LET( Maze := CAT( Maze, CAT( CAT("3", REPLICATE("1",48) ), "3") ) )
NEXT
LET( Maze := CAT( Maze, REPLICATE("3",50) ))
GOSUB( prepare maze )
HIDE-CURSOR
CLR-SCR
 
GOSUBSET( putTLimit titles:= LIMIT_TIME )
MEM(SIZE_INITIAL),GOSUB( start )
GOSUBSET( showtime out, TIME_LEVEL)
 
GOSUB( ready ), SLEEP(3)
SYS( CAT(CAT("aplay fl/",[sound index]CGET(sounds)), "</dev/null >/dev/null 2>&1 &"))
TIC( T ), TIC( TPlay )
WHILEGOSUB( NOTtitles (quit) )
DEVIATE-IF( TLimit ~= TPlay ){
/* PLAY GAME!! */
GOSUB( show )
SET(lives,3)
WHEN( KEY-PRESSED? ){
SCAN-CODEWHILE( Clives )
SWITCHGOSUB( Cshow )
GOSUB( put titles )
CASE( K_UP ) { dir = N, EXIT }
CASEGOSUB( K_RIGHTready ){ dir = E, EXIT }SLEEP(1.5)
TIC( T ), CASETIC( K_DOWNTPlay ) { dir = S, EXIT }TIC(TSound)
KBD-FREE
CASE( K_LEFT ) { dir = W, EXIT }
WHILE( NOT CASE( K_ESCquit) ) { quit = 1, EXIT }
ON-TIME( TLimit ~= CASE( 32TPlay ) { PAUSE, EXIT }
SWENDGOSUB( show )
WHEN( KEY-PRESSED? ){
SCAN-CODE( C )
SELECT( 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 }
SELEND
}
GOSUB( step )
}
GOSUBON-TIME( stepONE_SECOND ~= T ) {
TIME-=DECREMENT_TIME, CLAMP(0,TOTAL_TIME,TIME)
}
{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
DEVIATE-IF( 800 ~= T ) {
TIME-=10, CLAMP(0,100,TIME)}
{ON-TIME,( 12,time 52}out GOSUB(~= put timeTSound ){
} GOSUB(LEVELCLEAR)
}
WEND
COND( OR(EQ?(LEVEL,3),EQ?(LEVEL,6)) )
GOSUB(you lost),SLEEP(3)
SET(quit,0), [nHead]{len}CPUT(board)
LOCATE(1,1), FILL-BOX(" ",29,54)
GOSUB( another play )
ELS
GOSUB(you lost), SLEEP(3)
--lives
SET(quit,0)
TRUE(swPierde)
{len}GOSUB( start )
COND( IS-NOT-ZERO?(lives) )
SYS("aplay fl/Snake_music_vida_repechaje.wav </dev/null >/dev/null 2>&1 &")
CEND
CEND
 
WEND
GOSUB(you lost), SLEEP(1)
/* GAME OVER */
GOSUB(game over ), SLEEP(2)
LOCATEGOSUB(ADD(h,1game over ),1) PRNLSLEEP(7)
SET-VIDEO-TEXT
SHOW-CURSOR
PRNL
Line 391 ⟶ 470:
 
RUTINES
 
DEF-FUN( KILLSOUND )
SET( PID,0 )
LET( PID := ONLY-CHR("0123456789 ", EXEC( "pidof aplay" )))
COND( LEN(PID) )
SYS( CAT(CAT("kill ",PID), " </dev/null >/dev/null 2>&1"))
CEND
RET
 
// initialize the board, plant a very first food item
DEF-FUN( start, initial pos )
SET( i,1 )
 
COND( NOT-EQ?(LEVEL,3) )
[1:w] {BORDER} CPUT(board) // top
[ SUB(MUL(h,w),MINUS-ONE(w)) : end] {BORDERtBoard1} CPUTMOVE-TO(board) // bottom
{50,28},MUL(50,28), MOVE-TO( w, h, Size )
[1:w:end] {BORDER} CPUT(board) // left
[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( time out:=TIME_LEVEL )
ELS
TRASH(board)
CEND
SELECT(LEVEL)
CASE(2){
SET(i,3)
PERF-UP(i,5,1)
// laterales extremos:
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
// laterales fondo
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
 
NEXT
EXIT
}
CASE(3){ // challenge stage!
SPLIT(Maze,board, "" ), VAL(board), MOVE-TO(board)
[1:w] {BORDER}CPUT(board)
SET(i,1)
PERF-UP(i,19,1)
GOSUB(plant)
NEXT
LET(time out := TIME_CHALLENGE)
EXIT
}
CASE(4){
SET(i,3)
PERF-UP(i,5,1)
// laterales medios
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
// medio arriba
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
// medio abajo
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
NEXT
EXIT
}
CASE(5){
SET(i,3)
PERF-UP(i,5,1)
// laterales extremos:
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
// laterales medios
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
// laterales fondo
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
// medio arriba
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
// medio abajo
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
NEXT
EXIT
}
CASE(6){
SET(i,1)
PERF-UP(i,29,1)
GOSUB(plant)
NEXT
LET(time out := TIME_CHALLENGE)
}
CASE(7){
SET(i,3)
PERF-UP(i,5,1)
// laterales extremos:
[ADD(MUL(i,w),5):ADD(MUL(i,w),8)] {BORDER} CPUT(board)
[ADD(MUL(i,w),SUB(w,7)):ADD(MUL(i,w),SUB(w,4))] {BORDER} CPUT(board)
// laterales medios
[ADD(MUL(ADD(i,9),w),5):ADD(MUL(ADD(i,9),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,9),w),SUB(w,7)):ADD(MUL(ADD(i,9),w),SUB(w,4))] {BORDER} CPUT(board)
// laterales fondo
[ADD(MUL(ADD(i,19),w),5):ADD(MUL(ADD(i,19),w),8)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),SUB(w,7)):ADD(MUL(ADD(i,19),w),SUB(w,4))] {BORDER} CPUT(board)
// medio arriba
[ADD(MUL(i,w),17):ADD(MUL(i,w),20)] {BORDER} CPUT(board)
[ADD(MUL(i,w),31):ADD(MUL(i,w),34)] {BORDER} CPUT(board)
// medio medio
[ADD(MUL(ADD(i,9),w),17):ADD(MUL(ADD(i,9),w),20)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,9),w),31):ADD(MUL(ADD(i,9),w),34)] {BORDER} CPUT(board)
// medio abajo
[ADD(MUL(ADD(i,19),w),17):ADD(MUL(ADD(i,19),w),20)] {BORDER} CPUT(board)
[ADD(MUL(ADD(i,19),w),31):ADD(MUL(ADD(i,19),w),34)] {BORDER} CPUT(board)
NEXT
EXIT
}
SELEND
COND( NOT-EQ?(LEVEL,3) )
LET( nHead := MUL( w, SUB( SUB( h, 1 ), MOD(h,2) )) DIV-INTO(2) )
LET( dir := N )
ELS
LET( nHead := ADD( MUL( w, 13 ), 26 ) )
LET( dir := N )
CEND
[ nHead ] {initial pos} CPUT( board )
 
IF( swPierde, SRAND( ~SECONDS); FALSE(swPierde); {TIME_LOST} »» (time out),\
SRAND( 26785 ) )
 
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
Line 413 ⟶ 613:
DEF-FUN( you lost )
SET(i,1), SET(k,0), SET(n,1)
LOCATE(1,1)
FOR( LE?(i, h), ++i)
SET(j,1)
Line 420 ⟶ 619:
COND( IS-NEG?( k ))
LOCATE(i,j)
PRNLPRN("\033[38;15;3m\033[48;5;9m~\OFF")
CEND
++n
NEXT
NEXT
SYS("aplay fl/Snake_dolor.wav </dev/null >/dev/null 2>&1 &")
RET
 
DEF-FUN( show )
 
SET(i,1)
MSET(j, k)
 
SET(n,1)
LOCATE(1,1)
FOR( LE?(i, h), ++i)
SET(j,1),LOG-INV(tiles)
FOR( LE?(j, w), ++j)
LET( k := [ n ] GET(board) )
COND( IS-NEG?( k ))
PRNCOND("\033[38;5;3m\033[48;5;15m~\OFF" NOT-EQ?(n,nHead) )
IF(GT?(k,-3),IF(tiles,{tile1},{tile2});{"\033[38;5;15m+\OFF"},"\033[38;5;6m\033[48;5;11m \OFF")
ELS
COND( EQ?(dir,N))
IF(tiles,"\033[38;5;9m\033[48;5;15mv\OFF","\033[38;5;9m\033[48;5;15m|\OFF")
 
ELS-COND( EQ?(dir,S))
IF(tiles,"\033[38;5;9m\033[48;5;15m|\OFF","\033[38;5;9m\033[48;5;15m^\OFF")
 
ELS-COND( EQ?(dir,E))
IF(tiles,"\033[38;5;9m\033[48;5;15m<\OFF","\033[38;5;9m\033[48;5;15m-\OFF")
 
ELS
IF(tiles,"\033[38;5;9m\033[48;5;15m-\OFF","\033[38;5;9m\033[48;5;15m>\OFF")
 
CEND
CEND
ELS-COND( {k} IS-EQ?(BORDER))
{"\033[38;5;4m82m\033[48;5;2m57m \OFF"}
 
PRN( [k] GET(symbol),"\OFF")
ELS-COND( {k}IS-EQ?(FOOD) )
COLOR-FG(color food ),IF(tiles,{tile1},{tile2}) //back food)
{"\033[38;5;15m\033[48;5;9m"}
PRN( [k] GET(symbol),{"@\OFF")}
ELS
IF(tiles,{"\033[48;5;28m"tile1},{tile2})
{" PRN( [k] GET(symbol),"\OFF")}
CEND
PRN
LOG-INV(tiles)
++n
NEXT
PRNL
NEXT
color food+=2,
back food-=2, WHEN( EQ?(color food, PLUS-ONE(BACK_FOOD))){
LET( color food:=COLOR_FOOD)
LET( back food:=BACK_FOOD)
}
RET
 
Line 464 ⟶ 689:
 
GET( board ) PLUS(1) »» (jAge)
// this is necessary, because Hopper arrays begining in 1
CART( IS-ZERO?(jAge) ) »» (jR)
Line 471 ⟶ 697:
// ******
{jAge} PUT(board), CLR-RANGE
 
RET
 
DEF-FUN( step )
SET(len,0)
LET( len := [nHead] GET(board) )
SWITCHSELECT(dir)
CASE (N){ nHead -= w, EXIT }
CASE (S){ nHead += w, EXIT }
CASE (W){ --nHead, EXIT }
CASE (E){ ++nHead, EXIT }
SWENDSELEND
SWITCHSELECT( [nHead]CGET(board))
CASE (SPACE){
--len, LET( len := IF( IS-ZEROEQ?(len,0), 1, len) )
[nHead] { len }, CPUT(board) // keep in mind len is negative
GOSUB( age )
Line 490 ⟶ 716:
}
CASE (FOOD){
--len, LETCOND( len := IFNOT(OR( IS-ZEROEQ?(lenLEVEL,3), 1EQ?(LEVEL, len6))) )
--len, LET( len := IF( IS-ZERO?(len), 1, len) )
ELS
++len // quita celda del cuerpo: suma vida!
CEND
[nHead] { len }, CPUT(board)
WHEN(AND(NOT-EQ?(LEVEL,3),NOT-EQ?(LEVEL,6))){ GOSUB( plant ) }
ADD(SCORE,TIME), MOVE-TO(SCORE)
 
{SCORE, 4, 52COLUMNA_PRINT} GOSUB( put score )
LET( TIME := 100 )
++counter, COND( GTEQ?( counter, 525 ) )
LET( TLimit := SUB( TLimit,5 ))
CLAMP(30INF_TIME,100 LIMIT_TIME, TLimit)
LET( counter := 0 )
CEND
WHEN( OR(EQ?(LEVEL,3),EQ?(LEVEL,6))){ ++Consumed stage }
++ConsPrey
COLOR-FG(10)
LOCATE(20,52COLUMNA_PRINT) PRNLPRN("SPEED: ")
LOC-ROW(21), SET-PRN( ROUND(MUL(INV(TLimit),LIMIT_TIME),2), " M/S " )
PRNL( MUL(INV(TLimit),100), " M/S" )
LOC-ROW(23) PRN("CONSUMED SET-ROUND(-1PREY:")
LOC-ROW(2324) PRNLPRN(ConsPrey,"CONSUMED PREY:\OFF")
LOC-ROW(24) PRNL(ConsPrey,"\OFF")
LET( color food:=COLOR_FOOD)
LET( back food:=BACK_FOOD)
SYS("aplay fl/Snake_mascada.wav </dev/null >/dev/null 2>&1 &")
TIC( T ),{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
 
TIC( T ),{TIME, 12, 52} GOSUB( put time )
EXIT
}
LET(CASE-NEGATIVE quit := 1 ){
GOSUB(KILLSOUND)
SYS("aplay fl/Snake_mascada.wav </dev/null >/dev/null 2>&1")
SWEND
LET( quit := 1 )
EXIT
}
DEFAULT {
GOSUB(KILLSOUND)
SYS("aplay fl/Snake_golpe.wav </dev/null >/dev/null 2>&1")
 
LET( quit := 1 )
}
SELEND
RET
 
DEF-FUN( LEVELCLEAR )
GOSUB(KILLSOUND)
GOSUB( level clear )
SYS("aplay fl/Snake_level_clear.wav </dev/null >/dev/null 2>&1")
SLEEP(1)
WHEN( OR( EQ?(LEVEL,3), EQ?(LEVEL,6))){
WHEN( EQ?(Consumed stage,20)){
GOSUB( show )
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
GOSUB(GANA BONO),SLEEP(3)
ADD(SCORE,1000), MOVE-TO(SCORE)
{SCORE, 4, COLUMNA_PRINT} GOSUB( put score )
}
}
GOSUB( another play )
RET
 
DEF-FUN( another play )
++sound index, WHEN( EQ?(sound index,6)){ LET(sound index := 2) }
back tiles+=2, WHEN( EQ?(back tiles,15)){ LET(back tiles:=1) }
 
[back tiles] GET(head back tiles), MOVE-TO(tile1)
[PLUS-ONE(back tiles)] GET(head back tiles), MOVE-TO(tile2)
++LEVEL, WHEN( GT?(LEVEL,7)){ LET(LEVEL:=1) }
++ REAL LEVEL
COLOR-FG(15),LOCATE(26,COLUMNA_PRINT) SET-ITALIC, PRN("LEVEL: ",REAL LEVEL,"\OFF")
 
LET( len := [nHead] GET(board) )
[1:Size] MEM(1) CPUT(board)
CLR-INTERVAL
MEM(len), GOSUB( start )
GOSUB( show )
COND( OR( EQ?(LEVEL,3), EQ?(LEVEL,6)))
GOSUB(challenge stage)
ELS
GOSUB( ready )
CEND
SLEEP(2)
SYS( CAT(CAT("aplay fl/",[sound index]CGET(sounds)), "</dev/null >/dev/null 2>&1 &"))
LET( TIME := TOTAL_TIME )
{TIME, 12, COLUMNA_PRINT} GOSUB( put time )
RET
 
Line 529 ⟶ 822:
 
DEF-FUN( put titles )
LOCATE(2,52COLUMNA_PRINT) PRNLPRN("\033[38;5;15mSCORE\OFF")
{SCORE, 4, 52COLUMNA_PRINT} GOSUB( put score )
LOCATE(10,52COLUMNA_PRINT) PRNLPRN("\033[38;5;11mTIME\OFF")
{TIME, 12, 52COLUMNA_PRINT} GOSUB( put time )
 
COLOR-FG(15)
LOCATE(26,52COLUMNA_PRINT) SET-ITALIC, PRNL PRN("LEVEL: ",REAL S P E E DLEVEL,"\OFF")
LOC-ROWLOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRNLPRN("SLIVES: N A K E!",lives,"\OFF")
 
RET
 
Line 550 ⟶ 844:
LET( p4 := ADD( posx, 4 ))
COLOR-FG(11)
{"\033[38;5;11m\ENF"}
PERF-UP(k, lsb, 1)
LET( nB := VAL( MID( 1, k, sb )) )
Line 557 ⟶ 851:
SET( j, rx )
FOR( LE?(j, ADD( rx, 2 ) ), ++j )
LOCATE(i, j) PRNLPRN( STR-TO-UTF8(CHAR( [ PLUS-ONE(nB), x] CGET(big number) MUL-BY(219) )))
++x
NEXT
Line 563 ⟶ 857:
rx += 4
NEXT
PRNLPRN("\OFF")
RET
 
Line 574 ⟶ 868:
LOCATE ( posx, posy ) FILL-BOX(" ",4,20)
SET(i, 1)
COLOR-FG(15)
{"\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 ), PRN ( STR-TO-UTF8( GET(numL1) ))
PRNLLOC-ROW( PLUS-ONE(posx) ), PRN ( STR-TO-UTF8( GET(numL1numL2) ))
LOCATELOC-ROW( PLUS-ONETWO(posx) ),posy PRN ( STR-TO-UTF8( GET(numL3) ))
PRNL ( STR-TO-UTF8( GET(numL2) ))
LOCATE( PLUS-TWO(posx),posy )
PRNL ( STR-TO-UTF8( GET(numL3) ))
posy += 2
NEXT
PRNLPRN("\OFF")
COND( swExtra1 )
COND( GE?(SCORE,5000) )
++lives
FALSE(swExtra1)
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
LOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRN("LIVES: ",lives,"\OFF")
CEND
ELS-COND(swExtra2)
COND( GE?(SCORE,10000) )
++lives
FALSE(swExtra2)
SYS( "aplay fl/Snake_bono.wav </dev/null >/dev/null 2>&1 &" )
LOCATE(27,COLUMNA_PRINT) SET-INVERSE, PRN("LIVES: ",lives,"\OFF")
CEND
CEND
RET
 
Line 611 ⟶ 917:
{"\033[38;5;4m\033[48;5;11m"}
LOC-COL(16)
LOC-ROW(13); PRNLPRN( STR-TO-UTF8(" ▄ ▄▄ ▄ ▄▄ ▄ ▄ "))
LOC-ROW(14); PRNLPRN( STR-TO-UTF8(" █▄▀ █▀ █▄█ █ █ ▀▄▀ "))
LOC-ROW(15); PRNLPRN( STR-TO-UTF8(" ▀ ▀ ▀▀ ▀ ▀ ▀▄▀ ▀ "))
PRNLPRN("\OFF")
RET
 
DEF-FUN( level clear )
{"\033[38;5;4m\033[48;5;11m"}
LOC-COL(17)
LOC-ROW(12); PRN( STR-TO-UTF8( " ▄ ▄▄ ▄ ▄ ▄▄ ▄ "))
LOC-ROW(13); PRN( STR-TO-UTF8( " █ █▀ █ █ █▀ █ "))
LOC-ROW(14); PRN( STR-TO-UTF8( " ▀ ▀▀ ▀ ▀▀ ▀ "))
LOC-ROW(15); PRN( STR-TO-UTF8( " ▄ ▄ ▄▄ ▄ ▄ "))
LOC-ROW(16); PRN( STR-TO-UTF8( " █ █ █▀ █▄█ █▄▀ "))
LOC-ROW(17); PRN( STR-TO-UTF8( " ▀ ▀ ▀▀ ▀ ▀ ▀ ▀ "))
PRN("\OFF")
RET
 
DEF-FUN( challenge stage )
{"\033[38;5;4m\033[48;5;11m"}
LOC-COL(9)
LOC-ROW(12); PRN( STR-TO-UTF8( " ▄ ▄ ▄ ▄ ▄ ▄ ▄▄ ▄ ▄▄ ▄▄ "))
LOC-ROW(13); PRN( STR-TO-UTF8( " █ █▄█ █▄█ █ █ █▀ █ █ █ ▄ █▀ "))
LOC-ROW(14); PRN( STR-TO-UTF8( " ▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀ ▀ ▀ ▀▀ ▀▀ "))
LOC-ROW(15); PRN( STR-TO-UTF8( " ▄ ▄ ▄ ▄ ▄▄ ▄▄ "))
LOC-ROW(16); PRN( STR-TO-UTF8( " ▀▄ █ █▄█ █ ▄ █▀ "))
LOC-ROW(17); PRN( STR-TO-UTF8( " ▀ ▀ ▀ ▀ ▀▀ ▀▀ "))
PRN("\OFF")
RET
 
DEF-FUN( GANA BONO )
{"\033[38;5;11m\033[48;5;196m"}
LOC-COL(17)
LOC-ROW(12); PRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄ ▄ ▄ "))
LOC-ROW(13); PRN( STR-TO-UTF8(" █▄▀ █ █ █ █ █ █ ▀▄ "))
LOC-ROW(14); PRN( STR-TO-UTF8(" ▀▄▀ ▀ ▀ ▀ ▀ ▀ "))
LOC-ROW(15); PRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄ "))
LOC-ROW(16); PRN( STR-TO-UTF8(" █ █ █ █ █ █ █ "))
LOC-ROW(17); PRN( STR-TO-UTF8(" █ ▄ ▀▄▀ ▀▄▀ ▀▄▀ "))
PRN("\OFF")
RET
 
Line 620 ⟶ 962:
{"\033[38;5;15m\033[48;5;9m"}
LOC-COL(17)
LOC-ROW(12); PRNLPRN( STR-TO-UTF8(" ▄▄ ▄ ▄ ▄ ▄▄ "))
LOC-ROW(13); PRNLPRN( STR-TO-UTF8(" █ ▄ █▄█ █ █ █ █▀ "))
LOC-ROW(14); PRNLPRN( STR-TO-UTF8(" ▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀ "))
LOC-ROW(15); PRNLPRN( STR-TO-UTF8(" ▄ ▄ ▄ ▄▄ ▄ "))
LOC-ROW(16); PRNLPRN( STR-TO-UTF8(" █ █ █ █ █▀ █▄▀ "))
LOC-ROW(17); PRNLPRN( STR-TO-UTF8(" ▀ ▀ ▀▀ ▀ ▀ "))
PRNLPRN("\OFF")
RET
</lang>
{{out}}
Init game:
<pre>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ @ SCORE
@ @
@ @ ┌┐
@ @ ││
@ @ └┘
@ @
@ @
@ @
@ @ TIME
@ @
@ @ ██ ███ ███
@ ▄ ▄▄ ▄ ▄▄ ▄ ▄ @ █ █ █ █ █
@ █▄▀ █▀ █▄█ █ █ ▀▄▀ @ █ █ █ █ █
@ ▀ ▀ ▀▀ ▀ ▀ ▀▄▀ ▀ @ █ █ █ █ █
@ @ ███ ███ ███
@ @
@ $ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @ S P E E D
@ @ S N A K E!
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
DEF-FUN( titles )
</pre>
#define COLOR_INI 232
Play game:
#define COLOR_FIN 255
<pre>
SET(k,1)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PERF-UP(k,2,1)
@ @ SCORE
SET(j,COLOR_INI), SET(jbg,COLOR_FIN)
@ @
PERF-UP(j,COLOR_FIN,1)
@ @ ┌┐┌┐┌┐
COLOR(j, jbg--)
@ @ ├┐┌┘││
LOC-COL(17)
@ @ └┘└┘└┘
@ LOC-ROW(12); PRN(STR-TO-UTF8(" @ "))
@ LOC-ROW(13); PRN(STR-TO-UTF8(" ▄▄ @"))
LOC-ROW(14); PRN(STR-TO-UTF8(" ▀▄ █ █ █▄█ █▄ █▀ "))
@ @
@ LOC-ROW(15); PRN(STR-TO-UTF8(" ▀▀ @ TIME"))
@ LOC-ROW(16); PRN(STR-TO-UTF8(" ▄▄ ▄▄ ▄▄ @"))
LOC-ROW(17); PRN(STR-TO-UTF8(" ▀▄ █▄█ █▀ █▀ █ █ "))
@ @ ███ ███
LOC-ROW(18); PRN(STR-TO-UTF8(" ▀ ▀ ▀▀ ▀▀ ▀▄▀ "))
@ @ █ █ █
@ LOC-ROW(19); PRN(STR-TO-UTF8(" @ █ █ █ "))
MICROSECS(20000)
@ @ █ █ █
NEXT
@ @ █ ███
SET(j,COLOR_FIN), SET(jbg,COLOR_INI)
@ @
PERF-DOWN(j,COLOR_INI,1)
@ @
COLOR(j, jbg++)
@ @
LOC-COL(17)
@ ~~~~~~ @ SPEED:
@ ~ LOC-ROW(12); PRN(STR-TO-UTF8(" @ 1.00 M/S"))
@ ~ LOC-ROW(13); PRN(STR-TO-UTF8(" ▄▄ @ "))
LOC-ROW(14); PRN(STR-TO-UTF8(" ▀▄ █ █ █▄█ █▄ █▀ "))
@ ~~~~~~ $ @ CONSUMED PREY:
@ LOC-ROW(15); PRN(STR-TO-UTF8(" ▀▀ @ 11"))
@ LOC-ROW(16); PRN(STR-TO-UTF8(" ▄▄ ▄▄ ▄▄ @"))
LOC-ROW(17); PRN(STR-TO-UTF8(" ▀▄ █▄█ █▀ █▀ █ █ "))
@ @ S P E E D
@ LOC-ROW(18); PRN(STR-TO-UTF8(" ▀▀ ▀▀ ▀▄▀ @ S N A K E!"))
LOC-ROW(19); PRN(STR-TO-UTF8(" "))
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
MICROSECS(20000)
NEXT
NEXT
PRN("\OFF")
RET
 
DEF-FUN( prepare maze )
</pre>
REPL(12,ADD(MUL(w, 3),20),"333333333333",Maze), MOVE-TO(Maze)
Game over:
REPL(12,ADD(MUL(w, 24),20),"333333333333",Maze), MOVE-TO(Maze)
<pre>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
REPL(12,ADD(MUL(w, 6),7),"333333333333",Maze), MOVE-TO(Maze)
@ @ SCORE
REPL(12,ADD(MUL(w, 6),33),"333333333333",Maze), MOVE-TO(Maze)
@ @
@ @ ┐┌┐┌┐┌┐
@ @ │└┐└┐││
@ @ ┴└┘└┘└┘
@ @
@ @
@ @
@ @ TIME
@ @
@ ▄▄ ▄ ▄ ▄ ▄▄ @ █ █ ███
@ █ ▄ █▄█ █ █ █ █▀ @ █ █ █ █
@ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀ @ ███ █ █
@ ▄ ▄ ▄ ▄▄ ▄ @ █ █ █
@ █ █ █ █ █▀ █▄▀ @ █ ███
@ ~ ▀ ▀ ▀▀ ▀ ▀ @
@ ~ @
@ ~ @
@ ~ @ SPEED:
@ ~ @ 1.10 M/S
@ ~~~~~~~~~~~~~ @
@ ~ @ CONSUMED PREY:
@ ~ @ 17
@ ~ @
@ ~ @ S P E E D
@ ~ $ @ S N A K E!
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
REPL(12,ADD(MUL(w, 21),7),"333333333333",Maze), MOVE-TO(Maze)
</pre>
REPL(12,ADD(MUL(w, 21),33),"333333333333",Maze), MOVE-TO(Maze)
SET(i,7)
PERF-UP(i,10,1)
REPL(1,ADD(MUL(w, i),7),"3",Maze), MOVE-TO(Maze)
REPL(1,ADD(MUL(w, i),44),"3",Maze), MOVE-TO(Maze)
REPL(1,ADD(MUL(w, ADD(i,10)),44),"3",Maze), MOVE-TO(Maze)
REPL(1,ADD(MUL(w, ADD(i,10)),7),"3",Maze), MOVE-TO(Maze)
NEXT
RET
</syntaxhighlight>
{{out}}
[[File:Captura_de_pantalla_de_2022-10-07_14-13-27.png]]
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">gosub Init
Gui, +AlwaysOnTop
Gui, font, s12, consolas
Line 848 ⟶ 1,151:
return [oGrid, row, col]
}
;-----------------------------------------</langsyntaxhighlight>
 
=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
Rather than using DIM X%(1599),Y%(1599) which takes a long time to initialize, instead to speed this up, the program will POKE and PEEK the snake coordinates in memory. On initialization, LOMEM: 24576 moves variables out of the way.
 
Continue playing by typing the CONT command from the Applesoft BASIC prompt if you quit or it's game over.
<syntaxhighlight lang="basic">REM === VARIABLES ===
REM
REM D(4) X DELTAS
REM E(4) Y DELTAS
REM K(255) KEYCODE BEHESTS
REM FN X X COORDINATES OF SNAKE FROM MEMORY
REM FN Y Y COORDINATES OF SNAKE FROM MEMORY
REM A <UNUSED>
REM B BEHEST: 0=NOTHING 1=RIGHT 2=LEFT 3=DOWN 4=UP 5=QUIT
REM C SCRN COLOR
REM D X-DELTA
REM E Y-DELTA
REM F FOOD COLOR= 4 DARK GREEN
REM H HIT= 127
REM I KEYBOARD= 49152
REM J CLEAR KEYBOARD= 49168
REM K KEYCODE
REM L LENGTH WIDTH&HEIGHT= 40
REM M MAX= 1599 UPPER BOUND OF SNAKE X AND Y COORDINATES
REM N NEW POSITION OF HEAD OF SNAKE
REM O OLD POSITION OF TAIL OF SNAKE
REM P ADDRESS OF 1600 X COORDINATES OF SNAKE
REM Q QUIT= 5
REM R REMAINING COLOR= 9 ORANGE
REM S SNAKE HEAD COLOR= 13 YELLOW
REM T ONE= 1
REM U X FOOD COORDINATE
REM V Y FOOD COORDINATE
REM W WALL COLOR= 10 GREY
REM X X SNAKE HEAD COORDINATE
REM Y Y SNAKE HEAD COORDINATE
REM Z ADDRESS OF 1600 Y COORDINATES OF SNAKE
REM Q$ QUIT MESSAGE
 
REM === KEYBOARD ===
REM
REM UPPER LOWER KEY BEHEST
REM 155 ESC QUIT
REM 139 UP UP
REM 193 225 A UP
REM 201 233 I UP
REM 138 DOWN DOWN
REM 218 250 Z DOWN
REM 203 235 K DOWN
REM 136 LEFT LEFT
REM 202 234 J LEFT
REM 149 RIGHT RIGHT
REM 204 236 L RIGHT
 
0 ON B = Q GOTO 5: IF B THEN D = D(B):E = E(B)
1 X = X + D:Y = Y + E:C = SCRN( X,Y): COLOR= S: PLOT X,Y: COLOR= R: PLOT FN X(N), FN Y(N):N = N - T + (N = 0) * M: POKE P + N,X: POKE Z + N,Y: ON C(C) GOTO 4: IF NOT C THEN COLOR= 0: PLOT FN X(O), FN Y(O):O = O - T + (O = 0) * M
2 IF C THEN U = INT ( RND (T) * L):V = INT ( RND (T) * L): ON SCRN( U,V) > 0 GOTO 2: COLOR= F: PLOT U,V
3 K = PEEK (I):B = PEEK (J * (K > H)):B = K(K): GOTO
4 COLOR= T: PLOT X,Y: READ Q$: DATA5,20,20,1,-1,1,-1,13,9,4,10,1,40,1599,127,49152,49168,4608,6400,5,4,4,4,4,4,3,3,3,3,3,2,2,2,1,1,1,DONE,GAME OVER
5 IF Q = 5 THEN PRINT Q$;: END : HOME :Q = Q * (B = Q):B = 0: ON Q = 5 GOTO : RUN
6 LOMEM: 24576
7 DIM K(255),D(4),E(4),C(15): READ Q,X,Y,D(1),D(2),E(3),E(4),S,R,F,W,T,L,M,H,I,J,P,Z,K(155),K(139),K(193),K(225),K(201),K(233),K(138),K(218),K(250),K(203),K(235),K(136),K(202),K(234),K(149),K(204),K(236),Q$
8 DEF FN X(I) = PEEK (P + I): DEF FN Y(I) = PEEK (Z + I):B = RND (0):C(S) = T:C(R) = T:C(W) = T:B = INT ( RND (T) * 4) + T:D = D(B):E = E(B): POKE P + O,X: POKE Z + O,Y
9 GR : HOME : COLOR= W: VLIN 0,39 AT 0: VLIN 0,39 AT 39: HLIN 1,38 AT 0: HLIN 1,38 AT 39: COLOR= F: PLOT X + D,Y + E: GOTO</syntaxhighlight>
 
==={{header|Craft Basic}}===
[[File:Craft Basic Snake.png|right]]
<syntaxhighlight lang="basic">rem Snake example game for Craft Basic
rem by Gemino Smothers 2022
rem www.lucidapogee.com
 
title "Snake!"
 
define gfxx = 330, gfxy = 296
define upkey = 0, rightkey = 0, downkey = 0, leftkey = 0, esckey = 0
define speed = 0, delay = 0, score = 0, game = 1
define maxsize = 1000, size = 9, direction = int(rnd * 4) + 1
define rx = int(rnd * (gfxx - 24)) + 12
define ry = int(rnd * (gfxy - 40)) + 25
 
dim sx[maxsize]
dim sy[maxsize]
 
let sx[0] = gfxx / 2
let sy[0] = gfxy / 2
 
fill on
bgcolor 128, 64, 0
cls graphics
 
resize 0, 0, gfxx + 10, gfxy + 56
center
 
formid 1
staticform 1, 1, 100, 14
fgcolor 255, 255, 0
bgcolor 0, 80, 0
colorform
 
alert "Snake! by Gemino Smothers 2022"
alert "Get the gray little rodents and avoid hitting yourself or walls."
alert "Use arrow keys to move. Esc to exit."
 
input "Enter game speed between 0 to 100+", speed
 
fgcolor 0, 80, 0
rect 0, 0, gfxx, gfxy
 
do
 
button upkey, 38
button rightkey, 39
button downkey, 40
button leftkey, 37
button esckey, 27
 
if upkey = 1 and direction <> 3 then
 
let direction = 1
 
endif
 
if rightkey = 1 and direction <> 4 then
 
let direction = 2
 
endif
 
if downkey = 1 and direction <> 1 then
 
let direction = 3
 
endif
 
if leftkey = 1 and direction <> 2 then
 
let direction = 4
 
endif
 
fgcolor 0, 80, 0
oval sx[size], sy[size], 15, 15
 
let i = size + 1
 
do
 
let i = i - 1
let c = i - 1
 
if sx[0] = sx[i] and sy[0] = sy[i] = 1 then
 
let game = 0
 
endif
 
let sx[i] = sx[c]
let sy[i] = sy[c]
 
fgcolor 0, 255, 0
oval sx[i], sy[i], 15, 15
 
loop i > 1
 
fgcolor 0, 0, 255
oval sx[0] + 5, sy[0] + 5, 3, 3
oval sx[0] + 9, sy[0] + 5, 3, 3
 
if direction = 1 then
 
let sy[0] = sy[0] - 15
 
endif
 
if direction = 2 then
 
let sx[0] = sx[0] + 15
 
endif
 
if direction = 3 then
 
let sy[0] = sy[0] + 15
 
endif
 
if direction = 4 then
 
let sx[0] = sx[0] - 15
 
endif
 
if sx[0] <= -10 or sx[0] >= gfxx or sy[0] <= -10 or sy[0] >= gfxy = 1 then
 
let game = 0
 
endif
 
if sx[0] + 15 >= rx and sx[0] <= rx + 15 and sy[0] + 15 >= ry and sy[0] <= ry + 15 = 1 then
 
playwave "examples\tada.wav"
 
fgcolor 0, 80, 0
rect 0, 0, gfxx, gfxy
 
let rx = int(rnd * (gfxx - 24)) + 12
let ry = int(rnd * (gfxy - 40)) + 25
 
let size = size + 3
let score = score + 1
 
endif
 
fgcolor 100,100,100
oval rx, ry, 15, 15
 
fgcolor 255, 0, 0
oval rx + 5, ry + 5, 3, 3
oval rx + 9, ry + 5, 3, 3
 
fgcolor 255, 255, 0
formid 1
formtext "Score: ", score
updateform
 
let delay = clock
 
do
 
wait
 
loop clock < delay + speed
 
loop esckey <> 1 and game = 1
 
playwave "examples\boom.wav"
alert "Game over! Score: ", score</syntaxhighlight>
 
==={{header|FreeBASIC}}===
<langsyntaxhighlight lang="freebasic">
REM Snake
 
Line 969 ⟶ 1,508:
End
'--------------------------
</syntaxhighlight>
</lang>
 
==={{header|Integer BASIC}}===
{{Trans|Applesoft BASIC}}
<syntaxhighlight lang="basic"> 0 IF B=Q THEN GOTO 9: IF B THEN D=D(B): IF B THEN E=E(B):X=X+D:Y=Y+E:A= SCRN(X,Y): COLOR=S: PLOT X,Y: COLOR=R: PLOT X(N),Y(N)
1 N=N-T+(N=1)*M:X(N)=X:Y(N)=Y: IF C(A) THEN GOTO 9: IF A THEN GOTO 2: COLOR=0: PLOT X(O),Y(O):O=O-T+(O=1)*M: GOTO 3
2 U= RND (L):V= RND (L): IF SCRN(U,V)>0 THEN GOTO 2: COLOR=F: PLOT U,V
3 K= PEEK (I):B= PEEK (J*(K>H)):B=K(K): GOTO 0
4 DIM X(1600),Y(1600),K(255),D(4),E(4),C(15): FOR I=0 TO 255:K(I)=0: NEXT I: FOR I=1 TO 4:D(I)=0:E(I)=0: NEXT I
5 FOR I=0 TO 15:C(I)=0: NEXT I:Q=5:X=20:Y=20:E(1)=-1:D(2)=-1:E(3)=1:D(4)=1:S=13:R=9:F=4:W=10:T=1:L=40:M=1600
6 H=127:I=-16384:J=-16368:K(155)=5:K(193)=1:K(225)=1:K(201)=1:K(233)=1:K(136)=2:K(202)=2:K(234)=2:N=1:O=1
7 K(218)=3:K(250)=3:K(203)=3:K(235)=3:K(149)=4:K(204)=4:K(236)=4:C(S)=T:C(R)=T:C(W)=T:B= RND (4)+T:D=D(B)
8 E=E(B):X(O)=X:Y(O)=Y: GR : CALL -936: COLOR=W: VLIN 0,39 AT 0: VLIN 0,39 AT 39: HLIN 1,38 AT 0: HLIN 1,38 AT 39: COLOR=F: PLOT X+D,Y+E: GOTO 0
9 IF Q#5 THEN GOTO 4:Q=Q*(B=Q): COLOR=T: IF Q=0 THEN PLOT X,Y: IF Q=0 THEN PRINT "GAME OVER";: IF Q THEN PRINT "DONE";:K= PEEK (J):B=0: END </syntaxhighlight>
==={{header|Locomotive Basic}}===
 
Line 976 ⟶ 1,527:
 
If you are playing this in [https://benchmarko.github.io/CPCBasic/cpcbasic.html CPCBasic], first click on the CPC screen so it gets keyboard input and then enter "run" (clicking the Run button would deselect the screen again).
<langsyntaxhighlight lang="locobasic">10 mode 1:randomize time
20 sx=20:sy=5:dx=1:dy=0:ml=20:dim ox(ml),oy(ml):oi=1:ll=4:skill=6
30 f$=chr$(228):w$=chr$(127):b$=chr$(231)
Line 1,005 ⟶ 1,556:
280 if a$<>" " then 260
290 print f$;
300 return</langsyntaxhighlight>
 
==={{header|ZX Spectrum Basic}}===
Line 1,013 ⟶ 1,564:
 
Note that lines <code>10</code> to <code>210</code> and <code>580</code> to <code>890</code>—more than half the program—define graphics characters for the snake's head (facing in different directions) and for its food. If you're happy to make do with characters from the standard character set, you can easily adapt lines <code>220</code> to <code>570</code> to work on their own. The things the snake eats are supposed to be apples, although they don't look too much like them.
<langsyntaxhighlight lang="zxbasic"> 10 FOR i=0 TO 7
20 READ bits
30 POKE USR "L"+i,bits
Line 1,101 ⟶ 1,652:
870 DATA BIN 11111100
880 DATA BIN 01111111
890 DATA BIN 00110110</langsyntaxhighlight>
 
=={{header|C}}==
As some implementation below (C++) works on Windows console, let it work on Linux. Other implementations could be added as well, reusing the api.
<langsyntaxhighlight lang="c">// Snake
 
// The problem with implementing this task in C is, the language standard
Line 1,247 ⟶ 1,798:
close_screen();
return 0;
}</langsyntaxhighlight>
 
=={{header|C++}}==
Simple Windows console implementation.
[[File:SnakeCpp.png|200px|thumb|right]]
<langsyntaxhighlight lang="cpp">
#include <windows.h>
#include <ctime>
Line 1,365 ⟶ 1,916:
snake s; s.play(); return 0;
}
</syntaxhighlight>
</lang>
 
=={{header|Delphi}}==
{{libheader| Winapi.Windows}}
Line 1,376 ⟶ 1,928:
{{libheader| Vcl.ExtCtrls}}
{{Trans|JavaScript}}
<syntaxhighlight lang="delphi">
<lang Delphi>
unit SnakeGame;
 
Line 1,732 ⟶ 2,284:
FrameTimer.Enabled := True;
end;
end.</langsyntaxhighlight>
Form resources:
<syntaxhighlight lang="delphi">
<lang Delphi>
object SnakeApp: TSnakeApp
OnCreate = FormCreate
end
</syntaxhighlight>
</lang>
 
=={{header|EasyLang}}==
[https://easylang.dev/apps/snake.html Run it]
{{Trans|Craft Basic}}
<syntaxhighlight>
subr fruit
rx = (randint 20 - 1) * 5 + 2.5
ry = (randint 20 - 1) * 5 + 2.5
.
subr start
fruit
game = 1
sx[] = [ 52.5 0 0 0 0 ]
sy[] = [ 52.5 0 0 0 0 ]
dir = randint 4
timer 0
.
background 242
move 30 70
clear
color 997
text "SNAKE"
textsize 5
move 6 40
text "Keys or mouse for controlling"
move 6 30
text "Space or click to to start"
#
on key
if game = 0 and keybkey = " "
start
return
.
if dir mod 2 = 1
if keybkey = "ArrowRight"
dir = 2
elif keybkey = "ArrowLeft"
dir = 4
.
else
if keybkey = "ArrowUp"
dir = 1
elif keybkey = "ArrowDown"
dir = 3
.
.
.
on mouse_down
if game = 0
start
return
.
if dir mod 2 = 1
if mouse_x < sx
dir = 4
else
dir = 2
.
else
if mouse_y < sy
dir = 3
else
dir = 1
.
.
.
on timer
clear
color 997
move 2 95
text "Score: " & 10 * len sx[] - 50
color 966
move rx ry
circle 1.5
#
sx = sx[1] ; sy = sy[1]
if dir = 1
sy += 5
elif dir = 2
sx += 5
elif dir = 3
sy -= 5
elif dir = 4
sx -= 5
.
if sx < 0 or sx > 100 or sy < 0 or sy > 100
game = 0
.
color 494
for i = len sx[] downto 2
if sx = sx[i] and sy = sy[i]
game = 0
.
sx[i] = sx[i - 1]
sy[i] = sy[i - 1]
if sx[i] > 0
move sx[i] sy[i]
circle 2.5
.
.
move sx sy
circle 2.5
color 000
if dir = 2 or dir = 4
move sx sy + 1
circle 0.5
move sx sy - 1
circle 0.5
else
move sx + 1 sy
circle 0.5
move sx - 1 sy
circle 0.5
.
if sx = rx and sy = ry
len sx[] len sx[] + 3
len sy[] len sy[] + 3
fruit
.
sx[1] = sx ; sy[1] = sy
if game = 1
timer 0.15
else
color 997
move 10 10
text "Space or click new game"
.
.
</syntaxhighlight>
 
=={{header|F Sharp}}==
<syntaxhighlight lang="fsharp">
 
 
open System
open System.Threading.Tasks
open System.Threading
 
module SnakeGame =
 
/// 🚏 Directions on our grid:
type Movement =
| Left of Position
| Right of Position
| Down of Position
| Up of Position
| InvalidMove
 
/// 🐍 Sort of like a list, but not:
and Snake<'Position> =
| Head of Position * Snake<'Position>
| Belly of Position * Snake<'Position>
| Tail
 
/// 🕹️ Our basic runtime information:
and Game =
| GameRunning of Movement * Snake<Position> * Grid * Eaten:int * Food
| GameOver of Grid * Eaten:int
 
/// 🧭 x & y in our plane:
and Position = int * int
 
/// 🍎 The food our snake will eat:
and Food = Position * string
/// 🌐 A simple two dimensional plane:
and Grid = string[][]
 
/// Making a list of positions from a Snake 🐍
let snakeUnzip (snake:Snake<Position>) =
let rec unzip snake carry =
match snake with
| Head (p, rest) -> unzip rest <| carry @ [p]
| Belly (p, rest) -> unzip rest <| carry @ [p]
| Tail -> carry
unzip snake []
/// Making a Snake from a list of positions 🐍
let snakeZip (positions:list<Position>) (upto:int) =
let correctLength = (List.take upto positions)
let rec zip (carry:Snake<Position>) (rest:list<Position>) =
match rest with
| head::[] -> zip (Head(head, carry)) []
| back::front -> zip (Belly (back, carry)) front
| [] -> carry
zip Tail (List.rev correctLength)
 
module Graphics =
let private random = new Random()
let private head = "🤢"
let private belly = "🟢"
let private display = "⬜"
let private errorDisplay = "🟥"
 
let private food = [|"🐁";"🐀";"🐥";"🪺";"🐸";"🐛";"🪰";"🐞";"🦗"|]
let private randomFood () = food.[random.Next(food.Length - 1)]
 
let isFood square = Array.contains square food
let isFreeSpace square = square = display || square = errorDisplay
let isOccupied square =
match square with
| square when isFreeSpace square -> false
| square when isFood square -> false
| _ -> true
 
let makeGrid (dimensionsSquared) : Grid =
let row _ = Array.init dimensionsSquared (fun _ -> display)
Array.init dimensionsSquared row
 
let clearGrid (grid:Grid) : unit =
Array.iteri (fun i row ->
Array.iteri (fun j _ ->
grid.[i].[j] <- display
) row
) grid
 
let render (grid:Grid) : unit =
Console.Clear()
Array.iter (fun (row:string array) ->
let prettyprint = String.concat "" row
printfn $"{prettyprint}") grid
printfn "Snake Game in FSharp by @wiredsister"
printfn "Controls: ⬅️ ↕️ ➡️"
printfn "Press Ctrl+C to Quit Game"
Console.Title <- "FSharp Snake 🐍"
 
let getFreeSpaces (grid:Grid) : list<Position> =
let results : Position list ref = ref []
for i in 0..(grid.Length-1) do
for j in 0..(grid.Length-1) do
if isFreeSpace grid.[i].[j]
then results.Value <- results.Value @ [i,j]
else ()
()
results.Value
 
let getFood (grid:Grid) : Food =
Console.Beep()
let freeSpaces =
getFreeSpaces grid
|> Array.ofList
let food = randomFood ()
let randomPos = freeSpaces.[random.Next(freeSpaces.Length - 1)]
randomPos, food
 
let dropFood (grid:Grid) (food:Food) =
let (x, y), animal = food
grid.[x].[y] <- animal
 
let slither (snake:Snake<Position>) (grid:Grid) : unit =
try
let rec slithering (body:Snake<Position>) =
match body with
| Head(p, s) ->
let row, column = p
grid.[row].[column] <- head
slithering s
| Belly(p, s) ->
let row, column = p
grid.[row].[column] <- belly
slithering s
| Tail -> ()
do slithering snake
with _ -> failwith "ERROR: Could not slither snake!"
let endGame (grid:Grid) : unit =
Console.Clear()
Array.iteri (fun i row ->
Array.iteri (fun j _ ->
grid.[i].[j] <- errorDisplay
) row
) grid
Array.iter (fun (row:string array) ->
let prettyprint = String.concat "" row
printfn $"{prettyprint}") grid
Console.Beep()
 
module GamePlay =
 
let moveUp (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
match snake with
| Head (p, rest:Snake<Position>) ->
let x, y = p
let shiftUp = ((x-1), y)
try
match shiftUp with
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
GameOver (grid, eaten)
| (row, column) when Graphics.isFood grid.[row].[column] ->
let unzipped = snakeUnzip (Head (shiftUp, (Belly (p, rest))))
let newSnake = snakeZip unzipped (eaten+1)
let nextFood = Graphics.getFood grid
GameRunning (Up shiftUp, newSnake, grid, eaten+1, nextFood)
| pivot ->
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
let newSnake = snakeZip unzipped eaten
GameRunning (Up pivot, newSnake, grid, eaten, food)
with _ -> GameOver (grid, eaten)
| _ -> failwith "ERROR: No head!"
 
let moveDown (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
match snake with
| Head (p, rest:Snake<Position>) ->
let x, y = p
let shiftDown = ((x+1), y)
try
match shiftDown with
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
GameOver (grid, eaten)
| (row, column) when Graphics.isFood grid.[row].[column] ->
let unzipped = snakeUnzip (Head (shiftDown, (Belly (p, rest))))
let newSnake = snakeZip unzipped (eaten+1)
let nextFood = Graphics.getFood grid
GameRunning (Down shiftDown, newSnake, grid, (eaten+1), nextFood)
| pivot ->
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
let newSnake = snakeZip unzipped eaten
GameRunning (Down pivot, newSnake, grid, eaten, food)
with _ -> GameOver (grid, eaten)
| _ -> failwith "ERROR: No head!"
 
let moveLeft (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
match snake with
| Head (p, rest:Snake<Position>) ->
let x, y = p
let shiftLeft = (x, (y-1))
try
match shiftLeft with
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
GameOver (grid, eaten)
| (row, column) when Graphics.isFood grid.[row].[column] ->
let unzipped = snakeUnzip (Head (shiftLeft, (Belly (p, rest))))
let newSnake = snakeZip unzipped (eaten+1)
let nextFood = Graphics.getFood grid
GameRunning (Left shiftLeft, newSnake, grid, eaten+1, nextFood)
| pivot ->
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
let newSnake = snakeZip unzipped eaten
GameRunning (Left pivot, newSnake, grid, eaten, food)
with _ -> GameOver (grid, eaten)
| _ -> failwith "ERROR: No head!"
 
let moveRight (snake:Snake<Position>) (grid:Grid) (eaten:int) (food:Food) : Game =
match snake with
| Head (p, rest:Snake<Position>) ->
let (x: int), y = p
let shiftRight = (x, (y+1))
try
match shiftRight with
| (row,column) when Graphics.isOccupied grid.[row].[column] ->
GameOver (grid, eaten)
| (row, column) when Graphics.isFood grid.[row].[column] ->
let unzipped = snakeUnzip (Head (shiftRight, (Belly (p, rest))))
let newSnake = snakeZip unzipped (eaten+1)
let nextFood = Graphics.getFood grid
GameRunning (Right shiftRight, newSnake, grid, eaten+1, nextFood)
| pivot ->
let unzipped = snakeUnzip (Head (pivot, (Belly (p, rest))))
let newSnake = snakeZip unzipped eaten
GameRunning (Right pivot, newSnake, grid, eaten, food)
with _ -> GameOver (grid, eaten)
| _ -> failwith "ERROR: No head!"
 
open SnakeGame
 
[<EntryPoint>]
let main _ =
 
/// A gentle slope function for making the snake go faster:
let tick (eaten:int) = 100./log10(float eaten) |> int
 
let getNextMove prev snake grid eaten food : Task<Game> =
task {
do! Task.Delay(tick(eaten))
if not Console.KeyAvailable
then
match prev with
| Up _ -> return GamePlay.moveUp snake grid eaten food
| Down _ -> return GamePlay.moveDown snake grid eaten food
| Right _ -> return GamePlay.moveRight snake grid eaten food
| Left _ -> return GamePlay.moveLeft snake grid eaten food
| InvalidMove -> return GameOver (grid, eaten)
else
match Console.ReadKey() with
| keystroke when keystroke.Key.Equals(ConsoleKey.UpArrow) ->
return GamePlay.moveUp snake grid eaten food
| keystroke when keystroke.Key.Equals(ConsoleKey.DownArrow) ->
return GamePlay.moveDown snake grid eaten food
| keystroke when keystroke.Key.Equals(ConsoleKey.RightArrow) ->
return GamePlay.moveRight snake grid eaten food
| keystroke when keystroke.Key.Equals(ConsoleKey.LeftArrow) ->
return GamePlay.moveLeft snake grid eaten food
| _ ->
match prev with
| Up _ -> return GamePlay.moveUp snake grid eaten food
| Down _ -> return GamePlay.moveDown snake grid eaten food
| Right _ -> return GamePlay.moveRight snake grid eaten food
| Left _ -> return GamePlay.moveLeft snake grid eaten food
| InvalidMove -> return GameOver (grid, eaten)
}
 
let gridDimension = 20
let segments = [(0,3); (0,2); (0,1); (0,0)]
let youngSnake : Snake<Position> = snakeZip segments segments.Length
let startingGrid = Graphics.makeGrid gridDimension
let startingFood = Graphics.getFood startingGrid
let start = GamePlay.moveRight youngSnake startingGrid segments.Length startingFood
let rec gameLoop (game:Game) =
match game with
| GameRunning (prev, snake, grid, eaten, food) ->
do Graphics.clearGrid grid
do Graphics.dropFood grid food
do Graphics.slither snake grid
do Graphics.render grid
let eitherPlayerOrCursor = getNextMove prev snake grid eaten food
do eitherPlayerOrCursor.Wait()
gameLoop eitherPlayerOrCursor.Result
| GameOver (grid,eaten) ->
do Graphics.endGame grid
printfn $"Game Over! Snake ate {eaten-segments.Length} critters!"
do Thread.Sleep(1000)
let rec wantToPlayAgain () =
match Console.ReadKey() with
| keystroke when keystroke.Key.Equals(ConsoleKey.Y) -> gameLoop start
| keystroke when keystroke.Key.Equals(ConsoleKey.N) -> ()
| _ -> wantToPlayAgain ()
printfn $"Restart? Type Y to continue..."
wantToPlayAgain()
 
do gameLoop start
0
</syntaxhighlight>
 
=={{header|Go}}==
Line 1,746 ⟶ 2,732:
FreeBSD, OpenBSD, NetBSD, DragonFly BSD, Linux, MS Windows, and MacOS
(tested on FreeBSD and MS Windows).
<langsyntaxhighlight Golang="go">package main
 
import (
Line 1,980 ⟶ 2,966:
snakeHead = termbox.Cell{Ch: 'O', Bg: bg, Fg: termbox.ColorYellow | termbox.AttrBold}
food = termbox.Cell{Ch: '@', Bg: bg, Fg: termbox.ColorRed}
)</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Random (getRandomRs)
import Graphics.Gloss.Interface.Pure.Game
Line 2,082 ⟶ 3,068:
main = do world <- createWorld
play inW white 7 world renderWorld handleEvents updateWorld
where inW = InWindow "The Snake" (400, 400) (10, 10)</langsyntaxhighlight>
 
'''Extra credit'''
Line 2,088 ⟶ 3,074:
It is easy to make snake to seek food automatically. Just change the first line of the <code>updateWorld</code> definition:
 
<langsyntaxhighlight lang="haskell">updateWorld _ = id >>> snakeSeeksFood >>> (snakeEats <|> snakeMoves) </langsyntaxhighlight>
 
and add local definition:
 
<langsyntaxhighlight lang="haskell"> snakeSeeksFood w = w & snake .& turns optimalDirection
where
optimalDirection = minimumBy (comparing distanceToFood) safeTurns
Line 2,104 ⟶ 3,090:
distanceToFood d = let (a,b) = w^.snake & turns d & moves & (^.body) & head
(x,y) = w^.food & head
in (a-x)^2 + (b-y)^2</langsyntaxhighlight>
 
=={{header|J}}==
Line 2,110 ⟶ 3,096:
Needs j9 qt:
 
Use WASD to move. ReliesUse on<code>start''</code> keyboardto repeat for traversing the boardstart.
 
Difficulty may be adjusted by providing a non-default argument to start (time in milliseconds between animation updates). For example, <code>start 200</code> for an easier game.
<lang J>require'ide/qt/gl2'
 
In this implementation, speed is fixed (and final score is by the update rate). Another approach might be to start slow and gradually speed based on the length of the snake. Those sorts of changes are left as an exercise for the reader.
 
<syntaxhighlight lang="j">require'ide/qt/gl2'
coinsert 'jgl2'
 
Line 2,122 ⟶ 3,112:
}}
 
snakestart=: {{
speed=: {.y,200
open''
snake=: 10 10,10 11,:10 12
Line 2,143 ⟶ 3,134:
 
move=: {{
s_timer=: move@y
wd 'ptimer ',":speed
head=. y+{.snake
tail=. }: snake
if. head e. snake do. head gameover'' return. end.
if. _1 e. head do. (0>.head) gameover'' return. end.
Line 2,152 ⟶ 3,144:
newdot''
else.
snake=: head,tail}: snake
end.
draw''
Line 2,170 ⟶ 3,162:
 
gameover=: {{
wd 'ptimer 0'
if. 1<#snake do.
echo 'game over'
echo 'score: ',":(#snake)*1000%speed
draw''
glbrush glrgb 255 255 0
Line 2,177 ⟶ 3,171:
end.
snake=: ,:_ _
}}</langsyntaxhighlight>
 
=={{header|Java}}==
Line 2,185 ⟶ 3,179:
=={{header|JavaScript}}==
You need the P5 Library to run this code!
<langsyntaxhighlight lang="javascript">
const L = 1, R = 2, D = 4, U = 8;
var block = 24, wid = 30, hei = 20, frameR = 7, fruit, snake;
Line 2,293 ⟶ 3,287:
if( !snake.alive ) text( "THE END", 630, 250 );
}
</syntaxhighlight>
</lang>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">using GLMakie, GeometryBasics
Makie version in 99 lines.
<lang julia>using Makie
 
mutable struct SnakeGame
height::Int
width::Int
snake::Vector{CartesianIndex{2}}
food::CartesianIndex{2}
end
 
Line 2,342 ⟶ 3,335:
 
function play(;n=10,t=0.5)
game = NodeObservable(SnakeGame(;width=n,height=n))
scene = Scene(resolution = (1000, 1000), raw = true, camera = campixel!)
display(scene)
Line 2,363 ⟶ 3,356:
 
score_text = @lift("Score: $(length($game.snake)-1)")
text!(scene, score_text, color=:gray, position = @lift((widths($area)[1]/2, widths($area)[2])), textsizefontsize = 50, align = (:center, :top))
 
direction = Ref{Any}(nothing)
 
on(events(scene).events.keyboardbuttonskeyboardbutton) do but
if ispressed(but,.action == Keyboard.press || but.action == Keyboard.left)repeat
direction[]if but.key == CartesianIndex(-1,0)Keyboard.left
direction[] = CartesianIndex(-1,0)
elseif ispressed(but, Keyboard.up)
direction[]elseif but.key == CartesianIndex(0,1)Keyboard.up
direction[] = CartesianIndex(0,1)
elseif ispressed(but, Keyboard.down)
direction[]elseif but.key == CartesianIndex(0,-1)Keyboard.down
direction[] = CartesianIndex(0,-1)
elseif ispressed(but, Keyboard.right)
direction[]elseif but.key == CartesianIndex(1,0)Keyboard.right
direction[] = CartesianIndex(1,0)
end
end
end
Line 2,397 ⟶ 3,392:
 
play()
</syntaxhighlight>
</lang>
 
=={{header|Kotlin}}==
{{trans|C++}}
{{works with|Windows 10}}
<langsyntaxhighlight lang="scala">// Kotlin Native v0.5
 
import kotlinx.cinterop.*
Line 2,583 ⟶ 3,578:
srand(time(null).toInt())
Snake().play()
}</langsyntaxhighlight>
 
{{output}}
Line 2,593 ⟶ 3,588:
[[File:snake-lua.png]]
{{works with|LÖVE}}
<langsyntaxhighlight Lualang="lua">UP, RIGHT, DOWN, LEFT = 1, 2, 3, 4
UpdateTime=0.200
Timer = 0
Line 2,760 ⟶ 3,755:
Head.nextDirection = iDirection
end
end</langsyntaxhighlight>
 
=={{header|Nim}}==
Line 2,766 ⟶ 3,761:
{{libheader|nim-ncurses}}
As in the C version, the code is provided for Linux. We use the tiny API defined in the C version, only adjusted to work with Nim and the library “nim-ncurses”.
<langsyntaxhighlight Nimlang="nim">import macros, os, random
import ncurses
 
Line 2,875 ⟶ 3,870:
 
sleep(1000)
closeScreen()</langsyntaxhighlight>
 
=={{header|OCaml}}==
Line 2,881 ⟶ 3,876:
{{libheader|OCamlSDL2}}
 
<langsyntaxhighlight lang="ocaml">(* A simple Snake Game *)
open Sdl
 
Line 3,034 ⟶ 4,029:
main_loop state
in
main_loop initial_state</langsyntaxhighlight>
 
=={{header|Perl}}==
[[File:Snake_game_perl.png|200px|thumb|right]]
<langsyntaxhighlight lang="perl">use utf8;
use Time::HiRes qw(sleep);
use Term::ANSIColor qw(colored);
Line 3,208 ⟶ 4,203:
elsif ($key eq "\e[C" and $dir ne LEFT ) { $dir = RIGHT }
elsif ($key eq "\e[D" and $dir ne RIGHT) { $dir = LEFT }
}</langsyntaxhighlight>
 
=={{header|Phix}}==
{{trans|C++}}
<langsyntaxhighlight Phixlang="phix">constant W = 60, H = 30, MAX_LEN = 600
enum NORTH, EAST, SOUTH, WEST
 
Line 3,292 ⟶ 4,287:
end while
end procedure
play()</langsyntaxhighlight>
 
=={{header|Python}}==
Using Pygame. Works with Python >= 3.7.
<langsyntaxhighlight lang="python">from __future__ import annotations
 
import itertools
Line 3,557 ⟶ 4,552:
score = game.main()
print(score)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
Line 3,564 ⟶ 4,559:
This is a variation of a demo script included in the examples folder for the Raku [https://modules.raku.org/search/?q=SDL2%3A%3ARaw SDL2::Raw library bindings].
 
<syntaxhighlight lang="raku" perl6line>use SDL2::Raw;
use Cairo;
 
Line 3,738 ⟶ 4,733:
}
 
SDL_Quit();</langsyntaxhighlight>
 
=={{header|Rust}}==
Implemented smooth (per-pixel) animation on Win32 API (tested on Windows 7 and Windows 11)
<syntaxhighlight lang="rust">/* add to file Cargo.toml:
 
Used winsafe - a safe rust bindings library for Win32 GUI: young but very handy, with links to docs.microsoft.com from doc and src for all Win32 entities involved.
 
Along the way, the possibility of restarting while maintaining the length of the snake has been implemented. Now a long snake is available to everyone!
 
[http://github.com/rust-rosetta/rust-rosetta/blob/master/tasks/snake/SnkRust.png snake game screenshot]
<lang fsharp>/* add to file Cargo.toml:
[dependencies]
winsafe = "0.0.8" # IMHO: before the appearance of winsafe="0.1" it is not worth raising the version here
winsafe = "0.0.8"
rand = "0.8.4"
derive-new = "0.5"
*/
 
#![windows_subsystem = "windows"]
 
use randderive_new::Rngnew;
use rand::{thread_rng, Rng};
use std::{cell::RefCell, rc::Rc};
use winsafe::{co, gui, prelude::*, COLORREF, HBRUSH, HPEN, RECT, SIZE};
 
const STEP: i32 = 3; // px, motion per frame. STEP and FPS determine the smoothness and speed of the animation.
const FPSGCW: u32i32 = 907; // game grid cell width in STEPs
const CELL: i32 = 21; // px, game grid (logical step). Will be aligned by STEP
const FIELD_W: i32 = 20; // width of the square field in CELLs
const SNAKE_W: i32 = 20; // px
const FW: i32 = 20; // the width of the square field in the cells of the game grid
const ROUNDING: SIZE = SIZE::new(SNAKE_W / 2, SNAKE_W / 2);
const TW: i32 = (FW + 2) * GCW; // total field width (with overlap for collisions) in STEPs
 
const RATIOID0: i32 = CELLFW / STEP2 * GCW; // starting position id
const START_CELL: i32 = FIELD_W / 2 * RATIO;
/// total field width (with overlap for collisions) in STEPs
const TW: i32 = (FIELD_W + 2) * RATIO;
#[derive(Clone, Copy)]
#[repr(i32)]
enum Direction {
Start = 0,
A = -1,
D = 1,
W = -TW,
S = TW,
}
use Direction::*;
 
#[rustfmt::skip]
#[derive(new)]
struct Context {
wnd: gui::WindowMain,
#[new(default) ] snake: Vec<i32>, // [ids_rectrect_ids] where id_rectrect_id = y * TW + x (where x, y: nSTEPs)
id_r#[new(value = "[ID0; 6]")] r: [i32; 6], // ID 6 rectanglesrect to color in next frame (bg, tail, turn, body, food, head)
gap:#[new(default) i32, ] incr: i32, // gap0 in| STEPs-1 between| animation1 and| logic-TW cell| (negativeTW - removeincrement tail)r[head] in next STEP
#[new(value = "TW") ] next_incr: i32, // `incr` in the next grid cell
dir: Direction,
#[new(default) ] gap: i32, // interval in STEPs to the next grid cell; negative - tail clipping mark
ordered_dir: Direction,
}
impl Context {
fn new(wnd: gui::WindowMain, len: usize) -> Self {
Self {
wnd,
snake: vec![START_CELL; len.saturating_sub(RATIO as usize)],
id_r: [START_CELL; 6],
gap: 0,
dir: Start,
ordered_dir: S,
}
}
}
 
pub fn main() {
let [bg, tail, turn, body, food, head] = [0usize0_usize, 1, 2, 3, 4, 5];
let grid: Vec<_> = (1..=FW).flat_map(|y| (1..=FW).map(move |x| (y * TW + x) * GCW)).collect();
let mut colors = [(0x00, 0xF0, 0xA0); 6]; // color tail, turn, body
colors[bg] = (0x00, 0x50, 0x90);
Line 3,813 ⟶ 4,780:
let wnd = gui::WindowMain::new(gui::WindowMainOpts {
title: "Snake - Start: Space, then press W-A-S-D".to_string(),
size: winsafe::SIZE::new(FIELD_WFW * RATIOGCW * STEP, FIELD_WFW * RATIOGCW * STEP),
ex_style: co::WS_EX::CLIENTEDGE,
class_bg_brush: brushes[bg],
..Default::default()
});
// WindowMain is based on Arc, so wnd.clone() is a shallow copy of a reference.
let context = Rc::new(RefCell::new(Context::new(wnd.clone())));
 
wnd.on().wm_paint({
let context = Rc::new(RefCell::new(Context::new(wnd.clone(), 0)));
 
wnd.on().wm_key_down({
let context = Rc::clone(&context);
move |k| {
let mut ctx = context.borrow_mutborrow();
matchlet (ctx.dir,mut k.char_codeps as= u8winsafe::PAINTSTRUCT::default() {;
let hdc = ctx.wnd.hwnd(Start, bt @ ).BeginPaint(b'&mut ' | 113ps)) => {?;
hdc.SelectObjectPen(HPEN::CreatePen(co::PS::NULL, 0, COLORREF::new(0, 0, 0))?)?;
let len = ctx.snake.len(); // 113 == F2 key
for (&id, &brush) in *ctx = Context::new(ctx.wndr.cloneiter(), if bt =.zip(&brushes[bg..= b' 'head]) { len } else { 0 });
let [left, top] = ctx.wnd.hwnd().InvalidateRect(None[id % TW, true)?;id // call TW].wm_paintmap(|i| i * STEP - (STEP * GCW + SNAKE_W) with/ erase2);
let rect = RECT ctx.wnd.hwnd().SetTimer(1{ left, 1000top, /right: FPSleft + SNAKE_W, None)?bottom: top + SNAKE_W };
}hdc.SelectObjectBrush(brush)?;
hdc.RoundRect(rect, SIZE::new(SNAKE_W / 2, SNAKE_W / 2))?;
(W | S, bt @ (b'A' | b'D')) => ctx.ordered_dir = if bt == b'A' { A } else { D },
(A | D, bt @ (b'S' | b'W')) => ctx.ordered_dir = if bt == b'S' { S } else { W },
_ => (),
}
Ok(ctx.wnd.hwnd().EndPaint(&ps))
}
});
 
wnd.on().wm_timerwm_key_down(1, {
let context = Rc::clone(&context);
letmove cells:|key| Vec<i32> = (1..=FIELD_W){
.flat_map(|y| (1..=FIELD_W).map(move |x| (y * TW + x) * RATIO))
.collect();
move || {
let mut ctx = context.borrow_mut();
let new_h =Ok(match (ctx.id_r[head]incr.abs(), + ctxkey.dirchar_code as i32;u8) {
ctx.id_r[body] (0, b' ') => _ = ctx.id_r[head];wnd.hwnd().SetTimer(1, 10, None)?, // Start / Restart
(TW, bt @ (b'A' | b'D')) => ctx.id_r[head]next_incr = new_h;if bt == b'A' { -1 } else { 1 },
if (1, bt @ (b'S' | b'W')) => ctx.gapnext_incr <= 0if bt == b'S' { TW } else { -TW },
ctx.id_r[bg]_ => ctx.snake.remove(0);,
ctx.id_r[tail] = ctx.snake[0];})
ctx.id_r[turn] = ctx.snake[RATIO as usize / 2];
}
ctx.gap -= ctx.gap.signum();
if ctx.gap == 0 {
ctx.dir = ctx.ordered_dir;
let hw = ctx.wnd.hwnd();
let eat = new_h == ctx.id_r[food];
if !eat && (cells.binary_search(&new_h).is_err() || ctx.snake.contains(&&new_h)) {
hw.KillTimer(1)?;
hw.SetWindowText(&(hw.GetWindowText()? + " Restart: F2 (with save - Space)"))?;
ctx.dir = Start;
return Ok(());
} else if eat || ctx.id_r[food] == 0 && ctx.id_r[tail] != START_CELL {
let mut snk_cells: Vec<_> = ctx.snake.iter().step_by(RATIO as usize).collect();
if eat && snk_cells.len() == cells.len() - 2 {
hw.SetWindowText(&format!("Snake - EATEN ALL: {} !!!", snk_cells.len()))?
} else if eat {
hw.SetWindowText(&format!("Snake - Eaten: {}.", snk_cells.len()))?
}
if ctx.id_r[tail] == START_CELL || eat && snk_cells.len() == cells.len() - 2 {
ctx.id_r[food] = 0; // hide food if not all of the saved snake has come out or everything is eaten
} else if snk_cells.len() + 1 < cells.len() {
snk_cells.sort();
ctx.id_r[food] = *(cells.iter())
.filter(|i| **i != new_h && snk_cells.binary_search(i).is_err())
.nth(rand::thread_rng().gen_range(0..cells.len() - snk_cells.len() - 1))
.unwrap();
}
}
ctx.gap = if eat { RATIO } else { -RATIO }
}
ctx.snake.push(new_h);
ctx.wnd.hwnd().InvalidateRect(None, false)?; // call .wm_paint() without erase
Ok(())
}
});
 
wnd.on().wm_paintwm_timer(1, move || {
let mut ctx = context.borrowborrow_mut();
let mut psnew_h = winsafe::PAINTSTRUCT::default()ctx.r[head] + ctx.incr;
let(ctx.r[body], hdcctx.r[head]) = (ctx.wnd.hwnd().BeginPaint(&mutr[head], psnew_h)?;
if ctx.gap < 0 {
hdc.SelectObjectPen(HPEN::CreatePen(co::PS::NULL, 0, COLORREF::new(0, 0, 0))?)?;
for (&id_rect, &brush) in ctx.id_rr[bg] = ctx.iter()snake.zipremove(&brushes0) {;
hdcctx.SelectObjectBrush(brush)?r[tail] = ctx.snake[0];
let leftctx.r[turn] = id_rect % TW * STEP - (STEP * RATIOctx.snake[GCW +as SNAKE_W)usize / 2];
let top = id_rect / TW * STEP - (STEP * RATIO + SNAKE_W) / 2;
hdc.RoundRect(
winsafe::RECT {
left,
top,
right: left + SNAKE_W,
bottom: top + SNAKE_W,
},
ROUNDING,
)?;
}
ctx.wndgap -= ctx.hwnd()gap.EndPaintsignum(&ps);
if ctx.gap == 0 {
ctx.gap = if new_h == ctx.r[food] { GCW } else { -GCW };
let mut snake_cells: Vec<_> = ctx.snake.iter().step_by(GCW as usize).collect();
if new_h == ctx.r[food] {
ctx.wnd.hwnd().SetWindowText(&format!("Snake - Eaten: {}", snake_cells.len()))?;
snake_cells.sort();
ctx.r[food] = *(grid.iter())
.filter(|i| **i != new_h && snake_cells.binary_search(i).is_err())
.nth(thread_rng().gen_range(0..(grid.len() - 1 - snake_cells.len()).max(1)))
.unwrap_or(&0);
} else if grid.binary_search(&new_h).is_err() || snake_cells.contains(&&new_h) {
ctx.wnd.hwnd().KillTimer(1)?; // Stop
let title = ctx.wnd.hwnd().GetWindowText()?;
ctx.wnd.hwnd().SetWindowText(&(title + ". Restart: Space"))?;
*ctx = Context::new(ctx.wnd.clone());
return Ok(());
}
ctx.incr = ctx.next_incr;
}
ctx.snake.push(new_h);
ctx.wnd.hwnd().InvalidateRect(None, new_h == ID0)?; // call .wm_paint(), with erase on Restart
Ok(())
});
 
if let Err(e) = wnd.run_main(None) {.unwrap();
}</syntaxhighlight>
winsafe::HWND::NULL
{{out}}
.MessageBox(&e.to_string(), "Uncaught error", co::MB::ICONERROR)
[[File:Snake rust.png]]
.unwrap();
}
}</lang>
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">class SnakeGame(w, h) {
const readkey = frequire('Term::ReadKey')
const ansi = frequire('Term::ANSIColor')
Line 4,057 ⟶ 4,993:
var h = `tput lines`.to_i
 
SnakeGame(w || 80, h || 24).play</langsyntaxhighlight>
 
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell}}
{{works with|Z Shell}}
 
Play ASCII snake in your ANSI terminal.
 
It theoretically should also work with the Korn Shell, but for some reason the timeout on the key read is not consistent and the snake stops moving except one step after each keypress.
 
<syntaxhighlight lang="bash">function main {
typeset -i game_over=0
typeset -i height=$(tput lines) width=$(tput cols)
 
# start out in the middle moving to the right
typeset -i dx dy hx=$(( width/2 )) hy=$(( height/2 ))
typeset -a sx=($hx) sy=($hy)
typeset -a timeout
clear
tput cup "$sy" "$sx" && printf '@'
tput cup $(( height/2+2 )) 0
center $width "Press h, j, k, l to move left, down, up, right"
 
# place first food
typeset -i fx=hx fy=hy
while (( fx == hx && fy == hy )); do
fx=$(( RANDOM % (width-2)+1 )) fy=$(( RANDOM % (height-2)+1 ))
done
tput cup "$fy" "$fx" && printf '*'
 
# handle variations between shells
keypress=(-N 1) origin=0
if [[ -n $ZSH_VERSION ]]; then
keypress=(-k)
origin=1
fi
 
stty -echo
tput civis
typeset key
read "${keypress[@]}" -s key
typeset -i start_time=$(date +%s)
tput cup "$(( height/2+2 ))" 0 && tput el
while (( ! game_over )); do
timeout=(-t $(printf '0.%04d' $(( 2000 / (${#sx[@]}+1) )) ) )
if [[ -z $key ]]; then
read "${timeout[@]}" "${keypress[@]}" -s key
fi
 
case "$key" in
h) if (( dx != 1 )); then dx=-1; dy=0; fi;;
j) if (( dy != -1 )); then dy=1; dx=0; fi;;
k) if (( dy != 1 )); then dy=-1; dx=0; fi;;
l) if (( dx != -1 )); then dx=1; dy=0; fi;;
q) game_over=1; tput cup 0 0 && print "Final food was at ($fx,$fy)";;
esac
key=
(( hx += dx, hy += dy ))
# if we try to go off screen, game over
if (( hx < 0 || hx >= width || hy < 0 || hy >= height )); then
game_over=1
else
# if we run into ourself, game over
for (( i=0; i<${#sx[@]}; ++i )); do
if (( hx==sx[i+origin] && hy==sy[i+origin] )); then
game_over=1
break
fi
done
fi
if (( game_over )); then
break
fi
# add new spot
sx+=($hx) sy+=($hy)
 
if (( hx == fx && hy == fy )); then
# if we just ate some food, place some new food out
ok=0
while (( ! ok )); do
# make sure we don't put it under ourselves
ok=1
fx=$(( RANDOM % (width-2)+1 )) fy=$(( RANDOM % (height-2)+1 ))
for (( i=0; i<${#sx[@]}; ++i )); do
if (( fx == sx[i+origin] && fy == sy[i+origin] )); then
ok=0
break
fi
done
done
tput cup "$fy" "$fx" && printf '*'
# and don't remove our tail because we've just grown by 1
else
# if we didn't just eat food, remove our tail from its previous spot
tput cup ${sy[origin]} ${sx[origin]} && printf ' '
sx=( ${sx[@]:1} )
sy=( ${sy[@]:1} )
fi
# draw our new head
tput cup "$hy" "$hx" && printf '@'
done
typeset -i end_time=$(date +%s)
tput cup $(( height / 2 -1 )) 0 && center $width 'GAME OVER'
tput cup $(( height / 2 )) 0 &&
center $width 'Time: %d seconds' $(( end_time - start_time ))
tput cup $(( height / 2 + 1 )) 0 &&
center $width 'Final length: %d' ${#sx[@]}
echo
stty echo
tput cnorm
}
 
function center {
typeset -i width=$1 i
shift
typeset message=$(printf "$@")
tput cuf $(( (width-${#message}) / 2 ))
printf '%s' "$message"
}
 
main "$@"</syntaxhighlight>
 
=={{header|Wren}}==
Line 4,064 ⟶ 5,120:
{{libheader|Wren-dynamic}}
An embedded program so we can ask the C host to call ncurses and another library function for us.
<langsyntaxhighlight ecmascriptlang="wren">/* snakeSnake.wren */
 
import "random" for Random
Line 4,199 ⟶ 5,255:
}
C.usleep(999 * 1000)
Ncurses.endwin()</langsyntaxhighlight>
<br>
Now embed this script in the following C program, compile and run it.
<langsyntaxhighlight lang="c">/* gcc snakeSnake.c -o snakeSnake -lncurses -lwren -lm */
 
#include <stdio.h>
Line 4,348 ⟶ 5,404:
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "snakeSnake.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
Line 4,364 ⟶ 5,420:
free(script);
return 0;
}</langsyntaxhighlight>
 
=={{header|XPL0}}==
Line 4,378 ⟶ 5,434:
speed is currently set at nine steps per second.
 
<langsyntaxhighlight XPL0lang="xpl0">def Width=40, Height=25-1, \playing area including border
StartLength = 10, \starting length of snake including head
Morsels = 10; \number of food items constantly offered
Line 4,486 ⟶ 5,542:
Sound(0, 36, 1); \pause 2 seconds to see result
OpenI(1); \flush any pending keystrokes
]</langsyntaxhighlight>
1,969

edits