Воссоздать классическую игру змея


11

Задача состоит в том, чтобы создать классическую игру Snake, используя как можно меньше байтов.

Вот требования:

  • Игра должна быть реализована в типичном двухмерном макете. Змея должна иметь возможность значительно расти в пределах карты (это действительно означает, что не делайте вашу карту слишком маленькой, используйте ваше усмотрение здесь).
  • Пользователь может перемещать змею с помощью клавиш по вашему выбору, однако змея не может сдвинуться назад сама (например, если она идет на запад, она не может идти на восток, не пройдя сначала на север или юг). Змея должна быть в состоянии путешествовать во всех четырех направлениях: вверх, вниз, влево, вправо (север, юг, запад, восток).
  • Змея начинается с длины 1, каждый раз, когда она ест «пищевой» объект, она увеличивается на +1 в длину
  • Объекты питания случайным образом размещаются в местах, отличных от тех, которые заняты змеей
  • Если Змея ударит себя или стену, игра окончена
  • Когда игра закончена, отображается буквально «Счет: [счет]», где [счет] - это количество продуктов, съеденных во время игры. Так, например, если к концу игры змея съела 4 «еды» (и, следовательно, имеет длину 5), будет напечатано «Score: 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
@ Копировать Некоторые люди не любят быть ограниченным терминалами.
Гриффин

применимо ли правило «змея не может сдвинуть назад», если змея имеет длину 1?
Пол Престиж

@chron, да, это так. Во все времена змеи могут (только) поворачиваться только в двух направлениях - влево и вправо.
mjgpy3

Ответы:


2

Ruby 1.9 + SDL (341 324 316)

Вот первая попытка версии Ruby с использованием библиотеки SDL. Я могу сохранить 6 символов, если мне разрешено загружать библиотеку SDL с помощью -rsdlкомандной строки вместо оператора 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}

Сегменты змей и кусочки пищи представлены черными пикселями, размер сетки в настоящее время составляет 32 * 32. Вы можете управлять с помощью клавиш со стрелками (или любых других клавиш, код клавиши mod 4 индексирует массив направлений [ВЛЕВО, ВВЕРХ, ВНИЗ, ВПРАВО]). Я думаю, что здесь определенно есть место для улучшения, особенно в заявлении IF о проверке смерти.

Я значительно улучшил это по сравнению с предыдущей версией, надеюсь, теперь он более соответствует духу вопроса. Есть одна вещь, которую я должен исправить, чтобы соответствовать спецификации, - это то, что еда в настоящее время может появляться внутри хвоста. Исправлена!

Печатает счет в стандартный вывод после завершения игры.


2

Ява, 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


Комментарий

Некоторое время назад я посетил веб-сайт под названием zetcode, на котором были представлены некоторые учебные пособия по созданию классических 2D-игр на Java. На предоставленный код сильно повлияло учебное пособие, которое было предоставлено для игры Snake ... Я думаю, что в то время я только начал писать классические игры и следовал за учебником до буквы «Т».

Позже я сделаю правку и добавлю ссылку на исполняемый файл, чтобы люди могли играть в игру.


редактирует

  • 9.09.12: Я не могу правильно загрузить изображения из папки ресурсов. Я продолжу прорабатывать эту проблему, пытаясь доказать, что мой код работает и соответствует всем критериям вопроса.
  • 9/11/12: я собираюсь продолжить работу над загрузкой изображений из файла ресурсов. Я добавил картинку из учебника по 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переменные оболочки, он должен быть запущен источниками: . snake.sh. Змеей можно управлять с помощью клавиш w/ a/ s/ d.

Я знаю, что его можно легко уменьшить до 493 символов с помощью clearочистки экрана, но я предпочитаю держать его в чистоте 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
Спасибо :) Я тоже получаю это сообщение Segmentation fauklt. Пока не понял. Исправил счет и уменьшил размер :) это весело.
Stefreak

1
Вы можете сделать зеленый темнее, вместо 255, использовать 99, тогда это будет снятый байт
KrystosTheOverlord

@KrystosTheOverlord хахах да хорошая мысль: D
Stefreak
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.