Понг в найкоротшому коді


28

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

Як завжди, код повинен бути написаний вільною мовою (в обох сенсах) і повинен бути запущений на Linux. Будь-які бібліотеки, що використовуються, також повинні бути безкоштовними, доступними та не писатись для цілей цього змагання (а також не містити робочої версії Pong!).


Чесно кажучи, це питання є занадто складним для кодового гольфу. Фізика м'яча для Понга є досить складною.
beary605

@ beary605, я не думаю, що фізика м'яча занадто складна. Моє рішення - «максимально наближений» до демонстрації javascript, а фізика - досить проста.
виставка

Для довідки є деякі інші [code-golf], які працюють досить довго. Створіть двигун для гри в лабіринті , Noughts and Crosss (він же Tic-Tac-Toe) (обидва могли використовувати додаткові записи, хто любить "виграти" за замовчуванням?), Напишіть невеликий сервер HTTP , Інтерпретатор самоперекладки , Self- збирання компілятора , Compile Regexes ...
dmckee

@felipa, чи можете ви формалізувати "якомога ближче"? Я не знаю, чому моє рішення sed не веде.
кабіна

Відповіді:


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 id="c"width="640"height="480"style="background:#000"></canvas>

Гравець 1 використовує клавіші qі a, а гравець 2 використовує клавіші pі l. Натисніть escклавішу, щоб призупинити, і будь-яку клавішу, щоб почати / продовжити.

Ви можете відтворити його у своєму браузері тут .

Я не був впевнений у використанні фізики, тому почав з простого методу відображення, а потім додав різноманітності та трохи експериментував з цим. На швидкість кулі у напрямку y впливає те, де на весла ви потрапили в м'яч, тож ви маєте деякий контроль над тим, куди йде м'яч. Швидкість м'яча в напрямку x повільно зростає з кожним ударом в ралі.

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


2
Це дійсно приємна реалізація.
felipa

1
Можна було б пограти в гольф трохи більше, я знаю, я тут запізнююся на два роки. але ви можете призначити 20змінну з ім'ям gі зберегти один непомірний байт.
Zacharý

Чорт, важко грати на клавіатурі azerty ...
дим

38

sed, 35

Трохи підняти планку за допомогою медитації поштової марки.

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

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

0         <       1

з нулем гуру зліва та одним праворуч. Кутова дужка рухається вліво і вправо, і якщо гуру маневрує їх кількістю, щоб контактувати з курсором, коли він переходить на їх сторону, їх оцінка збільшується на одиницю, і вони стають піднесеними від радості.

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

Гуру, бажаючи виклику, може грати в режимі "турбо", в якому гуру намагаються спільно передбачити наступний стан комп'ютера і ввести його в підказку замість поточного стану. Гуру матимуть мудрість перевірити згоду між своїми прогнозами, перш ніж вступити у майбутнє.


23
Чувак ... що я щойно прочитав?
MrZander

9
@MrZander Тільки за допомогою широкого споглядання може бути розкрита мудрість медитації. Цьому спогляданню найкраще допомагати шляхом виконання програми.
кабіна

15

Python (з пігамою ) 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. Мені здається дивним, що м'яч може насправді повернутися "назад" (вгору чи вниз) після удару в весло, замість того, щоб продовжувати в тому ж напрямку (можливо, під іншим кутом). Але, можливо, версія Атарі зробила це, я не знаю.
aditsu

@aditsu Це коштувало декількох байтів, але я вважаю, що оцінка повинна бути по центру, незалежно від обраного шрифту (до тих пір, поки він не є просторовим). Дайте мені знати, чи працює це для вас. І так, прогин дуже схожий (хоча плавніший розподіл) на версію Atari, з якою я був знайомий. Якщо ви уявляєте весло як (опукло) вигнуту поверхню (як весло для хокею з повітряним хокеєм), я думаю, воно повинно бути більш інтуїтивним.
примо

Так, це зараз в центрі
aditsu

8

HTML і JavaScript (візьміть 2) - 525

Оскільки ОП, здавалося, не дуже переймається частиною "якомога ближче", ось таке альтернативне рішення, яке я нещадно спростив, роздяг та гольфував. 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 Я припускаю, що ви говорите про мою загальну думку, що ваше рішення не відповідає критерію "максимально наближеного". Ну, в ОП не згадується версія Atari 2600, а конкретна реалізація javascript, з якою він пов’язаний. І на перший погляд у вашому коді є 2 яскраві відмінності: відсутній комп'ютерний програвач і не відображається оцінка 7-сегмента. Напевно, набагато більше відмінностей у "механіці". Якщо ці речі не важливі, я вважаю, що це рішення має бути дійсним.
aditsu

Це моя помилка. Я дійсно мав на увазі "якомога ближче", тож ваше перше рішення - найкраще поки що.
felipa

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

Ви можете зберегти ще 1 персонаж, перемістившись ++S[n]всередину.random(++S[n])
Шміддті

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

Просто дуже мінімальна версія Понга, де м'яч працює лише в діагональних кутах і завжди має однакову швидкість.

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


Не вдалося перевершити: bit.ly/2VSIGz8
sergiol
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.