Pong dans le code le plus court

28

Le défi est simple. Donnez le code le plus court possible pour reproduire le jeu classique de pong à 2 joueurs http://en.wikipedia.org/wiki/Pong . Le niveau de graphisme et de fonctionnalité doit être aussi proche que possible de cette démonstration javascript http://codeincomplete.com/posts/2011/5/14/javascript_pong/demo.html (mais sans les options supplémentaires, vous pouvez cliquer sur la gauche ou le cadre, les informations fps, etc. en bas à droite).

Comme toujours, le code doit être écrit dans un langage libre (dans les deux sens) et doit être exécutable sur Linux. Toutes les bibliothèques utilisées doivent également être gratuites, facilement disponibles et ne pas être écrites aux fins de ce concours (et ne pas contenir déjà une version de travail de Pong!).

Felipa
la source
Honnêtement, cette question est un peu trop difficile pour le golf de code. La physique de la balle pour Pong est assez compliquée.
beary605
@ beary605, je ne pense pas que la physique de la balle soit trop compliquée. Ma solution est «aussi proche que possible» de la démonstration javascript, et la physique est assez simple.
stand
Juste pour référence, il existe d'autres [code-golf] qui durent assez longtemps. Construire un moteur pour un jeu de labyrinthe , Noughts and Crosses (alias Tic-Tac-Toe) (les deux pourraient utiliser des entrées supplémentaires, qui aime "gagner" par défaut?), Écrire un petit serveur HTTP , interprète auto-interprète , auto- compilation du compilateur , Compile Regexes ...
dmckee
@felipa, pouvez-vous formaliser "le plus près possible"? Je ne sais pas pourquoi ma solution sed n'est pas en tête.
stand
1
@ beary605 trop difficile?
FantaC

Réponses:

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

Le script peut être placé à la fin de <body>ou appelé onLoad. Il a besoin de l'élément canvas suivant:

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

Le joueur 1 utilise les qet aclés, et le joueur 2 utilise les pet lclés. Appuyez sur la esctouche pour mettre en pause et sur n'importe quelle touche pour démarrer / continuer.

Vous pouvez le lire dans votre navigateur ici .

Je n'étais pas sûr de la physique à utiliser, alors j'ai commencé avec une méthode de réflexion simple, puis j'ai ajouté de la variété et je l'ai expérimentée un peu. La vitesse de la balle dans la direction y est affectée par l'endroit où vous frappez la balle sur la raquette, vous avez donc un certain contrôle sur la direction de la balle. La vitesse de la balle dans la direction x augmente lentement à chaque coup dans le rallye.

Je soupçonne qu'il sera battu assez facilement par des solutions utilisant des bibliothèques, mais je me suis amusé à le faire en javascript simple.

grc
la source
2
C'est une très belle implémentation.
felipa
1
Pourrait être joué un peu plus au golf, je sais que j'ai deux ans de retard ici. mais vous pouvez attribuer 20à une variable nommée get enregistrer un octet minuscule.
Zacharý
Merde, c'est difficile de jouer sur un clavier azerty ...
dim
38

sed, 35

Relever un peu la barre avec une méditation sed de timbre-poste.

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

La méditation se fait sur stdin / stdout sur deux ordinateurs, pas forcément connectés par un réseau. La méditation commence dans l'état

0         <       1

avec gourou zéro à gauche et un à droite. Le support d'angle se déplace vers la gauche et la droite, et si un gourou manœuvre son nombre pour contacter le curseur quand il vient à son côté, son score est augmenté d'une unité, et ils deviennent ravis de joie.

La méditation est initiée en tapant l'état ci-dessus sed -f medi.sedet l'ordinateur répond avec l'état suivant. Les types de gourous consciencieux qui déclarent dans la méditation, lisant à haute voix la touche suivante sur laquelle ils appuieront, les deux gourous appuyant en entermême temps sur la touche sainte pour l'avenir. L'ordinateur consciencieux répond avec l'état suivant. Ceci, à son tour, est lu à haute voix tout en étant tapé à l'unisson comme avec le dernier. Continuez d'avancer vers l'avenir jusqu'à ce que le bonheur infini soit atteint.

Les gourous qui souhaitent relever un défi peuvent jouer en mode «turbo», dans lequel les gourous tentent de prédire en collaboration le prochain état de l'ordinateur et de le saisir dans l'invite au lieu de l'état actuel. Les gourous auront la sagesse de vérifier l'accord entre leurs prédictions avant d'entrer dans le futur.

boothby
la source
23
Mec ... qu'est-ce que je viens de lire?
MrZander
9
@MrZander Ce n'est que par une longue réflexion que la sagesse de la méditation peut être révélée. Cette contemplation est mieux aidée par l'exécution du programme.
stand
15

Python (avec pygame ) 650 octets

traits

  • Modes 1 et 2 joueurs - Lorsque le jeu commence, appuyez sur 1pour 1 joueur ou 2pour 2 joueurs. Le jeu ne commencera pas tant que vous n'aurez pas appuyé sur l'une de ces touches.
  • Augmentation de la vitesse de la balle - À chaque volée, la vitesse de la balle est augmentée de sorte qu'au bout de 10 volées, elle a augmenté d'environ 50%, après 20, elle sera 50% plus rapide que cela, etc.
  • Déviation variable de la balle - La déviation de la balle est basée sur deux facteurs: quelle partie de la raquette elle frappe et si la raquette se déplace ou non lors de l'impact. Si la balle frappe la raquette près d'une des extrémités, elle sera déviée plus fortement que si elle frappe près du milieu (presque comme s'il s'agissait d'une surface courbe). De plus, si la palette est en mouvement, le mouvement de la palette est ajouté à la déflexion. Afin d'obtenir la déviation la plus forte, la balle doit frapper près de l'extrémité de la pagaie et la pagaie doit être en mouvement vers cette même extrémité. Ceci est très similaire au Pong d'origine pour Atari 2600.
  • Pause - Le jeu peut être interrompu à tout moment en appuyant sur la Spacebarre. Le jeu reprendra en appuyant une deuxième fois sur la barre d'espace.
  • Commandes - Comme dans l'exemple, le joueur 1 se déplace avec le Qet les Atouches, et le joueur 2 se déplace avec Pet L.

Pour terminer, je voudrais demander que cette solution ne soit pas retenue comme réponse acceptée, pour diverses raisons.

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

Exemple de capture d'écran:

Remarque: la police utilisée pour la partition peut varier d'un système à l'autre.

primo
la source
Le score est dans la moitié gauche pour moi, et je pense que la déviation est trop forte, mais c'est quand même assez cool :)
aditsu
@aditsu opérez-vous sous linux? Je vais voir si je peux trouver une alternative qui fonctionne quelle que soit la police sélectionnée. L'idée derrière la déflexion est qu'il serait possible de dévier la balle à une vitesse plus rapide (maximum 2,5 sur mon échelle) que la pagaie ne peut déplacer ( 1,67 ). Cela n'est possible que si vous lui donnez un «spin». Si la raquette ne bouge pas lorsque la balle frappe, la vitesse maximale sera de 1,5 .
primo
Oui j'utilise Linux. Je trouve étrange que la balle puisse réellement "reculer" (vers le haut ou vers le bas) après avoir frappé la raquette, au lieu de continuer dans la même direction (peut-être sous un angle différent). Mais peut-être que la version Atari a fait ça, je ne sais pas.
aditsu
@aditsu Cela coûte quelques octets, mais je pense que la partition doit être centrée quelle que soit la police choisie (tant qu'elle est monospace). Dites-moi si cela marche pour vous. Et oui, la déviation est très similaire (bien qu'une distribution plus fluide) à la version Atari que je connaissais. Si vous imaginez la pagaie comme une surface courbe (convexe) (comme une pagaie de hockey sur air), je pense qu'elle devrait être plus intuitive.
primo
Oui, il est centré maintenant
aditsu
8

HTML et JavaScript (prendre 2) - 525

Étant donné que l'OP ne semblait pas se soucier beaucoup de la partie "aussi proche que possible", voici une solution alternative que j'ai impitoyablement simplifiée, dépouillée et golfée. Q / A et P / L pour jouer, mais toutes les autres touches ont également un effet. Encore une fois, le code est entièrement autonome et je l'ai testé dans Chromium 25 sur Linux. Je peux le jouer encore plus si vous pouvez accepter de petits bugs ou une plus grande dégradation de la qualité graphique / du gameplay.

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

Merci Shmiddty

aditsu
la source
Je ne comprends pas l'objection. Pour autant que je me souvienne, la version 715 octets (éditée 3 heures avant ce post) est presque identique à la version originale de Pong que j'avais pour mon Atari 2600.
primo
@primo Je suppose que vous parlez de mon affirmation implicite que votre solution ne répond pas au critère "le plus près possible". Eh bien, l'OP n'a pas mentionné la version Atari 2600, mais une implémentation javascript spécifique à laquelle il était lié. Et à première vue, il y a 2 différences flagrantes dans votre code: pas de lecteur d'ordinateur et pas d'affichage de score "7 segments". Il y a probablement beaucoup plus de différences dans la "mécanique". Si ces choses ne sont pas importantes, je pense que cette solution devrait également être valable.
aditsu
C'est mon erreur. Je voulais vraiment dire "aussi près que possible", donc votre première solution est la meilleure jusqu'à présent.
felipa
vous pouvez supprimer le c=window.c. Vous vous attribuez une variable globale.
Shmiddty
Vous pouvez enregistrer 1 personnage supplémentaire en vous déplaçant à l' ++S[n]intérieur de.random(++S[n])
Shmiddty
5

HTML et JavaScript - 1663

Contre mon meilleur jugement, j'ai pris l'approche folle de jouer au golf avec le code réel de la démo. J'ai supprimé certaines fonctionnalités et éléments d'interface, mais généralement cela fonctionne exactement de la même manière - 0, 1 ou 2 pour choisir le nombre de joueurs humains, Q / A et P / L à déplacer.

Sauf si j'ai fait quelques erreurs, le gameplay doit être identique, pixel pour pixel et milliseconde pour milliseconde, à l'original à 640 * 480 (indice: le redimensionnement de la fenêtre du navigateur modifie la taille du jeu dans la démo). Il ne donne tout simplement pas d'instructions, n'annonce pas le gagnant et ne gère pas l'esc.

Le code est entièrement autonome et je l'ai testé dans Chromium 25 sous Linux. Firefox ne l'aime pas beaucoup.

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

Quelques crédits à Shmiddty pour des améliorations

aditsu
la source
4

Traitement, 487 caractères

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

Exemple de capture d'écran:

entrez la description de l'image ici

Ce code a été créé avec un esprit court, il est donc assez buggé (la balle passe parfois à travers la pagaie ou s'enroule autour). Les commandes sont Q / A pour le joueur 1 et O / L pour le joueur 2.

segfaultd
la source
1
En tant que jeu, votre version de Pong semble également assez injuste, car seules les clés d'un joueur sont enregistrées par image: P
Jonathan Frech
2

C # - 1283 caractères

Cela peut être joué un peu plus, mais le voici.

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

Edit: Je n'ai pas vu la nécessité d'une langue gratuite, exécutable sous Linux ...

Brandon
la source
2

Tcl / Tk , 932 octets

Doit être exécuté dans le shell interactif

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 .

Remarque:

 #There is an Enter at the end

Juste une version très minimale de Pong, où la balle ne fonctionne que dans des angles diagonaux et a toujours la même vitesse.

entrez la description de l'image ici

sergiol
la source
Outgolf échoué: bit.ly/2VSIGz8
sergiol