Понг в самом коротком коде


28

Задача проста. Дайте кратчайший код, который можно воспроизвести в классической игре понг для 2 игроков http://en.wikipedia.org/wiki/Pong . Уровень графики и функциональности должен быть как можно ближе к этой демонстрации JavaScript http://codeincomplete.com/posts/2011/5/14/javascript_pong/demo.html (но без дополнительных опций вы можете нажать слева или информация о кадре, кадрах и т. д. справа внизу).

Как всегда, код должен быть написан на свободном языке (в обоих смыслах) и должен быть запущен на Linux. Любые используемые библиотеки также должны быть бесплатными, легкодоступными и не должны быть написаны для целей этого конкурса (а также еще не должны содержать рабочую версию Pong!).


Честно говоря, этот вопрос слишком сложен для кода гольфа. Физика мяча для Понга довольно сложна.
beary605

@ beary605, я не думаю, что физика мяча слишком сложна. Мое решение «как можно ближе» к демонстрации JavaScript, и физика довольно проста.
Boothby

Просто для справки есть некоторые другие [code-golf], которые работают довольно долго. Построить двигатель для лабиринте игры , крестики и нолики (ака Tic-Tac-Toe) (оба может использовать дополнительные элементы, которые любят «выиграть» по умолчанию?) Написать небольшой HTTP - сервер , Self-Interpreting переводчик , самодекогерирует компиляции компилятор , Compile Регулярные выражения ...
dmckee

@felipa, вы можете формализовать «как можно ближе»? Я не знаю, почему мое решение sed не лидирует.
Boothby

Ответы:


24

Javascript, 883 (+ 70 HTML)

c=document.getElementById('c').getContext('2d')
c.fillStyle="#FFF"
c.font="60px monospace"
w=s=1
p=q=a=b=0
m=n=190
x=300;y=235
u=-5;v=3
setInterval(function(){if(w&&!s)return;s=0
c.clearRect(0,0,640,480)
for(i=5;i<480;i+=20)c.fillRect(318,i,4,10)
m+=p;n+=q
m=m<0?0:m;m=m>380?380:m
n=n<0?0:n;n=n>380?380:n
x+=u;y+=v
if(y<=0){y=0;v=-v}
if(y>=470){y=470;v=-v}
if(x<=40&&x>=20&&y<m+110&&y>m-10){u=-u+0.2;v+=(y-m-45)/20}
if(x<=610&&x>=590&&y<n+110&&y>n-10){u=-u-0.2;v+=(y-n-45)/20}
if(x<-10){b++;x=360;y=235;u=5;w=1}
if(x>640){a++;x=280;y=235;u=-5;w=1}
c.fillText(a+" "+b,266,60)
c.fillRect(20,m,20,100)
c.fillRect(600,n,20,100)
c.fillRect(x,y,10,10)},30)
document.onkeydown=function(e){k=(e||window.event).keyCode;w=w?0:k=='27'?1:0;p=k=='65'?5:k=='81'?-5:p;q=k=='40'?5:k=='38'?-5:q;}
document.onkeyup=function(e){k=(e||window.event).keyCode;p=k=='65'||k=='81'?0:p;q=k=='38'||k=='40'?0:q}


/* Variable index:
a -> left player score
b -> right player score
c -> context
e -> event
i -> counter for dashed line
k -> keycode
m -> left paddle y
n -> right paddle y
p -> left paddle y velocity
q -> right paddle y velocity
s -> is start of game
u -> ball x velocity
v -> ball y velocity
w -> game is waiting (paused)
x -> ball x
y -> ball y
*/

Сценарий может быть размещен в конце <body>или вызван onLoad. Для этого нужен следующий элемент canvas:

<canvas id="c"width="640"height="480"style="background:#000"></canvas>

Игрок 1 использует qи aключи, и игрок 2 использует pи lключи. Нажмите escклавишу, чтобы приостановить и любую клавишу, чтобы начать / продолжить.

Вы можете воспроизвести его в своем браузере здесь .

Я не был уверен, какую физику использовать, поэтому я начал с простого метода отражения, а затем добавил немного разнообразия и немного поэкспериментировал с ним. На скорость мяча в направлении y влияет то, где на мяче вы ударили по мячу, поэтому вы можете контролировать направление движения мяча. Скорость мяча в направлении х медленно увеличивается с каждым попаданием в ралли.

Я подозреваю, что это будет довольно легко преодолевать решениями, использующими библиотеки, но мне было приятно делать это простым javascript.


2
Это действительно хорошая реализация.
Фелипа

1
Может быть, еще немного в гольфе, я знаю, что опаздываю на два года но вы можете присвоить 20переменной имя gи сохранить один мизерный байт.
Захари

Черт, трудно играть на клавиатуре azerty ...
dim

38

Сед, 35

Немного поднять планку с помощью медитации «почтовая марка».

s/> / >/
s/ </< /
s/0</0>/
s/>1/<1/

Медитация используется на stdin / stdout на двух компьютерах, не обязательно связанных сетью. Медитация начинается в состоянии

0         <       1

с гуру ноль слева и один справа. Угловая скобка перемещается влево и вправо, и если гуру маневрирует своим числом, чтобы соприкасаться с курсором, когда он приближается к их стороне, их счет увеличивается на единицу, и они радуются.

Медитация начинается с ввода вышеуказанного состояния sed -f medi.sed, и компьютер отвечает следующим состоянием. Послушные гуру вводят в медитацию, читая вслух следующую клавишу, которую они нажимают, и оба гуру одновременно нажимают святой ключ к enterбудущему. Послушный компьютер отвечает следующим состоянием. Это, в свою очередь, читается вслух, когда печатается в унисон, как и в случае с последним. Продолжайте двигаться в будущее, пока не будет достигнуто бесконечное блаженство.

Гуру, желающие получить вызов, могут играть в «турбо» режиме, когда гуру пытаются совместно предсказать следующее состояние компьютера и вводят его в подсказку вместо текущего состояния. Гуру хватит мудрости проверить соответствие между их предсказаниями, прежде чем войти в будущее.


23
Чувак ... что я только что прочитал?
MrZander

9
@MrZander Только через обширное созерцание можно раскрыть мудрость медитации. Это созерцание лучше всего помогает при выполнении программы.
Стенд

15

Python (с pygame ) 650 байт

особенности

  • Режимы 1 и 2 игроков - Когда начинается игра, нажмите 1для 1 игрока или 2для 2 игроков. Игра не начнется, пока не будет нажата одна из этих клавиш.
  • Увеличение скорости мяча - каждый залп, скорость мяча увеличивается так, что после 10 залпов он увеличивается примерно на 50%, после 20 он будет на 50% быстрее, чем этот, и т. Д.
  • Переменное отклонение шарика - отклонение шарика основано на двух факторах: на какую часть лопасти он ударяется и движется ли лопасть при ударе. Если мяч ударит по веслу около одного из концов, он будет отклоняться сильнее, чем если бы он ударил около середины (почти как изогнутая поверхность). Кроме того, если весло находится в движении, движение весла добавляется к отклонению. Чтобы получить самое сильное отклонение, шар должен ударить около конца весла, и весло должно двигаться к тому же концу. Это очень похоже на оригинальный Понг для Atari 2600.
  • Пауза - игра может быть приостановлена ​​в любое время нажатием на кнопку Space. Игра возобновится после повторного нажатия клавиши пробела.
  • Органы управления - Как и в примере, игрок 1 движется с Qи Aключей, а игрок 2 перемещается с Pи L.

В заключение, я хотел бы просить, чтобы это решение не было выбрано в качестве принятого ответа по разным причинам.

from pygame import*
init();d=display;s=d.set_mode((640,480))
g=p=16;j=q=80;x=y=200;o=t=h=v=1;z=m=n=0;w=[255]*3
while s.fill(time.wait(3)):
 event.get();k=key.get_pressed();t^=o*k[32];o=1-k[32];z=z or-k[49]-k[50]*2;e=k[113]-k[97];f=[k[112]-k[108],(h>0)*cmp(y,q-32)][z];a=p<g;b=q-[y,x][a]
 if p%608<g:m,n,p,h,v=[m+1-a,m,n+a,n,g+a*592,p,1-a*2,h/-.96,1,b/32.+~[f,e][a]][-g<b<j::2]
 for r in[(0,x,g,j),(624,y,g,j),(p,q,g,g)]+[(316,i*31,8,15)for i in range(g)]:draw.rect(s,w,r)
 if z*t:v*=(0<q<464)*2-1;x-=(0<x-e<400)*e/.6;y-=(0<y-f<400)*f/.6;p+=h;q+=v
 c=font.SysFont('monospace',j,1).render('%3d %%-3d'%m%n,1,w);s.blit(c,(320-c.get_width()/2,0));d.flip()

Пример снимка экрана:

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


Счет показывает в левой половине для меня, и я думаю, что отклонение слишком сильное, но это все равно довольно круто :)
aditsu

@aditsu вы работаете под Linux? Я посмотрю, смогу ли я найти альтернативу, которая работает независимо от выбранного шрифта лица. Идея отклонения заключается в том, что можно было бы отклонить мяч с более высокой скоростью (максимум 2,5 по моей шкале), чем весло может двигаться ( 1,67 ). Это возможно только в том случае, если вы дадите ему немного «вращения». Если весло не движется при ударе мяча, максимальная скорость будет 1,5 .
Примо

Да, я использую Linux. Я нахожу странным, что мяч может на самом деле вернуться назад (вверх или вниз) после удара по веслу, вместо того, чтобы продолжать движение в том же направлении (возможно, под другим углом). Но, возможно, версия Atari сделала это, я не знаю.
aditsu

@aditsu Это стоит несколько байтов, но я считаю, что счет должен быть центрирован независимо от выбранного шрифта (при условии, что он моноширинный). Дайте мне знать, если это работает для вас. И да, отклонение очень похоже (хотя и более плавное распределение) на версию Atari, с которой я был знаком. Если вы представляете весло как (выпукло) изогнутую поверхность (например, ракетку для аэрохоккея), я думаю, она должна быть более интуитивной.
Примо

Да, это по центру
aditsu

8

HTML & JavaScript (дубль 2) - 525

Поскольку OP, кажется, не особо заботился о «как можно ближе», вот альтернативное решение, которое я безжалостно упростил, раздевал и играл в гольф. Q / A и P / L, чтобы играть, но любая другая клавиша также имеет эффект. Опять же, код полностью автономен, и я протестировал его в Chromium 25 для Linux. Я могу сыграть в эту игру еще дальше, если вы допустите небольшие ошибки или еще большее ухудшение качества графики / игрового процесса.

<canvas id=c><script>C=c.getContext('2d');f=C.fillRect.bind(C)
S=[-1,I=J=0];A=B=210;X=Y=1
function g(n){++S[n];N=Math.random(M=n*613+9)*471}D=document
D.onkeydown=D.onkeyup=function(e){d=!!e.type[5];k=e.keyCode
k&1?I=k&16?d:-d:J=k&4?-d:d}
g(0);setInterval(function(){A-=A<I|A>420+I?0:I
B-=B<J|B>420+J?0:J
M+=X;N+=Y
N<0|N>471?Y=-Y:0
M==622&N>B&N<B+51|M==9&N>A&N<A+51?X=-X:M>630?g(0):M||g(1)
f(0,0,c.width=640,c.height=480)
C.fillStyle='tan';C.font='4em x';C.fillText(S,280,60)
f(0,A,9,60);f(631,B,9,60);f(M,N,9,9)},6)</script>

Спасибо Шмиддты


Я не понимаю возражения. Насколько я помню, 715-байтовая версия (отредактированная за 3 часа до этого поста) практически идентична оригинальной версии Pong, которую я имел для своего Atari 2600.
primo

@primo Я предполагаю, что вы говорите о моем подразумеваемом утверждении, что ваше решение не соответствует критерию "как можно ближе". Ну, OP не упомянул версию Atari 2600, но конкретную реализацию javascript, с которой он связался. И на первый взгляд, в вашем коде есть 2 явных различия: нет компьютерного плеера и нет отображения «7-сегментного» счета. Вероятно, есть намного больше различий в «механике». Если эти вещи не важны, то я думаю, что это решение также должно быть действительным.
aditsu

Это моя ошибка. Я действительно имел в виду «как можно ближе», поэтому ваше первое решение пока лучшее.
Фелипа

Вы можете удалить c=window.c. Вы назначаете глобальную переменную себе.
Шмиддти

Вы можете сохранить еще 1 персонажа, переместившись ++S[n]внутрь.random(++S[n])
Shmiddty

5

HTML & JavaScript - 1663

Вопреки здравому смыслу, я использовал сумасшедший подход к игре в реальном коде из демо Я удалил некоторые функции и элементы интерфейса, но в целом он работает точно так же - 0, 1 или 2, чтобы выбрать количество игроков, Q / A и P / L для перемещения.

Если я не допустил некоторых ошибок, игровой процесс должен быть идентичным, пиксель за пиксель и миллисекунда за миллисекунду, оригиналу при 640 * 480 (подсказка: изменение размера окна браузера изменяет размер игры в демоверсии). Он просто не дает инструкций, не объявляет победителя и не обрабатывает esc.

Код полностью автономен, и я протестировал его в Chromium 25 на Linux. Firefox это не очень нравится.

<body bgcolor=0><canvas id=c height=480><script>R=Math.random
C=c.getContext('2d');f=C.fillRect.bind(C)
S=[l=G=I=J=K=L=0,0];r=17;u=463;o=24;q=12;z=10;s=640;v=36
function T(z,t,u,v){P=0;if(e=v*E-u*F){a=(u*t-v*z)/e;b=(E*t-F*z)/e
a<0|a>1|b<0|b>1?0:P={x:M+a*E,y:N+a*F,d:u,s:0,X:X,Y:Y}}}function
i(p,q,h){T(p-22*(E<0),q,0,h)
P?0:T(p,q-h*(F<0),22,0)}function
U(p){if(p.a)if(M<p.x&X<0|M>p.x+q&X>0)p.u=0
else{P=p.P;if(P&&P.X*X>0&P.Y*Y>0&P.s<p.l/z)P.s+=t
else{E=X*z;F=Y*z;i(M-p.x+5,s*q,s*o)
if(p.P=P){y=P.y;while(y<r|y>u)y=y<r?34-y:y>u?u+u-y:y
P.y=y+R(e=(p.l+2)*(X<0?M-p.x-q:p.x-M)/64)*2*e-e}}P?p.u=P.y<p.y+25?1:P.y>p.y+35?-1:0:0}y=p.y-p.u*t*198
p.y=y<q?q:y>408?408:y}function
W(n,x){a=9.6;b=[~8,3,62,31,75,93,~2,7,-1,u][n]
b&4&&f(x,o,v,a);b&64&&f(x,o,a,o)
b&2&&f(x+v,o,-a,o);b&8&&f(x,43.2,v,a)
b&32&&f(x,48,a,o);b&1&&f(x+v,48,-a,o)
b&16&&f(x,72,v,-a)}A={u:0,x:0,y:210};B={u:0,x:628,y:210}
function g(n){if(++S[n]>8)G=A.a=B.a=0
else{N=R(M=n?635:5)*446+r;Y=157.5;X=n?-Y:Y
A.l=z+S[0]-S[1];B.l=20-A.l}}D=document
D.onkeydown=D.onkeyup=function(e){d=!!e.type[5]
k=e.keyCode-45;if(k>2&k<6&d&!G){G=S=[-1,0];A.a=k<4;B.a=k<5
g(0)}k^31?k^35?k^20?k^v?0:I=d:J=d:K=d:L=d
A.a?0:A.u=I-J;B.a?0:B.u=K-L}
setInterval(function(){t=new Date()/1000-l;l+=t;U(A);U(B)
if(G){E=t*X+4*t*t;F=t*Y+4*t*t
x=M+E;y=N+F;m=X+t*(X>0?8:-8);n=Y+t*(Y>0?8:-8)
if(n>0&y>u){y=u;n=-n}if(n<0&y<r){y=r;n=-n}p=m<0?A:B
i(M-p.x+5,N-p.y+5,70)
if(P){if(P.d){y=P.y;n=-n}else{x=P.x;m=-m}n*=n*p.u<0?.5:p.u?1.5:1}M=x;N=y
X=m;Y=n;M>645?g(0):M<-5&&g(1)}c.width=s;C.fillStyle='#fff'
f(0,0,s,q);f(0,468,s,q);for(j=o;j--;)f(314,6+o*j,q,q)
W(S[0],266.5);W(S[1],338.5)
f(0,A.y,q,60);f(s,B.y,-q,60);G&&f(M-5,N-5,z,z)},50/3)</script>

Некоторые кредиты Шмиддты за улучшения


4

Обработка, 487 символов

int a=320,b=240,c=2,d=2,e=0,f=0,g=0,h=0,i=15,j=80,k=640,
l=160,m;void setup(){size(k,b*2);}void draw(){background
(0);if(keyPressed){if(key=='q'&&g>0)g-=i;if(key=='a'&&g<
j*5)g+=i;if(key=='o'&&h>0)h-=i;if(key=='l'&&h<j*5)h+=i;}
rect(0,g,i,j);for(m=0;m<k;m+=30)rect(312,m,i,i);rect(a,b
,i,i);rect(625,h,i,j);a+=c;b+=d;c*=a<i&&(b>g&&b+i<g+j)||
a>610&&(b>h&&b+i<h+j)?-1:1;d*=b<0||b>=465?-1:1;if(a<0){f
++;a=0;b=240;c=2;}if(a>k){e++;a=625;b=240;c=-2;}textSize
(j);text(e,l,j);text(f,3*l,j);}

Пример скриншота:

введите описание изображения здесь

Этот код был сделан с учетом краткости, поэтому он довольно глючный (мяч иногда проходит через весло или оборачивается вокруг него). Управление Q / A для игрока 1 и O / L для игрока 2.


1
Как игра, ваша версия Pong также кажется довольно несправедливой, так как в каждом кадре регистрируется только один ключ игрока: P
Джонатан Фрех

2

C # - 1283 символа

Это может быть в гольф немного больше, но здесь это так.

using System;using System.Drawing;using System.Runtime.InteropServices;using System.Windows.Forms;using r=System.Drawing.RectangleF;namespace f{public partial class f:Form{public f(){InitializeComponent();}private void f_Load(object sender,EventArgs e){var t=this;var s=new r(0,0,300,300);var q=new r(0,0,15,50);var o=new r(0,0,15,50);var x=new PointF(150,150);var v=.06F;var h=v;var b=new r(x.X,x.Y,15,15);var p1=0;var p2=0;var p=new PictureBox{Size=t.Size,Location=new Point(0,0)};t.Controls.Add(p);p.Paint+=(wh,n)=>{var g=n.Graphics;Action<Brush,r>f=g.FillRectangle;var k=new SolidBrush(Color.Black);var w=new SolidBrush(Color.White);var d=new byte[256];GetKeyboardState(d);var l=q.Location;var _1=.1F;q.Location=new PointF(0,d[90]>1?l.Y+_1:d[81]>1?l.Y-_1:l.Y);l=o.Location;o.Location=new PointF(269,d[77]>1?l.Y+_1:d[79]>1?l.Y-_1:l.Y);f(k,s);f(w,q);f(w,o);Func<r,bool>i=b.IntersectsWith;h=i(q)||i(o)?-h:h;v=b.Top<1||b.Bottom>t.Height-30?-v:v;b.Offset(h,v);if(b.Left<0){p2++;b.Location=x;}if(b.Right>290){p1++;b.Location=x;}f(w,b);for(int j=0;j<19;)f(w,new r(140,(j+(j++%2))*15,10,10));var a=new Font("Arial",20);g.DrawString(p1.ToString(),a,w,100,12);g.DrawString(p2.ToString(),a,w,170,12);p.Invalidate();};}[DllImport("user32.dll")]static extern bool GetKeyboardState(byte[]s);}}

Редактировать: не видел требования для свободного, Linux-запускаемый язык ...


2

Tcl / Tk , 932 байта

Должен быть запущен в интерактивной оболочке

gri [can .c -w 1024 -he 768 -bg #000]
proc A {} {set ::v [expr (int(rand()*36)+1)*20]}
proc R {C t\ X} {.c cr r $C -f #aaa -t $t}
proc I {} {incr ::v 20}
time {R "504 [I] 520 [I]"} 18
R "0 0 1024 20"
R "0 748 1024 768"
R "0 340 20 440" b
R "1004 340 1024 440" B
R "40 [A] 60 [I]" P
lmap n 4\ 5 T F\ S {.c cr t ${n}62 60 -ta $T -te 0 -fi #aaa -font {"" 56}}
proc C t\ n {lindex [.c coo $t] $n}
lmap {a b c d e} {q b 1 >20 -20 a b 3 <740 20 p B 1 >20 -20 l B 3 <740 20} {bind . $a "if \[C $b $c]$d {.c move $b 0 $e}"}
lassign {0 0 20 20} F S y x
proc M {} {lmap {_ a b c d e f} {0 <40 b 20 S 960 980 2 >984 B -20 F 80 100} {if [C P $_]$a {if [C P 1]>=[C $b 1]&&[C P 3]<=[C $b 3] {bell
set ::x $c} {.c itemco $d -te [incr ::$d]
if \$::$d>8 {tk_messageBox -message WINNER!
lmap T F\ S {.c itemco $T -te [set ::$T 0]}}
.c coo P $e [A] $f [I]}}}
.c move P $::x [set ::y [expr [C P 1]<40?20:[C P 3]>727?-20:$::y]]
after 99 M}
M
focus -f .

Заметка:

 #There is an Enter at the end

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

введите описание изображения здесь


Неудачный outgolf: bit.ly/2VSIGz8
sergiol
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.