古典的なヘビゲームを再作成する


11

課題は、できるだけ少ないバイトを使用して古典的なSnakeゲームを作成することです。

要件は次のとおりです。

  • ゲームは一般的な2次元レイアウトで実装する必要があります。ヘビは、マップの境界内で大きく成長できるはずです(これは、実際には、マップを小さくしすぎず、ここであなたの裁量を使用することを意味します)。
  • ユーザーは、選択したキーを使用してヘビを動かすことができますが、ヘビは自分自身を元に戻すことはできません(たとえば、西に行く場合、最初に北または南に行かなければ東に行くことはできません)。ヘビは、上、下、左、右(北、南、西、東)の4方向すべてに移動できる必要があります。
  • ヘビは長さ1から始まり、「食品」オブジェクトを食べるたびに長さが+1増加します
  • 食べ物のオブジェクトは、ヘビが占有している場所以外の場所にランダムに配置されます
  • ヘビが自分自身または壁に当たった場合、ゲームは終了します
  • ゲームが終了すると、「スコア:[スコア]」という文字列が表示されます。[スコア]は、ゲーム中に食べた食品の数です。そのため、たとえば、ゲームの終了時にヘビが4つの「食べ物」を食べた(したがって5の長さを持っている)場合、「Score:4」が印刷されます。
  • コードで明示的に定義されていない限り、圧縮アルゴリズムはありません。

これが私のソリューション、908 Bytes、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は、端末に制限されることを好まない人もいます。
グリフィン

ヘビの長さが1の場合、「ヘビはダブルバックできない」というルールが適用されますか?
ポール・プレスティッジ

@chron、はい。常に、ヘビは(真に)左右の2方向にしか回転できません。
mjgpy3

回答:


2

Ruby 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は方向配列にインデックスを付けます[左、上、下、右])。私はここで、特に死をチェックするIFステートメントで、間違いなく改善の余地があると思います。

私はこれを以前のバージョンよりも大幅に改善しました。できれば今の質問の精神により近いものにしたいです。 仕様に準拠するために修正する必要があるものが1つあります。それは、現在、食物が尾の内部に発生する可能性があるということです。 修繕!

ゲームの完了後にスコアを標準出力に出力します。


2

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

スクリーンショット

Javaでのヘビゲーム


解説

しばらく前に、Javaで古典的な2Dゲームを作成するためのチュートリアルを提供するzetcodeというWebサイトにアクセスしました。提供されるコードは、Snakeゲーム用に提供されたチュートリアルの影響を強く受けてます。この時点で、古典的なゲームのコーディングを開始し、チュートリアルに従って「T」にしたと思います。

後で編集し、実行可能ファイルへのリンクを追加して、人々がゲームをプレイできるようにします。


編集

  • 9/9/12:リソースフォルダから画像を適切にロードできません。私のコードが機能し、質問のすべての基準を満たしていることを証明するために、引き続きこの問題に取り組みます。
  • 2012年9月11日:リソースファイルから写真を読み込む作業を続けます。ZetCodeチュートリアルから提供された画像を追加しました。

よろしくお願いします!
mjgpy3

実行中の実行可能ファイルへのリンクはありますか?)
Drenai

@BrianBishop申し訳ありませんが、リソースファイル内の画像ファイルで間違って何をしていたのか、私は理解できませんでした。すべてがコンパイルされますが、画像はポップアップしません。
ロブ

2

Bash: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外部ツールを使用せずに純粋に保つことを好みます。


非常にクールなソリューション!
mjgpy3

1

Pythonの2.7:869の 816 818 817 816文字

過去数時間でこれを一緒にハックしました。要件を満たす必要があり、mjgpy3のソリューションよりも数文字短くなっています(一生懸命試しましたが、もっと短くすることができませんでした。今は疲れています)。驚いたことに、pygameのようなゲーム開発ライブラリを使用しても、python-snakeはそれほど短くなりませんでした。短くする方法の提案とヒントは大歓迎です。私はそれがあまりにも不可解でないことを願っています。

これが結果です:

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)

このエラーメッセージ「セグメンテーションエラー(コアダンプ)」が引き続き表示されます。そして、スコアは1ずれているように見えます(実際には大したことではありません。非常にクールな答えです
。– mjgpy3

2
ありがとう:)私はそのセグメンテーションfaukltメッセージも受け取ります。まだわかりませんでした。スコアを修正し、サイズを縮小しました:)これは楽しいです。
-stefreak

1
あなたは255の代わりに緑をより暗くすることができ、99を使用すると、それは1バイト
削除

@KrystosTheOverlord haha​​hはい良い点:D
stefreak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.