Pong w najkrótszym kodzie

28

Wyzwanie jest proste. Podaj możliwie najkrótszy kod, aby odtworzyć klasyczną grę w ponga dla dwóch graczy http://en.wikipedia.org/wiki/Pong . Poziom grafiki i funkcjonalności powinien być jak najbardziej zbliżony do tej demonstracji javascript http://codeincomplete.com/posts/2011/5/14/javascript_pong/demo.html (ale bez dodatkowych opcji można kliknąć po lewej stronie lub informacje o ramce, fps itp. w prawym dolnym rogu).

Jak zawsze kod musi być napisany w wolnym języku (w obu zmysłach) i powinien być dostępny na Linuksie. Wszelkie używane biblioteki muszą być również bezpłatne, łatwo dostępne i nie mogą być napisane na potrzeby tego konkursu (a także nie mogą zawierać jeszcze działającej wersji Ponga!).

Felipa
źródło
Szczerze mówiąc, to pytanie jest trochę zbyt trudne dla golfa kodowego. Fizyka piłki do Ponga jest dość skomplikowana.
beary605
@ beary605, nie sądzę, aby fizyka piłki była zbyt skomplikowana. Moje rozwiązanie jest „jak najbliżej” do demonstracji javascript, a fizyka jest dość prosta.
stoisko
Dla porównania istnieje kilka innych [golfów kodowych], które biegną dość długo. Zbudować maszynę do gry labirynt , kółko i krzyżyk (aka Tic-Tac-Toe) (oba mogą korzystać z dodatkowych wpisów, który lubi „wygrać” domyślnie?), Napisać mały serwer HTTP , Self-tłumaczeniowe interpretera , Self- kompilator kompilatora , Kompiluj Regeksy ...
dmckee
@felipa, czy możesz sformalizować „jak najbliżej”? Nie wiem, dlaczego moje rozwiązanie sed nie jest na czele.
stoisko
1
@ beary605 zbyt trudne?
FantaC

Odpowiedzi:

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
*/

Skrypt można umieścić na końcu <body>lub wywołać onLoad. Potrzebuje następującego elementu canvas:

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

Gracz 1 używa klawiszy qi a, a gracz 2 używa klawiszy pi l. Naciśnij escklawisz, aby wstrzymać, a dowolny klawisz, aby rozpocząć / kontynuować.

Można grać w przeglądarce tutaj .

Nie byłem pewien, jakiej fizyki się posługiwać, więc zacząłem od prostej metody refleksji, a potem dodałem trochę różnorodności i trochę z nią eksperymentowałem. Na prędkość piłki w kierunku y ma wpływ to, gdzie na łopatce uderzysz piłkę, więc masz pewną kontrolę nad tym, dokąd piłka idzie. Prędkość piłki w kierunku x powoli wzrasta z każdym uderzeniem w rajdu.

Podejrzewam, że będzie dość łatwo pokonany przez rozwiązania wykorzystujące biblioteki, ale dobrze się bawiłem, robiąc to w prostym javascript.

grc
źródło
2
To naprawdę fajne wdrożenie.
felipa
1
Można by jeszcze trochę zagrać w golfa, wiem, że spóźnię się tu około dwóch lat. ale możesz przypisać 20do zmiennej o nazwie gi zapisać jeden bajt.
Zacharý
Cholera, ciężko jest grać na klawiaturze azerty ...
dim
38

sed, 35

Lekko podnosząc poprzeczkę dzięki medytacji sed znaczka pocztowego.

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

Medytacja odbywa się na stdin / stdout na dwóch komputerach, niekoniecznie połączonych siecią. Medytacja rozpoczyna się w stanie

0         <       1

z guru zero po lewej i jeden po prawej. Nawias kątowy przesuwa się w lewo i prawo, a jeśli guru manewruje swoją liczbą, aby skontaktować się z kursorem, gdy chodzi o ich bok, ich wynik jest zwiększany o jeden, a oni radują się.

Medytacja jest inicjowana przez wpisanie powyższego stanu do sed -f medi.sed, a komputer odpowiada następnym stanem. Obowiązkowi typy guru, którzy zapowiadają medytację, czytają na głos następny klawisz, który wcisną, przy czym obaj guru naciskają święty klucz enterw przyszłość w tym samym czasie. Sumienny komputer odpowiada następnym stanem. To z kolei jest odczytywane na głos podczas pisania jednogłośnie, jak w ostatnim. Kontynuujcie postępy w przyszłości, aż do osiągnięcia nieskończonej błogości.

Guru pragnący wyzwania może grać w trybie „turbo”, w którym guru próbuje wspólnie przewidzieć następny stan komputera i wpisuje go w monicie zamiast bieżącego stanu. Guru będą mieli mądrość, by zweryfikować zgodność między ich przewidywaniami przed wejściem w przyszłość.

boothby
źródło
23
Koleś ... co właśnie przeczytałem?
MrZander
9
@MZZander Tylko poprzez głęboką kontemplację można odkryć mądrość medytacji. Ta kontemplacja jest najlepiej wspomagana przez wykonanie programu.
stoisko
15

Python (z pygame ) 650 bajtów

cechy

  • Tryby 1 i 2 graczy - na początku gry naciśnij, 1aby wybrać 1 gracza lub 22 graczy. Gra nie rozpocznie się, dopóki nie zostanie naciśnięty jeden z tych klawiszy.
  • Zwiększenie prędkości piłki - Każda salwa zwiększa prędkość piłki, tak że po 10 salwach wzrosła o około 50%, po 20 będzie o 50% szybsza itd.
  • Zmienne ugięcie piłki - ugięcie piłki opiera się na dwóch czynnikach: na jakiej części wiosła uderza i czy wiosło porusza się po uderzeniu. Jeśli piłka uderzy w wiosło w pobliżu jednego z końców, zostanie odchylona mocniej niż w przypadku uderzenia w pobliżu środka (prawie tak, jakby była zakrzywioną powierzchnią). Dodatkowo, jeśli wiosło jest w ruchu, ruch wiosła jest dodawany do ugięcia. Aby uzyskać najsilniejsze ugięcie, piłka musi uderzyć w pobliżu końca wiosła, a wiosło musi być w ruchu w kierunku tego samego końca. Jest to bardzo podobne do oryginalnego Ponga dla Atari 2600.
  • Pauza - Grę można zatrzymać w dowolnym momencie, naciskając Spacepasek. Odtwarzanie zostanie wznowione po drugim naciśnięciu spacji.
  • Kontrole - tak jak na przykładzie, odtwarzacz 1 porusza się z Qi Akluczy, a gracz 2 porusza się Pi L.

Na koniec chciałbym poprosić, aby z różnych powodów nie wybrano tego rozwiązania jako przyjętej odpowiedzi.

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

Przykładowy zrzut ekranu:

Uwaga: czcionka użyta w wyniku może różnić się w zależności od systemu.

primo
źródło
Wynik pokazuje mi lewą połowę i myślę, że ugięcie jest zbyt silne, ale i tak jest całkiem fajne :)
aditsu
@aditsu czy działasz pod Linuksem? Zobaczę, czy mogę znaleźć alternatywę, która działa niezależnie od wybranej czcionki. Idea odchylenia polega na tym, że byłoby możliwe odchylenie piłki z większą prędkością (maksymalnie 2,5 na mojej skali), niż wiosło może się poruszać ( 1.67 ). Jest to możliwe tylko wtedy, gdy dasz mu „spin”. Jeśli wiosło nie porusza się, gdy piłka uderza, maksymalna prędkość wynosi 1,5 .
primo
Tak, używam Linuksa. Wydaje mi się dziwne, że piłka może faktycznie „wrócić” (w górę lub w dół) po uderzeniu w wiosło, zamiast kontynuować w tym samym kierunku (być może pod innym kątem). Ale może zrobiła to wersja Atari, nie wiem.
aditsu
@aditsu Kosztowało to kilka bajtów, ale uważam, że wynik powinien być wyśrodkowany bez względu na wybraną czcionkę (o ile jest to monospace). Daj mi znać, czy to działa dla Ciebie. I tak, odchylenie jest bardzo podobne (choć płynniejsze rozmieszczenie) do znanej mi wersji Atari. Jeśli wyobrażasz sobie wiosło jako (wypukłą) zakrzywioną powierzchnię (jak wiosło hokejowe), myślę, że powinno być bardziej intuicyjne.
primo
Tak, jest teraz wyśrodkowany
aditsu
8

HTML i JavaScript (weź 2) - 525

Ponieważ OP nie wydawało się zbytnio przejmować częścią „jak najbliżej”, oto alternatywne rozwiązanie, które bezlitośnie uprościłem, rozebrałem i grałem w golfa. Q / A i P / L do gry, ale każdy inny klawisz ma również wpływ. Ponownie kod jest w pełni samowystarczalny i przetestowałem go w Chromium 25 w systemie Linux. Mogę grać w golfa jeszcze bardziej, jeśli możesz zaakceptować małe błędy lub większe pogorszenie jakości grafiki / rozgrywki.

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

Dzięki Shmiddty

aditsu
źródło
Nie rozumiem sprzeciwu. O ile pamiętam, wersja 715 bajtów (edytowana 3 godziny przed tym postem) jest prawie identyczna z oryginalną wersją Ponga, którą miałem dla mojego Atari 2600.
primo
@primo Zakładam, że mówisz o moim dorozumianym twierdzeniu, że twoje rozwiązanie nie spełnia kryterium „jak najbliżej”. Cóż, OP nie wspomniał o wersji Atari 2600, ale o konkretnej implementacji javascript, z którą się łączył. Na pierwszy rzut oka w kodzie występują 2 rażące różnice: brak odtwarzacza komputerowego i brak wyświetlania wyników „7 segmentów”. Prawdopodobnie istnieje znacznie więcej różnic w „mechanice”. Jeśli te rzeczy nie są ważne, myślę, że to rozwiązanie również powinno być prawidłowe.
aditsu
To jest mój błąd. Naprawdę miałam na myśli „jak najbliżej”, więc twoje pierwsze rozwiązanie jest jak dotąd najlepsze.
felipa
możesz usunąć c=window.c. Przypisujesz sobie zmienną globalną.
Shmiddty
Możesz uratować jeszcze 1 postać, wchodząc ++S[n]do.random(++S[n])
Shmiddty
5

HTML i JavaScript - 1663

Wbrew mojej lepszej ocenie, wybrałem szalone podejście do gry w golfa z kodu demo. Usunąłem niektóre funkcje i elementy interfejsu, ale ogólnie działa dokładnie tak samo - 0, 1 lub 2, aby wybrać liczbę ludzkich graczy, Q / A i P / L do przeniesienia.

O ile nie popełniłem błędów, rozgrywka powinna być identyczna, piksel dla piksela i milisekunda dla milisekundy, z oryginałem przy 640 * 480 (wskazówka: zmiana rozmiaru okna przeglądarki zmienia rozmiar gry w wersji demo). Po prostu nie podaje instrukcji, nie ogłasza zwycięzcy i nie obsługuje esc.

Kod jest w pełni samodzielny i przetestowałem go w Chromium 25 w systemie Linux. Firefox bardzo go nie lubi.

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

Trochę kredytów dla Shmiddty za ulepszenia

aditsu
źródło
4

Przetwarzanie, 487 znaków

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

Przykładowy zrzut ekranu:

wprowadź opis zdjęcia tutaj

Ten kod został stworzony z myślą o skrócie, więc jest dość błędny (piłka czasami przechodzi przez wiosło lub owija się wokół niego). Kontrole są Q / A dla Gracza 1 i O / L dla Gracza 2.

segfaultd
źródło
1
Jako gra twoja wersja Ponga wydaje się również niesprawiedliwa, ponieważ tylko klucze jednego gracza są rejestrowane na klatkę: P
Jonathan Frech
2

C # - 1283 znaków

Można to pograć w golfa trochę więcej, ale oto jest.

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

Edycja: Nie widziałem wymogu wolnego, uruchamianego w systemie Linux języka ...

Brandon
źródło
2

Tcl / Tk , 932 bajty

Musi być uruchomiony w interaktywnej powłoce

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 .

Uwaga:

 #There is an Enter at the end

Tylko bardzo minimalna wersja Ponga, w której piłka porusza się tylko pod kątem ukośnym i zawsze ma taką samą prędkość.

wprowadź opis zdjęcia tutaj

sergiol
źródło
Nieudany outgolf: bit.ly/2VSIGz8
sergiol