Odtwórz klasyczną grę w węża


11

Wyzwanie polega na stworzeniu klasycznej gry Snake przy użyciu jak najmniejszej liczby bajtów.

Oto wymagania:

  • Gra musi być zaimplementowana w typowym dwuwymiarowym układzie. Wąż powinien być zdolny do znacznego wzrostu w granicach mapy (to naprawdę oznacza, nie zmniejszaj mapy za bardzo, skorzystaj z własnego uznania tutaj).
  • Użytkownik może przesunąć węża za pomocą wybranych przez ciebie klawiszy, jednak wąż nie może się podwoić (np. Jeśli jedzie na zachód, nie może lecieć na wschód bez uprzedniej podróży na północ lub południe). Wąż powinien być w stanie podróżować we wszystkich 4 kierunkach: w górę, w dół, w lewo, w prawo (północ, południe, zachód, wschód).
  • Wąż zaczyna się od długości 1, za każdym razem, gdy zjada obiekt „jedzenia”, rośnie o +1
  • Przedmioty żywnościowe są losowo umieszczane w miejscach innych niż te zajmowane przez węża
  • Jeśli Wąż uderzy o siebie lub o ścianę, gra się kończy
  • Po zakończeniu gry wyświetlany jest dosłowny „Wynik: [wynik]”, gdzie [wynik] to liczba artykułów spożywczych zjedzonych podczas gry. Na przykład, jeśli wąż zjadł 4 „pokarmy” (a zatem ma długość 5) po zakończeniu gry, zostanie wydrukowany „Wynik: 4”.
  • Brak algorytmów kompresji, chyba że są one wyraźnie zdefiniowane w kodzie.

Oto moje rozwiązanie, 908 bajtów, 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
możliwe powtórzenie gry „Wąż” w konsoli / terminalu
skopiuj

1
@ kopiuj, niektórzy ludzie nie lubią ograniczać się do terminali.
Griffin,

czy zasada „wąż nie może się wycofać” ma zastosowanie, jeśli wąż ma długość = 1?
Paul Prestidge,

@chron, tak to robi. Przez cały czas węże mogą (naprawdę) obracać się tylko na dwa sposoby, w lewo iw prawo.
mjgpy3

Odpowiedzi:


2

Ruby 1.9 + SDL (341 324 316)

Oto pierwsza próba wersji Ruby przy użyciu biblioteki SDL. Mogę zapisać 6 znaków, jeśli wolno mi załadować bibliotekę SDL za pomocą -rsdlwiersza poleceń zamiast instrukcji 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}

Segmenty węża i kawałki żywności są reprezentowane za pomocą czarnych pikseli, rozmiar siatki wynosi obecnie 32 * 32. Możesz sterować za pomocą klawiszy strzałek (lub dowolnych klawiszy, kod 4 mod indeksuje tablicę kierunkową [LEWO, GÓRA, DÓŁ, ​​PRAWO]). Myślę, że zdecydowanie jest tu miejsce na ulepszenia, szczególnie w oświadczeniu IF sprawdzającym śmierć.

Znacząco poprawiłem to w porównaniu z poprzednią wersją, mam nadzieję, że teraz bardziej pasuje do ducha pytania. Jest jedna rzecz, którą muszę naprawić, aby zachować zgodność ze specyfikacją, a mianowicie to, że jedzenie może obecnie pojawiać się wewnątrz ogona. Naprawiony!

Drukuje wynik na standardowe wyjście po zakończeniu gry.


2

Java, 2343 2239

Nie do końca zwięzłe, ale uważam, że spełnia wszystkie wymagania.

Klasa węża

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

Klasa zarządu

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

Zrzut ekranu

gra w węża w java


Komentarz

Jakiś czas temu odwiedziłem witrynę o nazwie zetcode, która zawiera kilka samouczków dotyczących tworzenia klasycznych gier 2D w Javie. Dostarczony kod jest pod silnym wpływem samouczka, który został udostępniony dla gry Snake ... Myślę, że w tym momencie właśnie zacząłem kodować klasyczne gry i podążałem za samouczkiem na „T”.

Zrobię edycję później i dodam link do pliku wykonywalnego, aby ludzie mogli grać w grę.


EDYCJE

  • 9.09.12: Nie mogę poprawnie załadować obrazów z folderu zasobów. Nadal będę pracować nad tym problemem, próbując udowodnić, że mój kod działa i spełnia wszystkie kryteria pytania.
  • 9/11/12: Mam zamiar kontynuować prace nad pobraniem zdjęć z pliku zasobów. Dodałem zdjęcie dostarczone z samouczka ZetCode.

Świetnie, nie mogę się doczekać, aby spróbować!
mjgpy3

Czy jest link do wykonywalnej trasy :)
Drenai

@BrianBishop Przepraszam stary, nigdy nie zrozumiałem, co robię niepoprawnie z moimi plikami obrazów w pliku zasobów. Wszystko się kompiluje, ale obrazy nigdy się nie wyświetlają.
Rob

2

Bash: 537 533 507 znaków

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

Jak się używa $COLUMNSi $LINESzmienne powłoki, należy uruchomić wczytany: . snake.sh. Węża można kontrolować za pomocą klawiszy w/ a/ s/ d.

Wiem, że można go łatwo zredukować do 493 znaków, używając clearekranu do czyszczenia, ale wolę zachować czystość bash, bez użycia zewnętrznego narzędzia.


Bardzo fajne rozwiązanie!
mjgpy3

1

Python 2.7: 869 816 818 817 816 znaków

Zhakowałem to razem w ciągu ostatnich kilku godzin. Powinien spełniać wymagania i jest o kilka znaków krótszy niż rozwiązanie mjgpy3 (Próbowałem ciężko, ale nie mogłem być znacznie krótszy. Teraz jestem zmęczony). Zaskakujące jest to, że użycie biblioteki do programowania gier, takiej jak pygame, nie skróciło węża pytona. Bardzo cenione są sugestie i porady dotyczące skrócenia. Mam nadzieję, że to nie jest zbyt tajemnicze.

Oto wynik:

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)

EDYCJA: Mógłbym to zmniejszyć do 816 bajtów, tak! :) Naprawiono wynik

EDYCJA 2: Przypadkowo wkleiłem niewłaściwą wersję

Oto skomentowana wersja:

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)

Wciąż pojawiał się komunikat o błędzie „Błąd segmentacji (zrzut rdzenia)”. I wygląda na to, że wynik jest wyłączony o 1 (to naprawdę nie jest wielka sprawa. Bardzo fajna odpowiedź.
mjgpy3 24.09.12

2
Dzięki :) Dostaję też tę wiadomość dotyczącą segmentacji. Jeszcze tego nie rozgryzłem. Naprawiono wynik i zmniejszono rozmiar :) to jest fajne.
stefreak

1
możesz przyciemnić zielony, zamiast 255, użyj 99, wtedy to będzie zdjęty bajt
KrystosTheOverlord

@KrystosTheOverlord hahah tak dobra uwaga: D
stefreak
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.