pygame is
Python
Simple DirectMedia Layer
 
 
pygame.org is
Site Swing
NanoSnake

NanoSnake - 522 B

ffao (ffao)

Tags:

Description

The original NanoSnake file had 1147 B. In the process of shortening it, I've had to make several bytes/usability tradeoffs. Also, I've incorporated suggestions from several people (Vitor Bosshard, Jordan Trudgett, Uli Eggermann, roebros, Jackson Gatenby). The updated code is below, enjoy!
import pygame as p,random
q=p.display
T=16
b=q.set_mode([256]*2).fill
l=[]
d=a=x=1
c=p.event.get
while not(x&528or x in l):
 l=l[a!=x:]+[x]
 while a&528or a in l:a=random.randrange(512)
 b(0);[b(99,(o%T*T,o/32*T,T,T))for o in l+[a]];q.flip();p.time.wait(99);D=d
 for e in c(2):
  v=e.key-272;n=((v&2)-1)*[1,32][v<3]
  if-n-D and 0<v<5:d=n
 c();x+=d

Changes

- Deleted variable k;
- Improved input handling.
- Changed 0x210 to 528.
- Considered enlarging the playfield to 512x512 with the saved space, but realized this would cost me more bytes than I'd expected.

522 B now!

Links

Home Page: http://www.pygame.org
Source: http://stuffr.net/d/12d20vw

Screenshot


click to view original size

Releases

NanoSnake - 348 B - Aug 16, 2008
NanoSnake - 364 B - Aug 12, 2008
NanoSnake - 371 B - Aug 2, 2008
NanoSnake - 429 B - Jul 31, 2008
NanoSnake - 478 B -- The Harder They Fall - Jul 31, 2008
NanoSnake - 502 B -- The Show Must Go On - Jul 31, 2008
NanoSnake - 522 B - Jul 30, 2008
NanoSnake - 554 B - Jul 30, 2008

Pygame.org account Comments

If you wish to leave a comment with your pygame.org account, please sign in first.

August 17, 2008 10:10am - Jordan Trudgett - nickname: (tgfcoder)
suggestions:
remove random from import, change line which uses random to
while a&528or a in l:a=(a*9)%512

now pseudo-random, gets you to 330 bytes.
August 17, 2008 9:10am - pymike - nickname: (pymike)
http://pymike.pastebin.com/f250cfbe3
If you want it down to 9 lines of code :P
August 15, 2008 11:38pm - Jordan Trudgett - nickname: (tgfcoder)
But in many cases the semicolon needed uses the same space as the newline. Hmm...
August 15, 2008 11:33pm - Jordan Trudgett - nickname: (tgfcoder)
Also, drop some linebreaks to save bytes for space indentation (thanks to Jackson Gatenby)
August 15, 2008 4:29pm - ffao - nickname: (ffao)
"from pygame import *" implies an "import random" later on...
August 15, 2008 8:18am - Jordan Trudgett - nickname: (tgfcoder)
from pygame import*
then remove p.'s?
August 12, 2008 7:08pm - ffao - nickname: (ffao)
Unfortunately no, as I only want multiples of 16. The code to round a number to the lowest multiple of 16 is o/16*16 - it may appear redundant, but it's not.
August 12, 2008 6:07am - ShenLei - nickname: (melon1234) - 5/5
Impressed!
Can "o/32*T" be changed to "o/2"?
August 4, 2008 4:23pm - Ian Mallett - nickname: (geometrian)
Actually, scratch that.
Get rid of these lines: "c=p.event.get", "c()"
and replace for e in "c(2)" with "for e in p.event.get(2)"
August 4, 2008 4:21pm - Ian Mallett - nickname: (geometrian)
Get rid of the line "c()"
Obviously, moving the mouse etc. will make it crash, but so does hitting the wall, so it is basically the same.
August 3, 2008 4:46am - Uli Eggermann - nickname: (theeggman)
@roebros: Sorry - I didn't read enough ;) You're right. Maybe in next python/pygame version you can mix tabs and blanks, too!
August 2, 2008 9:17pm - RB[0] - nickname: (roebros)
Uli, please note in the comments where I said that it broke the code to do that for me ;) Using latest python/pygame on Ubuntu.
August 2, 2008 8:21pm - Uli Eggermann - nickname: (theeggman)
Hello all together!
371 wow!
But I think I can't see those tabs (hex 09) in lines 17-19!
If you'd implant them, you'd reach the 368!

bash $ hexdump -C nano-snake-2a.py
00000000 69 6d 70 6f 72 74 20 70 79 67 61 6d 65 20 61 73 |import pygame as|
00000010 20 70 2c 72 61 6e 64 6f 6d 0a 70 2e 69 6e 69 74 | p,random.p.init|
00000020 28 29 0a 71 3d 70 2e 64 69 73 70 6c 61 79 0a 54 |().q=p.display.T|
00000030 3d 31 36 0a 62 3d 71 2e 73 65 74 5f 6d 6f 64 65 |=16.b=q.set_mode|
00000040 28 5b 32 35 36 5d 2a 32 29 2e 66 69 6c 6c 0a 6c |([256]*2).fill.l|
00000050 3d 5b 5d 0a 44 3d 64 3d 61 3d 78 3d 31 0a 63 3d |=[].D=d=a=x=1.c=|
00000060 70 2e 65 76 65 6e 74 2e 67 65 74 0a 77 68 69 6c |p.event.get.whil|
00000070 65 20 6e 6f 74 28 78 26 35 32 38 6f 72 20 78 20 |e not(x&528or x |
00000080 69 6e 20 6c 29 3a 0a 20 6c 3d 6c 5b 61 21 3d 78 |in l):. l=l[a!=x|
00000090 3a 5d 2b 5b 78 5d 0a 20 77 68 69 6c 65 20 61 26 |:]+[x]. while a&|
000000a0 35 32 38 6f 72 20 61 20 69 6e 20 6c 3a 61 3d 72 |528or a in l:a=r|
000000b0 61 6e 64 6f 6d 2e 72 61 6e 64 72 61 6e 67 65 28 |andom.randrange(|
000000c0 35 31 32 29 0a 20 62 28 30 29 0a 20 5b 62 28 39 |512). b(0). [b(9|
000000d0 39 2c 28 6f 25 54 2a 54 2c 6f 2f 33 32 2a 54 2c |9,(o%T*T,o/32*T,|
000000e0 54 2c 54 29 29 66 6f 72 20 6f 20 69 6e 20 6c 2b |T,T))for o in l+|
000000f0 5b 61 5d 5d 0a 20 71 2e 66 6c 69 70 28 29 0a 20 |[a]]. q.flip(). |
00000100 70 2e 74 69 6d 65 2e 77 61 69 74 28 39 39 29 0a |p.time.wait(99).|
00000110 20 66 6f 72 20 65 20 69 6e 20 63 28 32 29 3a 0a | for e in c(2):.|
00000120 09 76 3d 65 2e 6b 65 79 2d 32 37 32 0a 09 6e 3d |.v=e.key-272..n=|**
00000130 28 28 76 26 32 29 2d 31 29 2a 5b 31 2c 33 32 5d |((v&2)-1)*[1,32]|
00000140 5b 76 3c 33 5d 0a 09 69 66 2d 6e 2d 44 20 61 6e |[v<3]..if-n-D an|*
00000150 64 20 30 3c 76 3c 35 3a 64 3d 6e 0a 20 44 3d 64 |d 0<v<5:d=n. D=d|
00000160 0a 20 63 28 29 0a 20 78 3d 6c 5b 2d 31 5d 2b 64 |. c(). x=l[-1]+d|
00000170

It is not much, but...

Greetings!
August 2, 2008 11:31am - Jordan Trudgett - nickname: (tgfcoder)
You need to change some <'s to &lt;'s.
Incase that didn't come out, change some angular brackets to the &lt equiv. Otherwise your code isn't going to be the same here.

Haha. Okay :)
I might (in a few weeks) make a basic snake game with graphics, and have lots of graphics that can be used for future stuff so that if you intend to make it, the graphics is there. It might be an idea to share the project around with the other guys too, whoever they might be, and maybe they can code stuff too.

Hmm, well it remains an idea if I've got nothing to do on a rainy day X)
August 2, 2008 10:46am - ffao - nickname: (ffao)
If we do create a decent Snake game, you do the artwork! ;)
Rectangles are as good as it gets with me...
August 2, 2008 6:24am - Jordan Trudgett - nickname: (tgfcoder)
Changed "while x&528or x in l:" to "if x&528or x in l:". It was originally an if, but it probably got changed along the way.

As "if", it's 362 bytes, and as "while", it's 365.

(as is)
-rw-r--r-- 1 jordan jordan 365 2008-08-02 20:15 snake.py
(changed to if)
-rw-r--r-- 1 jordan jordan 362 2008-08-02 20:16 snake.py


It works better as while; otherwise it seems glitchy.
Also, there's a bug- you can change direction multiple times per frame (if you're fast) Try it, by making the delay longer, you can go

Frame 20: (FACING RIGHT)
press down .. face down
press left .. face left
Frame 21: (FACING LEFT)
crash into self

You have to be at least 2 units long, I think.
I think fixing that bug might have been a bulk in my code.

After this, we should make a proper snake game, maybe collaboratively? :P
August 1, 2008 1:31pm - RB[0] - nickname: (roebros)
I think you are right, I was testing and I thought I gained a byte or two, but I'm not sure now LOL.

Also, make sure fix the if -n-d:d=n line to if-n-d:d=n (saves a byte ;) )
August 1, 2008 1:20pm - ffao - nickname: (ffao)
So did I (if you didn't realize, the current version is 391 B without space/tab). It was just a matter of replacing the "while" with the "if", I think the "from pygame import *" thing uses the exact same number of bytes as "import pygame as p".
August 1, 2008 12:47pm - RB[0] - nickname: (roebros)
Here is the best I could do, got it back to 391 bytes without the space/tab mess stuff :D

import random
from pygame import*
init()
q=display
T=16
s=q.set_mode([256]*2)
b=s.fill
l=[0]
d=1
a=2
c=event.get
def j(o):b(99,(o%T*T,o/32*T,T,T))
while 1:
for e in c(2):
v=e.key-272
if 0<v<5:
n=((v&2)-1)*[1,32][v<3]
if-n-d:d=n
c()
b(0)
x=l[-1]+d
if x&528or x in l:o
l+=[x]
if a-x:l=l[1:]
while a&528or a in l:a=random.randrange(512)
map(j,l+[a])
q.flip()
time.wait(99)
August 1, 2008 12:25pm - RB[0] - nickname: (roebros) - 5/5
Awesome project guys!
Quick suggestion, in line 21, would not "if x&528or x in l:o" be smaller? I tested and it still works as far as I can tell.

Also, your code mix of spaces/tabs breaks my Python 2.5 on ubuntu :(
August 1, 2008 10:52am - ffao - nickname: (ffao)
I'd never have thought about that spaces to tabs substitution, that was quite ingenious! About LF, I'll just point out that Jordan can move back to LF if he wants now that I discovered that my editor had a hidden "UNIX" mode :)
August 1, 2008 6:17am - Uli Eggermann - nickname: (theeggman)
Me again!
not changing only the longest indents but those four:

if e.type==2:
<tab>v=e.key-272
<tab>if 0<v<5:
<tab> n=((v&2)-1)*[1,32][v<3]
<tab> if -n-d:d=n

brings me down to 397 bytes...

-rwxrwxrwx 1 theeggman mkpasswd 397 Aug 1 12:13 nano-snake.py

... and the game is still running!
August 1, 2008 6:10am - Uli Eggermann - nickname: (theeggman)
Phantastic!
I'm new here...
- What about changing all the CR/LF to only LF?
- What about changing the largest indent from spaces to tabs?
Doing these I get a total length of 399 bytes:

-rwxrwxrwx 1 theeggman mkpasswd 399 Aug 1 12:00 nano-snake.py

So long!
August 1, 2008 2:38am - Jordan Trudgett - nickname: (tgfcoder)
Congratulations, this is truly a work of art. I adore the def(): shortening, I never would've thought of that (Damn you, good programming habits!)

Also, why didn't I find randrange? Ah, the syntax in docs dissuaded me ... :S

I knew there should be a random function from 0 to x, which is shorter than randint(0,x)

"[v<3]"

My program also has <3

(heart)
August 1, 2008 2:33am - Jordan Trudgett - nickname: (tgfcoder)
Normal speak: Error
Programmer speak: Feature

i.e. An easy way to implement quitting! And save bytes while you're at it.
July 31, 2008 10:25pm - ffao - nickname: (ffao)
I hate HTML! (0<5 should have been 0<v<5) Thanks for pointing out the bug, but that code is really needed -- without it the code will crash whenever you press any key other than the arrow keys (enter, for example).
July 31, 2008 10:21pm - Vitor Bosshard - nickname: (algorias)
You introduced another bug, "if 0<5" is always true. I don't really know what that code was supposed to do, the game works anyway, so maybe you can just drop that whole statement and save another 9b.
July 31, 2008 10:11pm - ffao - nickname: (ffao)
About the special effect thing, well, I'll have to think about it. Also, the next version will probably contain more single-line compound statements; it's valid Python syntax and reduces the byte count after all (and makes the code look a bit more impressive :)
July 31, 2008 10:09pm - Vitor Bosshard - nickname: (algorias)
Even better!

Another thing: def j(o) is shorter than j=lambda o
July 31, 2008 10:06pm - ffao - nickname: (ffao)
Well, as everybody seems OK with a crash exit (in fact, everybody is suggesting me a crash exit), I'll do it. Note that I didn't need "1/0", a simple "o" suffices in that aspect (undefined variable).
July 31, 2008 10:00pm - Vitor Bosshard - nickname: (algorias)
You can repalce the bottommost while with an if, and the resulting behaviour could even be called a "special effect". Also, break can be substituted with 1/0. Besides those two nitpicks, the code is starting to look pretty clean and optimized.
July 31, 2008 9:36pm - ffao - nickname: (ffao)
@Jordan: about the bottom right edges killing you too early, it was really my fault after all (why is it always my fault?). As it turned out, the original code was displaying 2 frames early; when Vitor pointed out the unresponsiveness, I managed to get it to display only 1 frame early; now it's always displaying the newest frame (which it should be doing since the beginning; again, my fault). <br /><br />Thanks for the suggestions, I didn't think this code could be shortened further (as it turned out, it could be by a wide margin. I'm now wondering if I would find all those optimizations alone had you beat my 478 B version... I wouldn't lose the crown that easily ;) <br />
<br /> <br/>
@Emanuel: I might actually get to doing that when the code is stable enough. As I've just uploaded a new version with one less bug and 33 less bytes, it's definitely not stable yet!
July 31, 2008 4:18pm - Jordan Trudgett - nickname: (tgfcoder)
@Emanuel: teach*

But writing small programs is not generally useful today, just fun, and skillful ;) Good fun =P -- ffao will probably agree that mine played better (until I had to get it under 550 ish B :P)

Hey, I think this may have started around the time of my project "Tetris in 73 lines", then Snake followed in the same tradition, "Snake in 35 lines", and then the bytecount snakes came in soon after.

I just can't be bothered to write a smaller one, although I probably could:
(for example, my pellets CAN spawn on the snake.)
(about -12 bytes??)

Change references to y to 32 (there are only two)
+2 bytes
-6 for the initialisation
(-4 B)

Change break to an undefined variable name
(crash exit instead of break)
(-4 B)

(T*T,)*2 becomes [T*T]*2

(-1 B)

Your algorithm won out in the end. I started off with a rich version, and when I shortened that, it was STILL bulky. I admire your 'hack' of Snake :)
(I, having done a lot of the stuff in your game too, understand most if not all of it.)
July 31, 2008 11:20am - Emanuel Berg - nickname: (metabaron)
ALL HAIL THE WINNER!
and the first prize is: the honor of writing a tutorial, "python's smallest snake", where you generalize your experience from the contest and learn the rest of us to write really small applications :-)
July 31, 2008 10:41am - Jordan Trudgett - nickname: (tgfcoder)
I think you win O.O. It's nearly 1 AM. And I don't want to rewrite it.
Grats. :P
July 31, 2008 9:34am - ffao - nickname: (ffao)
OK, so we'll avoid line breaking from now on. Would you like me to remove my "if -n!=d:d=n"?
July 31, 2008 9:29am - Jordan Trudgett - nickname: (tgfcoder)
If we are using CRLF byte counting, then line break dropping is NOT allowed. I like LF counting because that's the smallest size it can take (you can theoretically change CRLFs to LFs, like any othe character) and it doesn't have problems with line break dropping, because if you use a semicolon, it takes the same space- thus improving readability.
July 31, 2008 9:22am - ffao - nickname: (ffao)
Oh, and thanks for the postable link!
July 31, 2008 9:19am - ffao - nickname: (ffao)
About the dropped line break, well, it was used for input on all other versions (although mine has only one if, I might actually benefit if that was disallowed ;)
While we're at it, on an Unix such as tgfcoder's, NanoSnake is 471 bytes long :D
July 31, 2008 9:17am - ffao - nickname: (ffao)
The decreased responsiveness was mostly my fault (see changes). I now spent a long time running around the corners to make sure that all the borders are OK, and they seem to be so (although the program exits before showing the collision between the snake and the wall, so the player may feel a little odd about that).
July 31, 2008 1:52am - Jordan Trudgett - nickname: (tgfcoder)
I don't regard dropping linebreaks as cheating--it is valid Python, and it doesn't improve your bytecount drastically (perhaps up to about 10 bytes max.)
July 31, 2008 1:12am - Jordan Trudgett - nickname: (tgfcoder)
ffao, use http://www.elliotswan.com/postable/ to make your code HTML friendly. :)
July 30, 2008 10:52pm - Vitor Bosshard - nickname: (algorias)
Sorry about the lambda thing, I missed the a=o() right at the bottom.

Actually you have one dropped linebreak: if -n!=d:d=n
July 30, 2008 10:50pm - Jordan Trudgett - nickname: (tgfcoder)
This is great XD Good to know there are people with a love and talent with Python that I have!! I must get to work on my snake to make it smaller!
The input is a bit hard to use, and it seems the bottom and right edges sometimes kill you too early.. Hm
July 30, 2008 10:46pm - ffao - nickname: (ffao)
It isn't so unresponsive here, but I guess that's the price you pay for shortening it -- it becomes more and more cpu-intensive as you go. As for dropping linebreaks, geometrian considered that 'cheating'; I'm only following the rules. As for dropping lambda, I don't see how that would save me space. import random as r gives the exact same byte count, and makes the code a bit less readable (as if it was readable to begin with ;) As for 2<7, well, that's indeed a mistake, it should have been 2<v<7. I'll see if I can fix it.
July 30, 2008 10:38pm - Vitor Bosshard - nickname: (algorias)
Pretty cool, but very unresponsive. Also what's up with "if 2<7"? There are several other minor optimizations to be done. You can drop linebreaks after if statements, drop the lambda, import random as r, etc.
July 30, 2008 10:33pm - ffao - nickname: (ffao)
Second version out - 522 B! (will it break 500?)
July 30, 2008 9:56pm - Ian Mallett - nickname: (geometrian)
I agree, and I like your control method better. The problem is the delay. I put time.sleep(1) not 0.1 to save 1 or 2 characters. There's some other problems with mine too. Good job!
July 30, 2008 9:29pm - ffao - nickname: (ffao)
First version is out!
spotlight

 
our projects
pygame.org welcomes all python game, art, music, sound, video and multimedia projects. If they use pygame or not.
 
recent releases
Oct 28, 2014

Oct 21, 2014

Oct 20, 2014

Oct 16, 2014

Oct 9, 2014

Oct 8, 2014

Oct 7, 2014

Oct 4, 2014

Oct 1, 2014

Sep 19, 2014

Sep 17, 2014

Sep 9, 2014

... more!
 
for pygame related questions, comments, and suggestions, please see help (lists, irc)