Recrea el clásico juego de la serpiente

11

El desafío es crear el clásico juego Snake usando la menor cantidad de bytes posible.

Aquí están los requisitos:

  • El juego debe implementarse en un diseño bidimensional típico. La serpiente debería poder crecer significativamente dentro de los límites del mapa (esto realmente significa, no haga su mapa demasiado pequeño, use su discreción aquí).
  • Un usuario puede mover la serpiente usando las teclas que elija, sin embargo, la serpiente no puede doblarse sobre sí misma (por ejemplo, si va hacia el oeste, no puede ir hacia el este sin ir primero hacia el norte o hacia el sur). Una serpiente debería poder viajar en las 4 direcciones: arriba, abajo, izquierda, derecha (norte, sur, oeste, este).
  • La serpiente comienza como longitud 1, cada vez que come un objeto "comida" crece +1 en longitud
  • Los objetos de comida se colocan al azar en lugares distintos de los ocupados por la serpiente
  • Si la serpiente se golpea a sí misma o a una pared, el juego termina
  • Cuando finaliza el juego, se muestra el literal "Puntaje: [puntaje]" donde [puntaje] es el número de alimentos consumidos durante el juego. Entonces, por ejemplo, si la serpiente ha comido 4 "alimentos" (y por lo tanto tiene una longitud de 5) cuando termina el juego, se imprimirá "Puntuación: 4".
  • No hay algoritmos de compresión a menos que estén explícitamente definidos en su código.

Aquí está mi solución, 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
 for i in q(0,s):z.addch(s[i][0],s[i][1],"X")
 z.addch(x[0],x[1],"O")
 z.move(0,0)
 z.refresh()
 if d[1]!=0:c.napms(e/2)
 else:c.napms(e)
c.endwin()
print 'Score: %s'%n
mjgpy3
fuente
1
posible duplicado de Recreate a 'Snake' en una consola / terminal
copie el
1
@copiar a algunas personas no les gusta estar restringidas a las terminales.
Griffin
¿Se aplica la regla 'la serpiente no puede duplicar la espalda' si la serpiente tiene una longitud = 1?
Paul Prestidge
@chron, sí lo hace. En todo momento, las serpientes solo pueden (de verdad) girar en dos direcciones, izquierda y derecha.
mjgpy3

Respuestas:

2

Ruby 1.9 + SDL (341 324 316)

Aquí hay un primer intento de una versión de Ruby usando la biblioteca SDL. Puedo guardar 6 caracteres si se me permite cargar la biblioteca SDL usando -rsdlen la línea de comando en lugar de la instrucción require.

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}

Los segmentos de serpiente y las piezas de comida se representan con píxeles negros, el tamaño de la cuadrícula es actualmente de 32 * 32. Puede controlar con las teclas de flecha (o cualquier tecla realmente, el mod 4 del código de tecla indexa la matriz de dirección [IZQUIERDA, ARRIBA, ABAJO, DERECHA]). Creo que definitivamente hay margen de mejora aquí, especialmente en la declaración IF de verificación de muerte.

Lo he mejorado enormemente con respecto a la versión anterior, espero que ahora coincida más con el espíritu de la pregunta. Hay una cosa que necesito arreglar para cumplir con la especificación, que es que la comida actualmente puede engendrar dentro de la cola. ¡Fijo!

Imprime el puntaje en stdout después de completar el juego.

Paul Prestidge
fuente
2

Java, 2343 2239

No es exactamente conciso, pero creo que sigue todos los requisitos.

Clase de serpiente

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();}}

Clase de la junta

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;}}}}

Captura de pantalla

juego de serpiente en java


Comentario

Hace un tiempo visité un sitio web llamado zetcode que proporcionaba algunos tutoriales para crear juegos 2D clásicos en Java. El código proporcionado está fuertemente influenciado por el tutorial que se proporcionó para el juego Snake ... Creo que en este momento recién comencé a codificar juegos clásicos y seguí el tutorial hasta una 'T'.

Haré una edición más tarde y agregaré un enlace a un ejecutable para que las personas puedan jugar el juego.


EDICIONES

  • 9/9/12: No puedo cargar correctamente las imágenes de la carpeta de recursos. Continuaré trabajando en este problema en un intento de probar que mi código funciona y cumple con todos los criterios de la pregunta.
  • 11/09/12: voy a seguir trabajando para que las imágenes se carguen desde el archivo de recursos. Agregué una imagen del tutorial de ZetCode.
Robar
fuente
¡Genial, espero probarlo!
mjgpy3
¿Hay un enlace al ejecutable en ruta :)
Drenai
@BrianBishop Lo siento amigo, nunca supe qué estaba haciendo incorrectamente con mis archivos de imagen en el archivo de recursos. Todo se compila, pero las imágenes nunca aparecen.
Rob el
2

Bash: 537 533 507 caracteres

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

Ya que utiliza los $COLUMNSy $LINESlas variables de shell, debe ejecutarse de origen: . snake.sh. La serpiente se puede controlar con las teclas w/ a/ s/ d.

Lo sé, se puede reducir fácilmente a 493 caracteres usando clearpara limpiar la pantalla, pero prefiero mantenerlo puro bash, sin usar ninguna herramienta externa.

hombre trabajando
fuente
¡Muy buena solución!
mjgpy3
1

Python 2.7: 869 816 818 817 816 Caracteres

Pirateé esto juntos en las últimas horas. Debe cumplir los requisitos y tiene unos pocos caracteres más cortos que la solución de mjgpy3 (Intenté mucho, pero no pude hacerlo mucho más corto. Ahora estoy cansado). Sorprendentemente, el uso de una biblioteca de desarrollo de juegos como pygame no hizo que la serpiente pitón fuera mucho más corta. Sugerencias y consejos sobre cómo acortarlo son muy apreciados. Espero que no sea demasiado críptico.

Este es el resultado:

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)

EDITAR: ¡Podría reducirlo a 816 Bytes, yay! :) Se corrigió el puntaje

EDIT2: pegó la versión incorrecta accidentalmente

Aquí hay una versión comentada:

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)
stefreak
fuente
Seguí recibiendo este mensaje de error "Error de segmentación (núcleo volcado)". Y parece que el marcador está desactivado de 1 (no es realmente un problema muy fresco respuesta, aunque..
mjgpy3
2
Gracias :) También recibo ese mensaje de segmentación fauklt. No lo descubrí todavía. Se corrigió el puntaje y se redujo el tamaño :) esto es divertido.
stefreak
1
podría hacer que el verde sea más oscuro, en lugar de 255, use 99, entonces eso será un byte despegado
KrystosTheOverlord
@KrystosTheOverlord jaja sí sí buen punto: D
stefreak