Ricrea il classico gioco del serpente


11

La sfida è creare il classico gioco Snake usando il minor numero di byte possibile.

Ecco i requisiti:

  • Il gioco deve essere implementato in un tipico layout bidimensionale. Il serpente dovrebbe essere in grado di crescere in modo significativo entro i limiti della mappa (questo significa davvero, non rendere la mappa troppo piccola, usa la tua discrezione qui).
  • Un utente può spostare il serpente usando i tasti di tua scelta, tuttavia, il serpente non può raddoppiare su se stesso (ad es. Se va verso ovest non può andare verso est senza prima andare verso nord o sud). Un serpente dovrebbe essere in grado di viaggiare in tutte e 4 le direzioni: su, giù, a sinistra, a destra (nord, sud, ovest, est).
  • Snake inizia come lunghezza 1, ogni volta che mangia un oggetto "cibo" cresce +1 in lunghezza
  • Gli oggetti alimentari vengono posizionati casualmente in luoghi diversi da quelli occupati dal serpente
  • Se il serpente colpisce se stesso o un muro il gioco termina
  • Quando il gioco è terminato, viene visualizzato letteralmente "Punteggio: [punteggio]", dove [punteggio] è il numero di alimenti consumati durante il gioco. Quindi, ad esempio, se il serpente ha mangiato 4 "alimenti" (e quindi ha una lunghezza di 5) al termine del gioco, verrà stampato "Punteggio: 4".
  • Nessun algoritmo di compressione a meno che non siano esplicitamente definiti nel codice.

Ecco la mia soluzione, 908 byte, 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


1
@copy ad alcune persone non piace essere limitato ai terminali.
Griffin,

si applica la regola "il serpente non può raddoppiare" se il serpente ha lunghezza = 1?
Paul Prestidge,

@chron, sì. In ogni momento, i serpenti possono solo (veramente) girare in due direzioni, a sinistra ea destra.
mjgpy3,

Risposte:


2

Ruby 1.9 + SDL (341 324 316)

Ecco un primo tentativo di una versione di Ruby utilizzando la libreria SDL. Posso salvare 6 caratteri se mi è permesso caricare la libreria SDL usando -rsdldalla riga di comando invece dell'istruzione request.

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}

I segmenti del serpente e i pezzi di cibo sono rappresentati usando pixel neri, la dimensione della griglia è attualmente 32 * 32. Puoi controllare con i tasti freccia (o qualsiasi altro tasto, il keycode mod 4 indicizza l'array di direzione [LEFT, UP, DOWN, RIGHT]). Penso che ci sia sicuramente spazio per miglioramenti qui, specialmente nella dichiarazione IF sul controllo della morte.

L'ho notevolmente migliorato rispetto alla versione precedente, spero che corrisponda più allo spirito della domanda ora. C'è una cosa che devo correggere per rispettare le specifiche, ovvero che il cibo può attualmente generarsi all'interno della coda. Fisso!

Stampa il punteggio su stdout al termine del gioco.


2

Java, 2343 2239

Non esattamente conciso, ma credo che segua tutti i requisiti.

Classe serpente

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

Classe di bordo

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

Immagine dello schermo

gioco del serpente a java


Commento

Qualche tempo fa ho visitato un sito web chiamato zetcode che forniva alcuni tutorial per la creazione di giochi 2D classici in Java. Il codice fornito è fortemente influenzato dal tutorial che è stato fornito per il gioco Snake ... Penso che in questo momento ho appena iniziato a programmare i giochi classici e ho seguito il tutorial fino a una "T".

Farò una modifica in seguito e aggiungerò un collegamento a un eseguibile in modo che le persone possano giocare.


EDITS

  • 09/09/12: Non riesco a caricare correttamente le immagini dalla cartella delle risorse. Continuerò a risolvere questo problema nel tentativo di dimostrare che il mio codice funziona e soddisfa tutti i criteri della domanda.
  • 11/09/12: Continuerò a lavorare sul caricamento delle immagini dal file di risorse. Ho aggiunto un'immagine fornita dal tutorial di ZetCode.

Fantastico, non vedo l'ora di provarlo!
mjgpy3,

C'è un collegamento all'eseguibile in rotta :)
Drenai,

@BrianBishop Mi dispiace amico, non ho mai capito cosa stavo facendo in modo errato con i miei file di immagine nel file di risorse. Tutto si compila, ma le immagini non compaiono mai.
Rob

2

Bash: 537 533 507 caratteri

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

In quanto utilizza i $COLUMNSe $LINESvariabili di shell, esso deve essere eseguito origine: . snake.sh. Il serpente può essere controllato con i tasti w/ a/ s/ d.

Lo so, può essere facilmente ridotto a 493 caratteri usando clearper cancellare lo schermo, ma preferisco mantenerlo puro bash, senza usare nessuno strumento esterno.


Soluzione molto interessante!
mjgpy3,

1

Python 2.7: 869 816 818 817 816 personaggi

L'ho hackerato insieme nelle ultime ore. Dovrebbe soddisfare i requisiti ed è più corto di alcuni caratteri rispetto alla soluzione di mjgpy3 (Provato duramente, ma non potevo farlo molto più corto. Ora sono stanco). Sorprendentemente, l'uso di una libreria di sviluppo di giochi come pygame non ha reso il serpente pitone molto più breve. Suggerimenti e suggerimenti su come abbreviare sono molto apprezzati. Spero non sia troppo criptico.

Questo è il risultato:

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: Potrei ridurlo a 816 byte, yay! :) Risolto il punteggio

EDIT2: incollato accidentalmente la versione errata

Ecco una versione commentata:

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)

Ho continuato a ricevere questo messaggio di errore "Errore di segmentazione (core scaricato)". E sembra che il punteggio sia fuori di 1 (non è un grosso problema. Risposta molto bella però.
mjgpy3

2
Grazie :) Ricevo anche quel messaggio Fauklt di segmentazione. Non l'ho ancora capito. Risolto il problema e ridotto le dimensioni :) questo è divertente.
stefreak,

1
potresti rendere il verde più scuro, anziché 255, usare 99, quindi sarà un byte rimosso
KrystosTheOverlord

@KrystosTheOverlord hahah sì buon punto: D
stefreak
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.