고전적인 뱀 게임을 재현 키를 사용하여 뱀을 움직일

문제는 가능한 적은 바이트를 사용하여 클래식 스네이크 게임을 만드는 것입니다.

요구 사항은 다음과 같습니다.

  • 게임은 일반적인 2 차원 레이아웃으로 구현해야합니다. 뱀은지도의 경계 내에서 크게 자랄 수 있어야합니다 (이것은 실제로지도를 너무 작게 만들지 말고 여기에 재량을 사용하십시오).
  • 사용자는 원하는 키를 사용하여 뱀을 움직일 수 있지만, 뱀은 다시 두 배로 돌아올 수 없습니다 (예 : 서쪽으로 가면 먼저 북쪽이나 남쪽으로 가지 않고 동쪽으로 갈 수 없음). 뱀은 위, 아래, 왼쪽, 오른쪽 (북쪽, 남쪽, 서쪽, 동쪽)의 네 방향으로 모두 이동할 수 있어야합니다.
  • 뱀은 길이 1로 시작합니다. “음식”물체를 먹을 때마다 길이가 +1로 자랍니다.
  • 음식물은 뱀이 차지하는 곳 이외의 장소에 무작위로 배치됩니다.
  • 뱀이 벽에 부딪 히거나 벽에 부딪 치면 게임이 종료됩니다
  • 게임이 끝나면 문자 “Score : [score]”가 표시됩니다. 여기서 [score]는 게임 중에 먹는 음식 수입니다. 예를 들어, 게임이 끝났을 때 뱀이 4 개의 “음식”을 먹었고 (따라서 길이가 5 인 경우) “점수 : 4″가 인쇄됩니다.
  • 코드에 명시 적으로 정의되어 있지 않으면 압축 알고리즘이 없습니다.

내 해결책은 908 바이트, 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.9 + SDL (341 324 316)

다음은 SDL 라이브러리를 사용한 Ruby 버전의 첫 번째 시도입니다. -rsdlrequire 문 대신 명령 줄을 사용하여 SDL 라이브러리를로드 할 수 있으면 6자를 저장할 수 있습니다 .

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}

뱀 세그먼트와 음식 조각은 검은 픽셀을 사용하여 표시되며 격자 크기는 현재 32 * 32입니다. 화살표 키를 사용하여 제어 할 수 있습니다 (또는 모든 키는 실제로 키 코드 mod 4가 방향 배열 [LEFT, UP, DOWN, RIGHT]을 인덱싱합니다). 특히 사망 확인 IF 문에서 개선의 여지가 있다고 생각합니다.

나는 이전 버전에 비해 이것을 크게 개선했으며, 현재 질문의 정신과 더 밀접하게 일치하기를 바랍니다. 사양을 준수하기 위해 수정해야 할 한 가지 사항이 있습니다. 즉, 음식이 현재 꼬리 안에 생성 될 수 있습니다. 결정된!

게임이 완료된 후 점수를 표준 출력으로 인쇄합니다.


답변

자바, 2343 2239

정확히 간결하지는 않지만 모든 요구 사항을 준수한다고 생각합니다.

스네이크 클래스

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

보드 클래스

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

스크린 샷


해설

얼마 전 나는 자바로 클래식 2D 게임을 만드는 튜토리얼을 제공하는 zetcode 라는 웹 사이트를 방문했다 . 제공된 코드 는 스네이크 게임을 위해 제공된 튜토리얼의 영향을 많이받습니다 …이 시점에서 방금 클래식 게임을 코딩하기 시작했고 튜토리얼을 ‘T’로 따랐습니다.

사람들이 게임을 할 수 있도록 나중에 편집하고 실행 파일에 대한 링크를 추가하겠습니다.


EDITS

  • 9/9/12 : 리소스 폴더에서 이미지를 제대로로드 할 수 없습니다. 내 코드가 작동하고 질문의 모든 기준을 충족한다는 것을 증명하기 위해이 문제를 계속 진행할 것입니다.
  • 9/11/12 : 리소스 파일에서 사진을로드하는 작업을 계속하겠습니다. ZetCode 튜토리얼에서 제공 한 그림을 추가했습니다.

답변

강타 : 537 533 507 자

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

$COLUMNS$LINES셸 변수를 사용하므로 sourced를 실행해야합니다 . snake.sh. 뱀은 w/ a/ s/ d키로 제어 할 수 있습니다 .

clear화면을 지우려면 을 사용하여 쉽게 493 자로 줄일 수 있지만 bash외부 도구를 사용하지 않고 순수하게 유지하는 것을 선호합니다 .


답변

파이썬 2.7 : 869 개 816 818 817 816 문자

지난 몇 시간 동안 함께 해킹했습니다. 요구 사항을 충족해야하며 mjgpy3의 솔루션보다 몇 자 더 짧습니다 (열심히 시도했지만 더 짧게 만들 수 없었습니다. 이제 피곤합니다). 놀랍게도, pygame과 같은 게임 개발 라이브러리를 사용하면 파이썬 뱀이 훨씬 짧아지지 않았습니다. 짧게 만드는 방법에 대한 제안과 팁은 높이 평가됩니다. 나는 그것이 너무 비밀스럽지 않기를 바랍니다.

결과는 다음과 같습니다.

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)

편집 : 나는 그것을 816 바이트로 줄일 수 있습니다. 🙂 점수를 수정

EDIT2 : 실수로 잘못된 버전을 붙여 넣었습니다.

다음은 주석 처리 된 버전입니다.

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)