Recréez le jeu de serpent classique


11

Le défi est de créer le jeu Snake classique en utilisant le moins d'octets possible.

Voici les prérequis:

  • Le jeu doit être implémenté dans une disposition en 2 dimensions typique. Le serpent devrait pouvoir grandir de manière significative dans les limites de la carte (cela signifie vraiment, ne faites pas votre carte trop petite, utilisez votre discrétion ici).
  • Un utilisateur peut déplacer le serpent à l'aide des clés de votre choix, cependant, le serpent ne peut pas se replier sur lui-même (par exemple, s'il va vers l'ouest, il ne peut pas aller vers l'est sans aller d'abord au nord ou au sud). Un serpent doit pouvoir voyager dans les 4 directions: haut, bas, gauche, droite (Nord, Sud, Ouest, Est).
  • Le serpent commence à la longueur 1, chaque fois qu'il mange un objet "alimentaire", il grandit de +1
  • Les objets alimentaires sont placés au hasard dans des endroits autres que ceux occupés par le serpent
  • Si le serpent se frappe ou frappe un mur, le jeu est terminé
  • Une fois la partie terminée, le littéral "Score: [score]" s'affiche où [score] est le nombre de denrées alimentaires consommées pendant la partie. Ainsi, par exemple, si le serpent a mangé 4 "aliments" (et a donc une longueur de 5) à la fin du jeu, "Score: 4" sera imprimé.
  • Aucun algorithme de compression à moins qu'ils ne soient explicitement définis dans votre code.

Voici ma solution, 908 octets, 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 certaines personnes n'aiment pas être limitées aux terminaux.
Griffin

la règle du «serpent ne peut pas doubler» s'applique-t-elle si le serpent a une longueur = 1?
Paul Prestidge

@chron, oui. À tout moment, les serpents ne peuvent (vraiment) tourner que dans les deux sens, à gauche et à droite.
mjgpy3

Réponses:


2

Ruby 1.9 + SDL (341 324 316)

Voici une première tentative de version Ruby à l'aide de la bibliothèque SDL. Je peux enregistrer 6 caractères si je suis autorisé à charger la bibliothèque SDL à l'aide -rsdlde la ligne de commande au lieu de l'instruction 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}

Les segments de serpent et les morceaux de nourriture sont représentés en pixels noirs, la taille de la grille est actuellement de 32 * 32. Vous pouvez contrôler avec les touches fléchées (ou n'importe quelle touche vraiment, le mod de code clé 4 indexe le tableau de direction [GAUCHE, HAUT, BAS, DROITE]). Je pense qu'il y a certainement place à amélioration ici, en particulier dans la déclaration IF de vérification de la mort.

J'ai considérablement amélioré cela par rapport à la version précédente, j'espère que cela correspond plus à l'esprit de la question maintenant. Il y a une chose que je dois corriger pour me conformer à la spécification, c'est que la nourriture peut actuellement apparaître à l'intérieur de la queue. Fixé!

Imprime le score sur stdout une fois le jeu terminé.


2

Java, 2343 2239

Pas exactement concis, mais je pense que cela répond à toutes les exigences.

Classe de serpent

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 de conseil

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

Capture d'écran

jeu de serpent en java


Commentaire

Il y a quelque temps, j'ai visité un site Web appelé zetcode qui fournissait des didacticiels pour créer des jeux 2D classiques en Java. Le code fourni est fortement influencé par le tutoriel fourni pour le jeu Snake ... Je pense qu'à ce moment-là, je viens de commencer à coder des jeux classiques et j'ai suivi le tutoriel jusqu'à un "T".

Je ferai une modification plus tard et ajouterai un lien vers un exécutable afin que les gens puissent jouer au jeu.


MODIFICATIONS

  • 9/9/12: Je n'arrive pas à charger correctement les images du dossier de ressources. Je vais continuer à travailler sur ce problème afin de prouver que mon code fonctionne et répond à tous les critères de la question.
  • 11/09/12: Je vais continuer à travailler sur le chargement des images à partir du fichier de ressources. J'ai ajouté une image fournie par le tutoriel ZetCode.

Super, j'ai hâte de l'essayer!
mjgpy3

Existe-t-il un lien vers l'exécutable en route :)
Drenai

@BrianBishop Désolé mec, je n'ai jamais compris ce que je faisais mal avec mes fichiers image dans le fichier de ressources. Tout se compile, mais les images ne surgissent jamais.
Rob

2

Bash: 537 533 507 caractères

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

Comme il utilise les $COLUMNSet $LINESvariables shell, il doit être exécuté source: . snake.sh. Le serpent peut être contrôlé avec les touches w/ a/ s/ d.

Je sais, il peut être facilement réduit à 493 caractères en utilisant clearpour effacer l'écran, mais je préfère le garder pur bash, sans utiliser aucun outil externe.


Solution très cool!
mjgpy3

1

Python 2.7: 869 816 818 817 816 Caractères

J'ai piraté cela ensemble au cours des dernières heures. Il devrait répondre aux exigences et est plus court de quelques caractères que la solution de mjgpy3 (J'ai essayé dur, mais je n'ai pas pu le faire beaucoup plus court. Maintenant, je suis fatigué). Étonnamment, l'utilisation d'une bibliothèque de développement de jeux comme pygame n'a pas raccourci le serpent python. Les suggestions et astuces pour le raccourcir sont très appréciées. J'espère que ce n'est pas trop cryptique.

Voici le résultat:

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: je pourrais le réduire à 816 octets, yay! :) Correction du score

EDIT2: Collé la mauvaise version accidentellement

Voici une version commentée:

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)

J'ai continué à recevoir ce message d'erreur "Erreur de segmentation (core dumpé)." Et il semble que le score soit inférieur de 1 (ce n'est pas vraiment une grosse affaire. Réponse très cool
quand

2
Merci :) Je reçois aussi ce message de segmentation fauklt. Je ne l'ai pas encore compris. Correction du score et réduction de la taille :) c'est amusant.
stefreak du

1
vous pouvez rendre le vert plus foncé, au lieu de 255, utilisez 99, alors ce sera un octet retiré
KrystosTheOverlord

@KrystosTheOverlord hahah oui bon point: D
stefreak
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.