Tái tạo trò chơi rắn cổ điển


11

Thách thức là tạo ra trò chơi Snake cổ điển bằng cách sử dụng càng ít byte càng tốt.

Dưới đây là các yêu cầu:

  • Trò chơi phải được thực hiện theo bố cục 2 chiều điển hình. Con rắn sẽ có thể phát triển đáng kể trong giới hạn của bản đồ (điều này thực sự có nghĩa là, đừng làm cho bản đồ của bạn quá nhỏ, hãy sử dụng theo ý của bạn ở đây).
  • Người dùng có thể di chuyển con rắn bằng các phím bạn chọn, tuy nhiên, con rắn không thể tự nhân đôi (ví dụ: nếu nó đi về hướng Tây, nó không thể đi về hướng Đông mà không đi về hướng Bắc hoặc Nam). Một con rắn phải có khả năng di chuyển theo cả 4 hướng: lên, xuống, trái, phải (Bắc, Nam, Tây, Đông).
  • Con rắn bắt đầu với chiều dài 1, mỗi lần nó ăn một vật "thức ăn", nó sẽ tăng thêm 1 chiều dài
  • Các đối tượng thực phẩm được đặt ngẫu nhiên ở các vị trí khác ngoài những nơi bị rắn chiếm giữ
  • Nếu con rắn tự đánh hoặc vào tường thì trò chơi kết thúc
  • Khi trò chơi kết thúc, "Điểm: [điểm]" được hiển thị trong đó [điểm] là số lượng thực phẩm được ăn trong trò chơi. Vì vậy, ví dụ, nếu con rắn đã ăn 4 "thức ăn" (và do đó có chiều dài là 5) khi trò chơi kết thúc, "Điểm: 4" sẽ được in.
  • Không có thuật toán nén trừ khi chúng được xác định rõ ràng trong mã của bạn.

Đây là giải pháp của tôi, 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 một số người không muốn bị giới hạn trong các thiết bị đầu cuối.
Griffin

quy tắc 'con rắn không thể nhân đôi trở lại' có áp dụng nếu con rắn có chiều dài = 1 không?
Paul Prestidge

@ sync, đúng vậy. Tại mọi thời điểm, rắn chỉ có thể (thực sự) rẽ theo hai cách, trái và phải.
mjgpy3

Câu trả lời:


2

Ruby 1.9 + SDL (341 324 316)

Đây là lần thử đầu tiên tại phiên bản Ruby sử dụng thư viện SDL. Tôi có thể lưu 6 ký tự nếu tôi được phép tải thư viện SDL bằng -rsdldòng lệnh thay vì câu lệnh yêu cầu.

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}

Các đoạn rắn và miếng thức ăn được thể hiện bằng các pixel đen, kích thước lưới hiện tại là 32 * 32. Bạn có thể điều khiển bằng các phím mũi tên (hoặc bất kỳ phím nào thực sự, mã khóa mod 4 lập chỉ mục mảng hướng [TRÁI, LÊN, XUỐNG, PHẢI]). Tôi nghĩ chắc chắn có chỗ để cải thiện ở đây, đặc biệt là trong tuyên bố IF kiểm tra cái chết.

Tôi đã cải thiện rất nhiều so với phiên bản trước, hy vọng nó phù hợp hơn với tinh thần của câu hỏi bây giờ. Có một điều tôi cần sửa để tuân thủ thông số kỹ thuật, đó là thức ăn hiện có thể sinh sản bên trong đuôi. Đã sửa!

In điểm đến thiết bị xuất chuẩn sau khi trò chơi hoàn thành.


2

Java, 2343 2239

Không chính xác súc tích, nhưng tôi tin rằng nó tuân theo tất cả các yêu cầu.

Lớp rắn

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

Lớp học

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

Ảnh chụp màn hình

trò chơi con rắn trong java


Bình luận

Một thời gian trước, tôi đã truy cập một trang web có tên zetcode cung cấp một số hướng dẫn để tạo các trò chơi 2D cổ điển trong Java. Mã được cung cấp bị ảnh hưởng mạnh mẽ bởi hướng dẫn được cung cấp cho trò chơi Snake ... Tôi nghĩ tại thời điểm này tôi mới bắt đầu viết mã các trò chơi cổ điển và làm theo hướng dẫn đến 'T'.

Tôi sẽ chỉnh sửa sau và thêm một liên kết đến một tệp thực thi để mọi người có thể chơi trò chơi.


EDITS

  • 9/9/12: Tôi không thể tải đúng hình ảnh từ thư mục tài nguyên. Tôi sẽ tiếp tục giải quyết vấn đề này trong nỗ lực chứng minh rằng mã của tôi hoạt động và đáp ứng tất cả các tiêu chí của câu hỏi.
  • 9/11/12: Tôi sẽ tiếp tục làm việc để tải ảnh từ tệp tài nguyên. Tôi đã thêm một hình ảnh được cung cấp từ hướng dẫn ZetCode.

Tuyệt vời, tôi mong được thử nó!
mjgpy3

Có liên kết đến đường thực thi không :)
Drenai

@BrianBishop Xin lỗi anh bạn, tôi chưa bao giờ tìm ra những gì tôi đã làm không đúng với các tệp hình ảnh của tôi trong tệp tài nguyên. Tất cả mọi thứ biên dịch, nhưng hình ảnh không bao giờ bật lên.
Cướp

2

Bash: 537 533 507 ký tự

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

Vì nó sử dụng các biến $COLUMNS$LINESshell, nên nó phải được chạy nguồn : . snake.sh. Con rắn có thể được kiểm soát với các w/ a/ s/ dphím.

Tôi biết, nó có thể dễ dàng giảm xuống 493 ký tự bằng cách sử dụng clearđể xóa màn hình, nhưng tôi thích giữ nó thuần túy bash, không sử dụng bất kỳ công cụ bên ngoài nào.


Giải pháp rất tuyệt!
mjgpy3

1

Python 2.7: 869 816 818 817 816 Ký tự

Tôi đã hack cái này cùng nhau trong vài giờ qua. Nó phải đáp ứng các yêu cầu và ngắn hơn một vài ký tự so với giải pháp của mjgpy3 (Đã thử rất nhiều, nhưng không thể rút ngắn hơn nhiều. Bây giờ tôi mệt). Đáng ngạc nhiên, sử dụng một thư viện phát triển trò chơi như pygame đã không khiến con trăn ngắn hơn nhiều. Gợi ý và lời khuyên làm thế nào để làm cho nó ngắn hơn được đánh giá cao. Tôi hy vọng nó không quá khó hiểu.

Đây là kết quả:

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: Tôi có thể giảm nó xuống còn 816 Byte, yay! :) Đã sửa điểm

EDIT2: Đã dán nhầm phiên bản

Đây là một phiên bản nhận xét:

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)

Tôi liên tục nhận được thông báo lỗi này "Lỗi phân đoạn (lõi bị đổ)." Và có vẻ như điểm số bị giảm đi 1 (không thực sự là vấn đề lớn. Mặc dù vậy, câu trả lời rất tuyệt vời
mjgpy3

2
Cảm ơn :) Tôi cũng nhận được thông báo Phân đoạn fauklt. Chưa tìm ra nó. Đã sửa điểm và giảm kích thước :) đây là niềm vui.
stefreak

1
bạn có thể làm cho màu xanh đậm hơn, thay vì 255, sử dụng 99, thì đó sẽ là một byte bị loại bỏ
KrystosTheOverlord

@KrystosTheOverlord hahah vâng điểm tốt: D
stefreak 22/03/19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.