Construire un tas de sable

59

Un tas de sable abélien , pour nos besoins, est une grille infinie avec des coordonnées entières, initialement vide de sable. Après chaque seconde, un grain de sable est placé à (0,0). Chaque fois qu’une cellule de la grille contient au moins 4 grains de sable, elle renverse simultanément un grain de sable sur chacun de ses quatre voisins. Les voisins de (x, y) sont (x-1, y), (x + 1, y), (x, y-1) et (x, y + 1).

Lorsqu'une cellule se renverse, ses voisins risquent de se renverser. Quelques faits:

  • Cette cascade finira par s'arrêter.
  • L'ordre dans lequel les cellules se répandent est sans importance; Le résultat sera le même.

Exemple

Après 3 secondes, la grille ressemble à

.....
.....
..3..
.....
.....

Après 4 secondes:

.....
..1..
.1.1.
..1..
.....

Après 15 secondes:

.....
..3..
.333.
..3..
.....

Et après 16 secondes:

..1..
.212.
11.11
.212.
..1..

Le défi

Dans le moins d'octets possible, écrivez une fonction qui prend un seul entier positif t et génère une image du tas de sable après t secondes.

Contribution

Un seul entier positif t , dans le format de votre choix.

Sortie

Une image du tas de sable après t secondes, en utilisant les caractères

 . 1 2 3

Modifier: utilisez quatre caractères distincts que vous aimez ou dessinez une image. Si vous n'utilisez pas ".123" ou "0123", spécifiez dans votre réponse la signification des caractères.

Contrairement aux exemples, votre sortie doit contenir le nombre minimal de lignes et de colonnes nécessaires pour afficher la partie non nulle de la pile de sable.

C'est-à-dire que pour l'entrée 3, la sortie doit être

 3

Pour 4, la sortie devrait être

 .1.
 1.1
 .1.

Notation

Le score de golf standard s'applique.

Règles

Aucune fonction de langage ou bibliothèque qui sait déjà ce qu'est un tas de sable n'est autorisée.

Edit: la section de sortie a été modifiée, la restriction de jeu de caractères a été complètement levée. Utilisez quatre caractères ou couleurs distincts que vous aimez.

Eric Tressler
la source
2
L'entrée peut t être 0? Quelle est la sortie alors?
Luis Mendo
1
Est-il correct car à une heure donnée, plusieurs cascades peuvent se dérouler dans une rangée? Donc, à ce moment-là, les cascades continuent de se produire jusqu'à ce que chaque cellule atteigne 3 ou moins?
Flawr
2
@flawr: Oui, ce serait correct. Regardez la différence entre t = 15 et t = 16.
El'endia Starman
@LuisMendo L'entrée est spécifiée avec un t positif , donc zéro n'est pas une entrée valide.
Eric Tressler
1
Est-il vraiment nécessaire d'avoir .des cellules vides? Pouvons-nous avoir 0une cellule vide valide?
Andreï Kostyrka

Réponses:

56

R, 378 343 297 291 octets

Comme d'habitude, l'utilisateur fournit son entrée via scan()(j'ai déjà utilisé la variable t, prenons-le à la zplace), la seconde ligne doit donc être lancée séparément, puis le reste:

e=numeric
a=1%*%scan()
x=1
o=a>3
n=1
while(any(o)){
v=which(o,T)
if(any(v==1)){a=rbind(e(n+2),cbind(e(n),a,e(n)),e(n+2));x=x+1;n=n+2;v=which(a>3,T)}
q=nrow(v)
u=cbind(e(q),1)
l=v-u[,1:2];r=v+u[,1:2];t=v-u[,2:1];b=v+u[,2:1]
a[l]=a[l]+1;a[r]=a[r]+1;a[t]=a[t]+1;a[b]=a[b]+1
a[v]=a[v]-4
o=a>3}
a

Les sorties d' un tableau qui contient les valeurs d' aau tième génération (0, 1, 2 ou 3).

Cas de test:

z=3
     [,1]
[1,]    3
z=4
     [,1] [,2] [,3]
[1,]    0    1    0
[2,]    1    0    1
[3,]    0    1    0
z=16
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    1    0    0
[2,]    0    2    1    2    0
[3,]    1    1    0    1    1
[4,]    0    2    1    2    0
[5,]    0    0    1    0    0

Cela nous aide que cette chose soit symétrique à la fois verticalement et horizontalement, ce qui signifie que le point le plus à gauche a une hauteur de 4, cela signifie que les points le plus haut, le plus à droite et le plus bas sont également à 4.

Oh, et ai-je dit que vous pouvez faire de belles visualisations?

Après 1000 gouttes:

Tas de sable abélien après 1000 pas

Après 50000 gouttes (≈4 secondes):

Tas de sable abélien après 50000 pas

Après 333333 gouttes (15 minutes):

Tas de sable abélien après 100 000 pas

Vous pouvez aussi le dessiner!

image(1:n,1:n,a,col=colorRampPalette(c("#FFFFFF","#000000"))(4), axes=F, xlab="", ylab="")

Cette opération a pris 4 secondes pour 10000 itérations mais ralentit considérablement pour les baies plus grandes (par exemple quelques minutes pour 100000 itérations). C’est pourquoi il est si lent (j’ai estimé le taux de croissance comme dans Taux de croissanceet j’ai obtenu τ (i) ≈ 689 · i ^ 1,08, de sorte que le temps moyen par grain supplémentaire jusqu’à ce que tout le tas de sable s’installe après l’ iétape est légèrement supérieur à un) , et le temps total en fonction du nombre de grains augmente un peu plus lentement que quadratiquement (T (i) 0,028 * i ^ 1,74):

Itération moyenne jusqu'à ce que la pile se stabilise

Temps de calcul approximatif

Et maintenant, avec une explication complète:

e=numeric # Convenient abbreviation for further repeated use
a=1%*%scan() # Creates a 1×1 array with a user-supplied number
x=1 # The coordinate of the centre
o=a>3 # Remember which cells were overflown
n=1 # Array height that is going to change over time
while(any(o)){ # If there is still any overflow
  v=which(o,T) # Get overflown cells' indices
  if(any(v==1)){ # If overflow occurred at the border, grow the array
    a=rbind(e(n+2),cbind(e(n),a,e(n)),e(n+2)) # Growing
    x=x+1 # Move the centre
    n=n+2 # Change the height
    v=which(a>3,T) # Re-index the overflowed cells
    }
  q=nrow(v) # See how many indices are overflown
  u=cbind(e(q),1) # Building block for neighbours' indices
  l=v-u[,1:2];r=v+u[,1:2];t=v-u[,2:1];b=v+u[,2:1] # L, R, T, B neighbours
  a[l]=a[l]+1;a[r]=a[r]+1;a[t]=a[t]+1;a[b]=a[b]+1 # Increment neighbours
  a[v]=a[v]-4 # Remove 4 grains from the overflown indices
  o=a>3} # See if still overflown indices remain
a # Output the matrix

C’est la première fois de ma vie que la croissance d’objets (comme a <- c(a, 1)) fonctionne beaucoup plus vite que de pré-allouer une grande matrice vide pour les valeurs et de la remplir progressivement avec une tonne de zéros inutilisés.

Mise à jour. Golfed 18 octets en éliminant arr.inden whichraison de Billywob et en remplaçant rep(0,n)avec e=numeric;e(n)dans 5 cas , en raison de JDL , et 17 plusieurs octets en raison de JDL .

Mise à jour 2. Le tas de sable étant Abelian, il peut commencer par une pile de la hauteur souhaitée. J'ai donc supprimé la boucle redondante et amélioré considérablement la productivité!

Andreï Kostyrka
la source
1
Je comprends ce que vous voulez dire sur la colonne supplémentaire, les index de lignes que vous exportez, mais je pense que je veux limiter la sortie à être simplement "la réponse", et rien de plus. Je suis content que vous ayez inclus des images, cependant.
Eric Tressler
1
Bonne réponse Andreï! Cependant, vous pouvez certainement jouer au golf quelques octets, par exemple en prédéfinissant rep(), étant donné que vous l’utilisez 6 fois. Deuxièmement, je ne pense pas que vous ayez besoin d’écrire l’ arr.ind=Toption pour la which()fonction. Il suffit d'utiliser which(...,T).
Billywob
1
Il peut être plus compliqué de définir n=numericet d’utiliser cela à la place, car il n(k)ya moins de caractères que r(0,k). J'aime les images cependant.
JDL
1
Une autre suggestion: 1%*%0est moins de caractères que array(0,c(1,1)). De plus, le deuxième argument u <- cbindpouvant être simplement égal à 1, cbindl'étendra par défaut à la longueur du premier argument.
JDL
1
@GregMartin a résolu ce problème. Désolé; dans ma langue maternelle, nous utilisons le mot «moi» et ne nous préoccupons jamais du sexe de la personne en question (comme «un petit pas pour un homme»); encore, parfois, à de très rares occasions, j’appelle un chien «elle» ou un «il», alors que cela devrait être «le», à moins que, comme, par exemple, vous en soyez le propriétaire et que vous vouliez vraiment mettre l’accent sur le sexe de votre anumal ( en dépit du fait que dire un homme d'une femme n'est pas si difficile).
Andreï Kostyrka
13

MATL , 55 53 48 43 42 octets

Inspiré par la réponse de @ flawr .

Sortie graphique :

0i:"Gto~+XytP*+t"t4=t1Y6Z+b+w~*]]tat3$)1YG

Essayez-le sur MATL Online! . Cela prend environ 10 secondes pour la saisie 30. Vous devrez peut-être actualiser la page et appuyer à nouveau sur "Exécuter" si cela ne fonctionne pas.

Voici un exemple de résultat pour l'entrée 100:

entrez la description de l'image ici

Sortie ASCII (43 octets) :

0i:"Gto~+XytP*+t"t4=t1Y6Z+b+w~*]]tat3$)48+c

Essayez-le en ligne!

Explication

0          % Push a 0. This is the initial array. Will be resized in first iteration
i:         % Take input n. Generate range [1 2 ... n]
"          % For each, i.e. repeat n times
  Gto~+    %   Push input and add negate parity. This "rounds up" n to odd number
           %   m = n or n+1
  Xy       %   Identity matrix with that size
  tP*      %   Multiply element-wise by vertically flipped copy. This produces a
           %   matrix with a 1 in the center and the rest entries equal to 0
  +        %   Add to previous array. This updates the sandpile array
  t        %   Duplicate
  "        %   For each column (i.e. repeat m times)
    t4=    %     Duplicate. Compare with 4 element-wise. This gives a 2D mask that
           %     contains 1 for entries of the sandpile array that equal 4, and 0
           %     for the rest
    t      %     Duplicate
    1Y6    %     Predefined literal: [0 1 0; 1 0 1; 0 1 0]
    Z+     %     2D convolution, maintaining size
    b      %     Bubble up to bring sandpile array to top
    +      %     Element-wise addition. This adds 1 to the neighbours of a 4
    w      %     Swap to bring copy of mask to top
    ~*     %     Multiply bu negated mask. This removes all previous 4
  ]        %  End
]          % End
t          % Duplicate the updated sandpile array
a          % 1D mask that contains 1 for columns that contain a 1. This will be
           % used as a logical index to select columns
t          % Duplicate. This will be used as logical index to select rows (this
           % can be done because of symmetry)
3$)        % Keep only those rows and columns. This trims the outer zeros in the
           % sandpile array
1YG        % Display as scaled image
Luis Mendo
la source
3
Je suis jaloux de 1Y6.
Flawr
1
@flawr Mais tu es ~mod(spiral(3),2)beaucoup plus malin :-)
Luis Mendo
11

Matlab, 160 156 148 octets

n=input('');z=zeros(3*n);z(n+1,n+1)=n;for k=1:n;x=z>3;z=z+conv2(+x,1-mod(spiral(3),2),'s');z(x)=z(x)-4;end;v=find(sum(z));z=z(v,v);[z+48-(z<1)*2,'']

Tout d'abord, une matrice trop grosse est créée, avec nle milieu quelque part. Ensuite, la cascade est calculée avec une convolution 2D très pratique. À la fin, l'excédent est coupé et le tout est converti en chaîne.

Exemple de sortie pour t=100

...121...
..32.23..
.3.323.3.
123.3.321
2.23.32.2
123.3.321
.3.323.3.
..32.23..
...121...

Comme toujours:

La convolution est la clé du succès.

flawr
la source
v=any(z)au lieu de v=find(sum(z))(je l'utilise dans ma réponse). Aussi, 2*~zau lieu de(z<1)*2
Luis Mendo
Mon ordinateur s'est arrêté de fonctionner n=500... Cela faisait n=400plusieurs secondes que le traitement était en cours . Est-ce que je fais quelque chose de mal?
Andreï Kostyrka
@ AndreïKostyrka Ça marche pour moi (Matlab R2015b)
Luis Mendo
1
@ AndreïKostyrka Pour une entrée de nce programme génère une 3*n x 3*nmatrice, il a donc besoin de stocker sur les 9*n^2chiffres. En outre, il est totalement inefficace, car nous avons également une longue itération totalement inutile allant de 1 à n. Mais là encore, c’est du code-golf , rendre un programme efficace est une tasse de thé différente.
Flawr
@ AndreïKostyrka Vous pouvez améliorer l'efficacité de la mémoire en utilisant des matrices creuses (deuxième ligne:) z=sparse(zeros(2*n+1))et en modifiant la boucle for en while any(z(:)>3). Ensuite , vous pouvez peut - être aussi calculer le noyau de convolution une seule fois: kern = 1-mod(spiral(3),2).
Flawr
9

Python 2, 195 +1 +24 = 220 217

from pylab import*
ifrom scipy.signal import convolve2d as c
k=(arange(9)%2).reshape(3,3)
def f(n):g=zeros((n,n),int);g[n/2,n/2]=n;exec"g=c(g/4,k,'same')+g%4;"*n;return g[any(g,0)].T[any(g,0)]

sortie pour n = 16

array([[0, 0, 1, 0, 0],
       [0, 2, 1, 2, 0],
       [1, 1, 0, 1, 1],
       [0, 2, 1, 2, 0],
       [0, 0, 1, 0, 0]])

il y a BEAUCOUP de remplissage et d'itérations inutiles, en utilisant ncomme limite supérieure "assez bonne", mais n = 200 toujours terminé en une seconde et n = 500 en environ 12 secondes

non-golfé

from pylab import*
from scipy.signal import convolve2d as c
k=array([0,1,0],
        [1,0,1],
        [0,1,0])
def f(n):
  g=zeros((n,n))                 # big grid of zeros, way bigger than necessary
  g[n/2,n/2]=n                   # put n grains in the middle
  exec"g=c(g/4,k,'same')+g%4;"*n # leave places with <4 grains as is, convolve the rest with the kernel k, repeat until convergence (and then some more)
  return g[any(g,0)].T[any(g,0)] # removes surrounding 0-rows and columns

Le remplacement return xpar imshow(x)ajoute un caractère et génère une image interpolée laide, ce qui imshow(x,'gray',None,1,'nearest')supprime l’interpolation floue, ce qui amène la sortie à la hauteur des spécifications.

n = 100

DenDenDo
la source
Je reçois l'erreur suivante lorsque je lance votre code: ImportError: No module named convolve2d. Changer import scipy.signal.convolve2d as cpour from scipy.signal import convolve2d as crésoudre le problème. J'utilise scipy version 0.16.1, ai-je besoin d'une version plus ancienne ou plus récente? Ou le problème est-il autre chose?
Andrew Epstein
bizarre, maintenant que vous mentionnez que cela ne fonctionne plus pour moi non plus. Je l'ai probablement bien fait la première fois en mode interactif, puis je l'ai abrégé et ignoré l'erreur, mais la fonction est restée en mémoire
DenDenDo
6

Perl, 157 147 octets

Inclut +1 pour -p

Exécuter avec le décompte sur STDIN, imprime la carte en utilisant 0123STDOUT:

sandpile.pl <<< 16

sandpile.pl:

#!/usr/bin/perl -p
map{++substr$_,y///c/2-1,1;/4
/?$.+=s%^|\z%0 x$..$/%eg+!s/\b/0/g:s^.^$&%4+grep{3<substr$\,0|$_+"@+",1}-$.-2,-2,0,$.^eg while/[4-7]/}($\="0
")x$_}{
Ton Hospel
la source
5

Python 3 2, 418 385 362 342 330 octets

w='[(i,j)for i in r(n)for j in r(n)if a[i][j]>3]'
def f(z):
 a,x,r=[[z]],0,range
 for _ in[0]*z:
  n=len(a);v=eval(w)
  if[1for b,c in v if(b==0)+(c==0)]:n+=2;a=[[0]*n]+[[0]+a[i]+[0]for i in r(n-2)]+[[0]*n];x+=1;v=eval(w)
  for c,d in v:exec'a[c+%s][d+%s]+=1;'*4%(-1,0,1,0,0,-1,0,1);a[c][d]-=4
 for i in a:print''.join(map(str,i))

Edit: sauvegardé 6 octets grâce à @ Qwerp-Derp

Tout le mérite de @ Andreï Kostyrka, car il s'agit d'une traduction directe de son code R en Python.

Andrew Epstein
la source
Je pense que vous pouvez déplacer l'affectation de a,x,rdans les arguments de la fonction.
Loovjo
1
J'ai joué votre code avec quelques octets ... ce n'est pas beaucoup, mais il faudra faire. Cela vous dérange-t-il si je modifie votre réponse et si je change de version de Python en Python 2?
clismique
@ Qwerp-Derp: N'hésitez pas! J'aimerais voir ce que tu as fait.
Andrew Epstein
3

JavaScript, 418 416 406 400 393 octets

Crée une fonction anonyme qui affiche le résultat sur la console.

var f =
    t=>{a=(q,w)=>Math.max(q,w);c=_=>{x=a(p[0],x);y=a(p[1],y);m[p]=(g(p)+1)%4;if(!m[p]){s.push([p[0],p[1]]);}};x=y=0,m={};g=k=>{v=m[k];return!v?0:v;};m[o=[0,0]]=1;s=[];while(--t){m[o]=(m[o]+1)%4;if(!m[o]){s.push(o);}while(s.length){p=s.pop();p[0]++;c();p[0]-=2;c();p[0]++;p[1]++;c();p[1]-=2;c();p[1]++;}}s='';for(i=-x;i<=x;i++){for(j=-y;j<=y;j++){v=g([i,j]);s+=v==0?'.':v;}s+='\n';}console.log(s);}
<input id="i" type="number"><input type="button" value="Run" onclick="var v = +document.getElementById('i').value; if (v>0) f(v)">

Hetzi
la source
1
Attention: j'ai appuyé sur 'run' sans entrée et mon écran s'est écrasé (boucle infinie). Ne sois pas aussi bête que moi.
roberrrt-s
1
@Roberrrt J'ai mis à jour ma réponse pour éviter cela.
Hetzi
3

Nim, 294 caractères

import os,math,sequtils,strutils
var
 z=parseFloat paramStr 1
 y=z.sqrt.toInt+1
 w=y/%2
 b=y.newSeqWith newSeq[int] y
 x=0
proc d(r,c:int)=
 b[r][c]+=1;if b[r][c]>3:b[r][c]=0;d r-1,c;d r,c+1;d r+1,c;d r,c-1
for i in 1..z.toInt:d w,w
while b[w][x]<1:x+=1
for r in b[x..< ^x]:echo join r[x..< ^x]

Compiler et exécuter:

nim c -r sandbox.nim 1000

Remarques:

  1. J'ai été en mesure de proposer une version plus courte qui utilise une taille de table fixe, mais je l'ai modifiée en faveur de la version dynamique.
  2. Une fois que le bac à sable est calculé, xest calculé comme le nombre de colonnes zéro au début de la ligne du milieu.
  3. Pour l'affichage, la table est découpée en excluant les xlignes et les colonnes de chaque extrémité.

Performance

nim c --stackTrace:off --lineTrace:off --threads:off \ 
      --checks:off --opt:speed sandbox.nim

time ./sandbox   10000       0.053s
time ./sandbox   20000       0.172s
time ./sandbox   30000       0.392s
time ./sandbox   40000       0.670s
time ./sandbox  100000       4.421s
time ./sandbox 1000000    6m59.047s
Danny Kirchmeier
la source
3

Scala, 274 octets

val t=args(0).toInt
val s=(Math.sqrt(t)+1).toInt
val (a,c)=(Array.ofDim[Int](s,s),s/2)
(1 to t).map{_=> ?(c,c)}
println(a.map{_.mkString}.mkString("\n"))
def?(b:Int,c:Int):Unit={
a(b)(c)+=1
if(a(b)(c)<4)return
a(b)(c)=0
?(b+1,c)
?(b-1,c)
?(b,c+1)
?(b,c-1)
}

Usage:

scala sandpile.scala <iterations>

Je ne pense pas qu'il y ait beaucoup à expliquer à propos de celui-ci. Fondamentalement, il ajoute juste un grain de sable au centre. Ensuite, vérifie si elle est plus grande que 4, si c'est le cas, cela va déborder et vérifier que tous les voisins plus grands que 4, débordent, etc. C'est assez rapide.

Performance:

  • t = 10000 72ms
  • t = 20000 167ms
  • t = 30000 419ms
  • t = 40000 659ms
  • t = 100000 3413ms
  • t = 1000000 environ 6 minutes
AmazingDreams
la source
Mon programme suggère que, centré à (0,0), le tas de sable atteigne d’abord un rayon de 15 à t = 1552. Cela nécessiterait un tableau 31x31 à stocker (coordonnées -15 à 15 inclus). Etes-vous sûr que c'est correct avec t = 5000?
Eric Tressler
Je ne suis pas sûr que ce soit correct, bien que je pense avoir compris la logique? Je reçois une exception d'index de tableau hors limite sur t> 5593
AmazingDreams
Lorsque j'incrémente et que je vérifie immédiatement s'il y a des déversements, il sort des limites à t = 1552. Je dirais que c'est la bonne mise en œuvre. J'ai mis à jour le code.
AmazingDreams
Vos performances ne peuvent être dépassées que par la manipulation directe de tableaux en C ou en Fortran avec optimisation du compilateur. Je vous envie.
Andreï Kostyrka
@ AndreïKostyrka, oui, c’est là que scala brille! Ma sortie n'est pas conforme aux spécifications, donc je devrais travailler dessus
AmazingDreams
2

J, 76 octets

p=:0,.~0,.0,~0,]
p`(4&|+3 3([:+/@,*&(_3]\2|i.9));._3[:<.4%~p)@.([:*/4>{.)^:_

Je définis un verbe pqui met une bordure de zéros autour de l’entrée. Le verbe principal prend un tableau en entrée. Il vérifie ensuite la première ligne pour tout tas de sable contenant 4 grains ou plus. Si tel est le cas, il génère le même tableau, à l'exception du remplissage p, et sinon, il effectue une convolution 2D pour simuler la chute des grains. Le verbe principal est répété jusqu'à la convergence en utilisant l'opérateur électrique ^:_.

Usage

   p =: 0,.~0,.0,~0,]
   f =: p`(4&|+3 3([:+/@,*&(_3]\2|i.9));._3[:<.4%~p)@.([:*/4>{.)^:_
   f 15
0 3 0
3 3 3
0 3 0
   f 50
0 0 0 1 0 0 0
0 0 3 1 3 0 0
0 3 2 2 2 3 0
1 1 2 2 2 1 1
0 3 2 2 2 3 0
0 0 3 1 3 0 0
0 0 0 1 0 0 0
   timex 'r =: f 50000'
46.3472
   load 'viewmat'
   ((256#.3&#)"0<.255*4%~i._4) viewmat r

Il faut environ 46 secondes pour calculer le résultat pour n = 50000. Le résultat peut être affiché à l'aide de l' viewmataddon avec un jeu de couleurs monochrome.

figure

milles
la source
2

C 229 (avec beaucoup d'avertissements)

G[99][99],x,y,a=99,b=99,c,d;S(x,y){if(++G[y][x]>3)G[y][x]=0,S(x+1,y),S(x-1,y),S(x,y+1),S(x,y-1);a=x<a?x:a;b=y<b?y:b;c=x>c?x:c;d=y>d?y:d;}F(t){for(;t--;)S(49,49);for(y=b;y<=d;y++){for(x=a;x<=c;x++)printf("%d ",G[y][x]);puts("");}}

/* call it like this */
main(_,v)char**v;{F(atoi(v[1]));}
Jerry Jeremiah
la source
Ok, j'abandonne: pourquoi votre tableau est-il 99 par 98?
Eric Tressler
@EricTressler Comment n'ai-je pas trouvé cela dans les tests?!
Jerry Jeremiah
1

PHP, 213 octets

function d($x,$y){global$p,$m;$m=max($m,$x);$q=&$p[$y][$x];if(++$q>3){$q=0;d($x+1,$y);d($x-1,$y);d($x,$y+1);d($x,$y-1);}}while($argv[1]--)d(0,0);for($y=-$m-1;$y++<$m;print"\n")for($x=-$m;$x<=$m;)echo+$p[$y][$x++];

crée récursivement la pile en se $psouvenant de sa taille $m; puis imprime avec des boucles imbriquées.
Courez avec -r.

Titus
la source