g | x | w | all
Bytes Lang Time Link
nan250916T210405ZBad Boy
609JavaScript201208T211853Zjdt
233APL dzaima/APL201208T174631ZRazetime
816Python 2.7 816 Characters120924T004240Zstefreak
507Bash120911T175301Zmanatwor
316Ruby 1.9 + SDL 341 324120910T053840ZPaul Pre
2239Java120909T170505Zanon

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.getContext`2d`,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)

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.getContext`2d`,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

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)

enter image description here

Python 2.7: 869 816 818 817 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)

Bash: 537 533 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.

Ruby 1.9 + SDL (341 324 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.

Java, 2343 2239

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

Snake class

import javax.swing.*;
public class S extends JFrame{
S(){add(new B());setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setSize(320,340);setVisible(true);}
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;}}}}

Screenshot

snake game in java


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