# Recreate the classic snake Game

The challenge is to create the classic Snake game using as few bytes as possible.

Here are the requirements:

• The game must be implemented in a typical 2-dimensional layout. The snake should be able to grow significantly within the bounds of the map (this really means, don't make your map too small, use your discretion here).
• A user may move the snake using keys of your choosing, however, the snake cannot double back on itself (e.g. if it is going West it cannot go East without first going North or South). A snake ought to be able to travel in all 4 directions: up, down, left, right (North, South, West, East).
• Snake starts off as length 1, each time it eats a "food" object it grows +1 in length
• Food objects are randomly placed in locations other than those occupied by the snake
• If the Snake hits itself or a wall the game is ended
• When the game has been ended the literal "Score: [score]" is displayed where [score] is the number of food items eaten during the game. So, for example, if the snake has eaten 4 "foods" (and therefore has a length of 5) when the game ends, "Score: 4" will be printed.
• No compression algorithms unless they are explicitly defined in your code.

Here's my solution, 908 Bytes, Python 2.7

import random as r
import curses as c
def g(s,w,l):
while 1:
p=[r.randrange(0,w),r.randrange(0,l)]
for l in s:
if l==p:continue
return p
s=[]
d=[0,1]
p=k=n=0
e=100
v={65:[-1,0],66:[1,0],68:[0,-1],67:[0,1]}
z=c.initscr()
w,l=z.getmaxyx()[0],z.getmaxyx()[1]
c.noecho()
z.clear()
x=g(s,w,l)
s.append([w/2,l/2])
z.nodelay(1)
q=lambda h,i:range(h,len(i))
while k!=101:
k=z.getch()
if k in v and not (d[0]==(v[k][0]*-1) and d[1]==(v[k][1]*-1)):d=v[k]
f=[0,0]
for i in q(0,s):
if i == 0:
f=[s[i][0],s[i][1]]
s[i][0]+=d[0]
s[i][1]+=d[1]
else:s[i],f=f,s[i]
if s[0]==x:
n+=1
s.append(f)
x=g(s,w,l)
z.clear()
if s[0][0]>=w or s[0][1]>=l or s[0][0]<0 or s[0][1]<0:break
for i in q(1,s):
if s[0] == s[i]: k = 101
z.move(0,0)
z.refresh()
if d[1]!=0:c.napms(e/2)
else:c.napms(e)
c.endwin()
print 'Score: %s'%n

• possible duplicate of Recreate a 'Snake' game in a console/terminal
– copy
Sep 8 '12 at 18:23
• @copy some people don't like to be restricted to terminals. Sep 8 '12 at 18:29
• does the 'snake cannot double back' rule apply if the snake is length=1? Sep 10 '12 at 4:55
• @chron, yes it does. At all times, snakes may only (truly) turn two ways, left and right. Sep 10 '12 at 11:09

## Ruby 1.9 + SDL (341324 316)

Here's a first attempt at a Ruby version using the SDL library. I can save 6 characters if I'm allowed to load the SDL library using -rsdl on the command line instead of the require statement.

require'sdl'
f=o=d=3
s=SDL::Screen.open l=32,l,0,0
r=*0..l*l
loop{f==o ?f=(r-$*).sample:$*.shift
/yU/=~"#{e=SDL::Event.poll}"&&(v=e.sym%4)&&d+v!=3&&d=v
$><<"Score #{$*.size}"&&exit if$*.index(n=o+[-1,-l,l,1][d])||n<0||n>=l*l||d%3<1&&n/l!=o/l$*<<o=n
r.map{|i|s[i%l,i/l]=[[f,*$*].index(i)?0:255]*3} s.flip sleep 0.1}  The snake segments and food pieces are represented using black pixels, the grid size is currently 32*32. You can control with the arrow keys (or any keys really, the keycode mod 4 indexes the direction array [LEFT, UP, DOWN, RIGHT]). I think there's definitely room for improvement here, especially in the death-checking IF statement. I've vastly improved this over the previous version, hopefully it more closely matches the spirit of the question now. There's one thing I need to fix to comply with the spec, which is that food can currently spawn inside the tail. Fixed! Prints the score to stdout after the game is completed. # Bash: 537533 507 characters C=$COLUMNS;L=$LINES;D=-1;c=9;r=9;z=(9\ 9);l=;h=1;v=;s=1;d=1 t(){ echo -en "\e[$2;$1H$3";}
b(){ ((f=RANDOM%C+1));((g=RANDOM%L+1));for i in "${z[@]}";do [[$f\ $g =$i ]]&&b;done;t $f$g F;}
echo $'\e[2J';b while :;do read -sn1 -t.1 k case$k in
w|s)((h))&&h=&&v=${D:$k};;
a|d)((v))&&v=&&h=${D:$k};;
esac
((c+=h));((r+=v))
((c==f&&r==g&&++l))&&b
((c<1||r<1||c>C||r>L))&&break
for i in "${z[@]}";do [[$c\ $r =$i ]]&&break 2;done
t ${z[-1]} \ ;t$c $r X z=($c\ $r "${z[@]::l}")
done
echo $'\e[2J\e[H'Score:$l


As it uses the $COLUMNS and $LINES shell variables, it must be run sourced: . snake.sh. The snake can be controlled with the w/a/s/d keys.

I know, it can be easily reduced to 493 characters by using clear to clear the screen, but I prefer to keep it pure bash, without using any external tool.

• Very cool solution! Sep 11 '12 at 18:03
• I love bash solutions! Dec 13 '20 at 10:22

# APL (dzaima/APL), 244 233 bytes

s←2⌿⊂2⌿25
d←?x←2⌿50
o←⍳2
G←P5.G
P5.draw←{G.bg¯1
G.fill←0
s⊢←(1↓s),⊂o+f←⊃⌽s
((⊢≢∪)s)∨~f⊂⍛∊a←⍳x:P5.exit 0⊣⍞←'Score: ',⍕2-⍨≢s
d≡f:s⊢←s,⊂f+2×o⊣d⊢←?x
(t←'center'G.rect,∘2 2)¨2×s
G.fill←'f00'
t+⍨d}
P5.kp←{o≢-n←('sdwa'⍳⍵)⊃1-↓⍬2⍴3⊤2320:o⊢←n}


Golfed from 294 → 244 bytes with the help of dzaima.

Uses WASD controls.

Uses ⎕IO←0 (0-indexing).

The grid is 50x50, on the default 100x100 canvas Processing uses.

Displays score to the console.

Explanation done!

## Explanation

s←2⌿⊂2⌿25 snake starts at $$\(25,25)\$$

d←?x←2⌿50 first food position: 2 random ints in (0,50)

x←2⌿50 save (50,50) in x

o←⍳2 initial snake direction: (0,1)

G←P5.G save namespace as G

P5.draw←{ execute the following each frame:

 G.bg¯1 display white background

 G.fill←0 set fill to black

 s⊢←(1↓s),⊂o+f←⊃⌽s calculate next snake position:

 (1↓s) remove the last tail segment

 ,⊂o+f←⊃⌽s add direction to the front, and append that

 f←⊃⌽s assign head coordinates to f

 ((⊢≢∪)s)∨~f⊂⍛∊a←⍳x:(...) check if the player has lost:

 ((⊢≢∪)s)∨ if snake does not match itself uniquified, or

 ~f⊂⍛∊a←⍳x: head is not within 50x50 grid:

 ⍞←'Score: ',⍕2-⍨≢s display the score in console, and

 P5.exit 0⊣ exit, displaying nothing

 d≡f:s⊢←s,⊂f+2×o⊣d⊢←?x if head matches food, then change food position and increase snake length.

 (t←'center'G.rect,∘2 2)¨2×s draw each position of the snake

 t←'center'G.rect,∘2 2 create function t for drawing the blocks

 G.fill←'f00' set fill to red

 t+⍨d draw the food

} close draw loop

P5.kp←{...} execute the following each time a key is pressed (⍵ is key name):

 1-↓⍬2⍴3⊤2320 array of directions │0 1│1 0│0 ¯1│¯1 0│

 ('sdwa'⍳⍵)⊃ get key number, index into directions

 n← store direction in n

 o≢- if snake direction is not the opposite of n,(prevents moving backward)

 o⊢←n then change snake direction

## Gameplay

(recorded at low fps)

• The tio link reports errors for me. Dec 13 '20 at 10:22
• @Anush the tio link isn't supposed to run it, it needs to be run on your system. I left that in by mistake. Dec 13 '20 at 14:27

# JavaScript, 609 bytes

document.write<canvas id=C width=40 height=40 style='width:180px;height:180px;border:4px solid'
s=[l={x:9,y:9}]
h=t=0,v=1
r=(x,y,w,h,f)=>{c.fillStyle=f,c.fillRect(x,y,w,h)}
m=n=>{g=4,i=0|38*(R=Math.random)()+1,j=0|38*R()+1,s.map(b=>b.x^i|b.y^j?0:m())},m()
onkeydown=k=>{f={d:[0,1],a:[0,-1],w:[-1,0],s:[1,0]}[k.key],f?(v=f[0],h=f[1]):0}
z=setInterval(w=>z?(focus(),c=C.getContext2d,r(0,0,80,80,'#fff'),s.push(l={x:l.x+h,y:l.y+v}),s.splice(0,0>g--),l.x^i|l.y^j?0:t+=!m(),s.map(b=>z&&(0>l.x||0>l.y||39<l.x||39<l.y||b!=l&&b.x==l.x&&b.y==l.y)?z=alert('Score:'+t):r(b.x,b.y,1,1,'#000')),r(i,j,1,1,'#f0f')):0,75)

Use WASD for controls.

JSFiddle

• You can remove all the windows and replace the addEventListener with onkeydown=... Dec 9 '20 at 15:01
• Also, parseInt(...) is way longer than ...|0, and you might be able to save some bytes by replacing document with (D=document and then D. Other than that this is a really cool answer! Dec 9 '20 at 15:06
• @Redwolf, cool thanks! I'll update it a bit later, first have to get some actual work done ;-)
– jdt
Dec 9 '20 at 15:11
• -13 bytes: pastebin.com/3xZtyEH2 Dec 11 '20 at 22:20
• Bugs: Trying to double the snake back on itself ends the game, and there is a missing space between Score: and the score May 26 at 23:45

## Python 2.7: 869816818817 816 Characters

I hacked this together in the last few hours. It should meet the requirements and is a few characters shorter than mjgpy3's solution (Tried hard, but couldn't get it much shorter. Now I'm tired). Surprisingly, using a game development library like pygame didn't get the python-snake much shorter. Suggestions and tips how to make it shorter are highly appreciated. I hope it's not too cryptic.

This is the result:

import pygame as p
from random import randint as r
p.init();l=20
c=p.time.Clock()
dp=p.display;w=p.display.set_mode((500,)*2)
C=p.Color;b=C(0,0,0);g=C(0,99,0)
D=(0,1);U=(0,-1);L=(-1,0);R=(1,0)
S=[R];d=R;n=[]
O=lambda t:{U:D,R:L,D:U,L:R}[t]
def Q(e):print "Score: %i"%(len(S)-1);p.quit()
def K(e):global d;_={276:L,273:U,274:D,275:R}.get(e.key,(0,0));d=not _==O(d) and _ or d
def N(S):[p.draw.rect(w,g,[x[0]*l,x[1]*l,l,l]) for x in S+n]
def M():n=(r(0,24),r(0,24));return n not in S and n or M()
A=lambda s,o:tuple(x+y for x,y in zip(s,o))
n=[M()]
while True:
w.fill(b);[{12:Q,2:K}.get(e.type,lambda e:e)(e) for e in p.event.get()]
if not (0<=S[-1][0]<25 and 0<=S[-1][1]<25) or A(S[-1],d) in S: Q(e)
if A(S[-1],d) in n: S.append(A(S[-1],d));n=[M()]
else: S.append(A(S[-1],d));S.pop(0)
N(S);dp.update();c.tick(6)


EDIT: I could reduce it to 816 Bytes, yay! :) Fixed the score

EDIT2: Pasted the wrong version accidentally

Here is a commented version:

import pygame as p
from random import randint as r

# initialize pygame
p.init()

# the game consists of 25*25 blocks,with each block 20*20 pixels
l=20

# initialize the main loop clock
c=p.time.Clock()

# open the window
dp=p.display;w=p.display.set_mode((500,)*2)

# define black and green colors
C=p.Color;b=C(0,0,0);g=C(0,99,0)

# Directions of the snake: down, up, left, right
D=(0,1);U=(0,-1);L=(-1,0);R=(1,0)

# S is the snake, d is the current direction and n is the array of foods
S=[R];d=R;n=[]

# get the opposite direction of a direction to forbid double backing
O=lambda t:{U:D,R:L,D:U,L:R}[t]

# print the score and quit
def Q(e):print "Score: %i"%(len(S)-1);p.quit()

# update the direction (this is a key press handler)
def K(e):global d;_={276:L,273:U,274:D,275:R}.get(e.key,(0,0));d=not _==O(d) and _ or d

# draw the snake and food boxes
def N(S):[p.draw.rect(w,g,[x[0]*l,x[1]*l,l,l]) for x in S+n]

# place new food on the map not colliding with the snake
def M():n=(r(0,24),r(0,24));return n not in S and n or M()

# A((1,1), (-2, 1)) -> (-1,2)
A=lambda s,o:tuple(x+y for x,y in zip(s,o))

# initialize food array
n=[M()]

while True:
# fill the screen black
w.fill(b)
# get quit or key press events and execute the event handlers
[{12:Q,2:K}.get(e.type,lambda e:e)(e) for e in p.event.get()]

# check if snake hits map boundaries or itself
if not (0<=S[-1][0]<25 and 0<=S[-1][1]<25) or A(S[-1],d) in S: Q(e)

# check if snake is eating food at the moment and append one to the snake's length
if A(S[-1],d) in n: S.append(A(S[-1],d));n=[M()]

# move the snake in the current direction
else: S.append(A(S[-1],d));S.pop(0)

# draw the map and limit the main loop to 6 frames per second
N(S);dp.update();c.tick(6)

• I kept getting this error message "Segmentation fault (core dumped)." And it seems like the score is off by 1 (not really a big deal. Very cool answer though. Sep 24 '12 at 11:17
• Thanks :) I get that Segmentation fauklt message too. Didn't figure it out yet. Fixed the score and reduced the size :) this is fun. Sep 24 '12 at 11:30
• you could make the green darker, instead of 255, use 99, then that'll be a byte taken off Mar 21 '19 at 1:47
• @KrystosTheOverlord hahah yes good point :D Mar 22 '19 at 19:08

# Java, 2343 2239

Not exactly concise, but I believe it follows all the requirements.

### Snake class

import javax.swing.*;
public class S extends JFrame{
public static void main(String[]a){new S();}}


### Board class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class B extends JPanel implements ActionListener{
int W=300;int H=300;int DS=10;int AD=900;int RP=29;int D=140;int x[]=new int[AD];int y[]=new int[AD];int d;int ax;int ay;boolean l=false;boolean r=true;boolean u=false;boolean dn=false;boolean ig=true;Timer t;Image b;Image a;Image h;
B(){addKeyListener(new T());setBackground(Color.black);ImageIcon id=new ImageIcon(this.getClass().getResource("d.png"));b=id.getImage();ImageIcon ia=new ImageIcon(this.getClass().getResource("a.png"));a=ia.getImage();ImageIcon ih=new ImageIcon(this.getClass().getResource("h.png"));h=ih.getImage();setFocusable(true);i();}
void i(){d=3;for(int z=0;z<d;z++){x[z]=50-z*10;y[z]=50;}l();t=new Timer(D,this);t.start();}
public void p(Graphics g){super.paint(g);if(i){g.drawImage(a,ax,ay,this);for(int z=0;z<d;z++){if(z==0)g.drawImage(h,x[z],y[z],this);else g.drawImage(b,x[z],y[z],this);}Toolkit.getDefaultToolkit().sync();g.dispose();}else{g(g);}}
void g(Graphics g){String ms="Score:";Font sm=new Font("Courier",Font.PLAIN,12);FontMetrics me=this.getFontMetrics(sm);g.setColor(Color.white);g.setFont(sm);g.drawString(ms+d,(W-me.stringWidth(ms)),H);}
void c(){if((x[0]==ax)&&(y[0]==ay)){d++;l();}}
void m(){for(int z=d;z>0;z--){x[z]=x[(z-1)]; y[z]=y[(z-1)];}if(l){x[0]-=DS;}if (r){x[0]+=DS;}if(u){y[0]-=DS;}if(dn){y[0]+=DS;}}
void cc(){for(int z=d;z>0;z--){if((z>4)&&(x[0]==x[z])&&(y[0]==y[z])){ig=false;}}if(y[0]>H){ig=false;}if(y[0]<0){ig=false;}if(x[0]> W){ig=false;}if(x[0]<0){ig=false;}}
void l(){int r=(int)(Math.random()*RP);ax=((r*DS));r=(int)(Math.random()*RP);ay=((r*DS));}
public void actionPerformed(ActionEvent e){if(ig){c();cc();m();}repaint();}
class T extends KeyAdapter{public void keyPressed(KeyEvent e){int k=e.getKeyCode();if((k==KeyEvent.VK_LEFT)&&(!r)){l=true;u=false;dn=false;}if((k==KeyEvent.VK_RIGHT)&&(!l)){r=true;u=false;dn=false;}if((k==KeyEvent.VK_UP)&&(!dn)){u=true;r=false;l=false;}if((k==KeyEvent.VK_DOWN)&&(!u)){dn=true;r=false;l=false;}}}}
`

### Commentary

A while back I visited a website called zetcode which provided some tutorials for creating classic 2D games in Java. The code provided is strongly influenced by the tutorial that was provided for the Snake game... I think at this time I just started coding classic games and followed the tutorial to a 'T'.

I'll make an edit later and add a link to an executable so people can play the game.

### EDITS

• 9/9/12: I am unable to properly load the images from the resource folder. I'll continue to work through this issue in an attempt to prove that my code works and meets all criteria of the question.
• 9/11/12: I am going to continue working on getting the pictures to load from the resource file. I added a picture provided from the ZetCode tutorial.
• Great, I look forward to trying it! Sep 10 '12 at 2:23
• Is there a link to the executable en-route:) Sep 27 '12 at 16:30
• @BrianBishop Sorry dude, I never did figure out what I was doing incorrectly with my image files in the resource file. Everything compiles, but the images never popup.
– Rob
Oct 1 '12 at 11:51