Ameobas di Manhattan in crescita


11

Un *** grafico ameoba **** è un tipo di albero i cui nodi hanno tutti valori da 0 a qualche numero intero non negativo N e qualsiasi nodo particolare con valore x <N si collega a x + 1 nodi distinti con valori x + 1.

Grafico ameoba per N = 3: (indicato con A 3 )

ameoba 3

Si noti che ai 2 non è consentito condividere nessuno dei 3; esattamente tre 3 devono "appartenere" a ciascun 2.

Sfida

Il tuo compito è "far crescere" induttivamente questi grafici ameoba in una griglia bidimensionale minimizzando avidamente la distanza di Manhattan tra i nodi:

  • Caso di base: uno 0 è semplicemente il grafico 0.
  • Fase induttiva: un N + 1 viene generato posizionando iterativamente i nuovi nodi valutati N + 1 il più vicino possibile ai nodi di valori N nella struttura A N esistente . (Può essere il più vicino possibile poiché i punti più vicini potrebbero già essere riempiti.)

Per la fase induttiva la procedura generale che devi seguire è:

for each existing node P with value N:
    for each new N+1 valued node Q you need to connect to P: //this loops N+1 times
        find the set of vacant spots that are minimally distant from P //by Manhattan distance
        place Q in any of these vacant spots

(Una procedura diversa con output indistinguibile va bene.)

Esempio di crescita per A 4 :

A0 is always the same:

0

For A1 I happen to put the 1 to the right of the 0 (it has to go on one of the 4 open sides):

01

For A2 I happen to put the two 2's above and to the right of the 1:

 2
012


For A3 I find that one of the six 3's I must place cannot be directly next to a 2, so I put in one of the next closest places:

 3
323
0123
  33 <-- this 3 is distance two away from its 2

The process continues in A4. Note that I'm iterating over each 3 and placing four 4's next to it or as close as possible, then moving to the next 3 (the order of 3's does not matter):

 444
443444
4323444
4012344
 44334
  4444
   44

Always keep in mind that nodes cannot be "shared".

Programma

Il programma che scrivi deve contenere un numero compreso tra 0 e 8 (incluso) e generare un grafico ameoba valido utilizzando il modello di crescita induttiva spiegato sopra.

Ciò che accade oltre l'8 non ha importanza.

(Un 8 contiene 46234 nodi che lo stanno spingendo. Qualsiasi cosa oltre A 8 sarebbe troppo lontana. Grazie a Martin Büttner per averlo notato.)

L'input dovrebbe provenire da stdin o dalla riga di comando e l'output dovrebbe andare in stdout o in un file.

Esempi (presi direttamente dall'alto)

Input: 0
Output:

0

Input: 1
Output:

01

Input: 2
Output:

 2
012

Input: 3
Output:

 3
323
0123
  33

Input: 4
Output:

 444
443444
4323444
4012344
 44334
  4444
   44

* Questo tipo di grafici potrebbe già avere un nome. Ammetto di averli appena inventati. ;)


Alla luce del tasso di crescita fattoriale, la domanda potrebbe essere cambiata dall'interruzione di A35 all'arresto di un file da 1 Megabyte o qualcosa di simile? A10 è la prima ameba con oltre un milione di caratteri.
isaacg,

@ MartinBüttner Ho raggiunto il limite 8 che è di circa 50k nodi. Ancora molto ma si spera gestibile.

Risposte:


6

Mathematica, 353 288 285 275 byte

n=Input[];f@_=" ";g={z={0,0}};i=f@z=0;For[r=Range,i++<n,g=Reap[(j=i;o={};For[d=0,j>0,o=Rest@o,If[o=={},o=Join@@({e={#,d-#},-e,e={d-#,-#},-e}&/@r@++d)];If[f[c=#&@@o+#]==" ",f@c=i;Sow@c;--j]])&/@g][[2,1]]];Riffle[(x=#;ToString@f@{x,#}&/@m~r~M)&/@r[m=Min@{g,0},M=Max@g],"
"]<>""

Ungolfed:

n = Input[];
f@_ = " ";
g = {z = {0, 0}};
i = f@z = 0;
For[r = Range, i++ < n,
  g = Reap[(
        j = i;
        o = {}; 
        For[d = 0, j > 0, o = Rest@o,
         If[o == {}, 

          o = Join @@ ({e = {#, d - #}, -e, e = {d - #, -#}, -e} & /@  
              r@++d)
          ];  
         If[f[c = # & @@ o + #] == " ",
          f@c = i;
          Sow@c;
          --j 
          ]   
         ]   
        ) & /@ g
     ][[2, 1]] 
  ];  
Riffle[(
     x = #;
     ToString@f@{x, #} & /@ m~r~M
     ) & /@ r[m = Min@{g, 0}, 
    M = Max@g
    ], "
  "] <> ""

Ecco un esempio di output per n = 5:

      5
     5555     
    555555    
   5555555    
  555555555   
 55555555555  
5555554445555 
5555544444555 
 5555443305555
 55554432144555
 55555443234555
  5555544344555
   555554445555
    5555555555
      5555555 
       55555  
       55     

L'ingresso 8dura circa 4,5 minuti.

Per una rapida suddivisione del mio algoritmo:

Sto usando due tabelle di ricerca fe g. Il primo è solo una mappa sparsa contenente le celle non vuote. Quest'ultimo è un elenco che contiene tutte le coppie di coordinate per ciascun valore di cella (penso che non ho nemmeno bisogno di tenere traccia di quelle vecchie qui). Sto ripetendo le coordinate gper estendere ogni cella dall'ultima iterazione. Per fare ciò, eseguo l'iterazione sulle distanze di Manhattan, creando tutti i possibili vettori per ciascuna distanza e controllando se la cella risultante è ancora vuota (nel qual caso la riempio). Ripetere l'operazione fino a quando non sono state create abbastanza nuove celle.

Quando ho finito, trovo la coordinata minima e massima ge creo una griglia appropriata, che viene riempita cercando le celle f. Il resto è semplicemente unire tutto in un'unica stringa con interruzioni di riga.


5

C - 309 305 301 275 byte

Meh, troppo a lungo ... se solo uno potesse scrivere #Do qualcosa invece di #define, allora C sarebbe davvero fantastico. Ovviamente i -Dflag del compilatore sono possibili, ma mi sembra imbroglione, avere personaggi diversi da quelli nel file sorgente.

Istruzioni per l'esecuzione:

Stai attento! Il primo tasto premuto dopo l'avvio del programma costituisce l'input. Quando si immette un personaggio diverso da '0' a '8', chissà quali cose indefinite accadranno.

#define F(D,O)x=*r+O d;for(c=d;h*c--;x+=D)!g[x]?g[*w++=x]=l,--h:5;
L=400;g[1<<18];n;s;*r;*w;*m;h;l;d;x;main(c){n=getch()-32;r=w=g+L*L;for(l=g[*w++=80200]=16;l++<n;)for(m=w;r<m;r++)for(d=1,h=l-16;h;d++){F(L+1,-)F(L-1,-L*)F(-L+1,L*)F(~L,)}for(n=L*L;--n;)putch(n%L?g[n]+32:10);}

Versione non golfata (ma già pensando al golf futuro):

void exit(int);

#define L 400

#define FIND(D, X0)   x = *pread X0 d; \
                for(c = d; c--; x+=D) { \
                    if(x%L == 0 || x%L == L-1 || x/L == 0 || x/L == L-1) \
                        exit(5); \
                    if(!g[x]) { \
                        g[*pwrite++ = x] = '0' + l; \
                        if(!--children) \
                            goto pnext; \
                    } \
                }

main()
{
    int n = getch() - '0';
    //char g[3] = {};
    char g[L*L] = {};
    int plist[46324];

    int *pwrite = plist, *pread = plist;
    *pwrite++ = L/2*L + L/2;
    g[*plist] = '0';
    int factorial = 1;
    int l,  c, parents, children, d, x;
    for(l = 1; l <= n; l++) {
        for(parents = factorial; parents--; pread++) {
            children = l;
            for(d = 1; ; d++) {
                FIND(L + 1, - )
                FIND(L - 1, -L* )
                FIND(-L + 1, +L* )
                FIND(-L - 1, + )
            }
            pnext:;
        }
        factorial *= l;
    }
    int i;
    for(i = L*L; i--; )
        putch(i%L ? (g[i] ? g[i] : ' ') : '\n');
}

Modifica: mi sono reso conto che da quando ho spostato le dichiarazioni al di fuori di main (), le matrici non possono più essere allocate nello stack, quindi sono libero di usare la memoria in modo disastroso senza rischio di overflow.


2

Rubino - 296

g=[s=' ']*d=10**6
$*[g[50500]=0].to_i.times{|c|d.times{|x|g[x]==c&&(r=1;a=c;(4.times{|v|r.times{|w|g[q=x+r*(1e3*(v-1-v/2)+v%2-v/2)+w*(1e3*~0**(v/2)+~0**v)]==s&&a>~0?(g[q]=c+1;a-=1):0}};r+=1)while~0<a)}}
g=g.join.scan(/.{1000}/)
g.map{|s|s[/\d/]&&(puts s[g.map{|s|s[/\A */].size}.min..-1].rstrip)}

Leggermente ungolfed.

g=[s=' ']*d=10**6 # Initialize a big 1d array as a 2d grid
$*[g[50500]=0].to_i.times{|c| # For n times
    d.times{|x| # For each index in the grid
        g[x]==c&&( # If the element at x is equal to the current growth stage, c
            r=1;   # Initial manhattan radius = 1
            a=c;   # a is number of times the ameoba must replicate
            (4.times{|v| # For each of the 4 sides of the manhattan diamond
                r.times{|w| # For each node in each side
                    # Spawn the 'c+1' ameoba's from the c ameobas... 
                    # The messy formula gives the index of the space in the grid to try spawning
                    g[q=x+r*(1e3*(v-1-v/2)+v%2-v/2)+w*(1e3*~0**(v/2)+~0**v)]==s&&a>~0?(g[q]=c+1;a-=1):0 
                }
            };
            r+=1 # Increase the raidus of the manhattan diamond by one
            ) while~0<a # while not enough ameoba's have been spawned
        )
    }
}
g=g.join.scan(/.{1000}/) # Join the 1d array into a huge string and slice it into rows
# Strip away the empty spaces all around the graph and print it
g.map{|s|s[/\d/]&&(puts s[g.map{|s|s[/\A */].size}.min..-1].rstrip)} 

2

APL (Dyalog) (121)

{0::0⋄V←,⍳⍴Z←' '⍴⍨2/M←⌈4×.5*⍨3÷⍨+/!⍳⍵⋄Z[G;G←⌈M÷2]←'0'⋄Z⊣{⍵∘{⍵∘{+((⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺])⌷Z)←⍕⍵}¨⍺/⍺}¨V/⍨,Z=⍕⍵-1}¨⍳⍵}⎕

Caratteristiche prestazionali: è O (n!). Sul mio sistema, fino a n = 5 è istantaneo; n = 6 richiede un secondo, n = 7 richiede un minuto e n = 8 richiede un'ora.

Versione senza golf

Test:

      {0::0⋄V←,⍳⍴Z←' '⍴⍨2/M←⌈4×.5*⍨3÷⍨+/!⍳⍵⋄Z[G;G←⌈M÷2]←'0'⋄Z⊣{⍵∘{⍵∘{+((⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺])⌷Z)←⍕⍵}¨⍺/⍺}¨V/⍨,Z=⍕⍵-1}¨⍳⍵}⎕
⎕:
      5





           5555             
          555555            
         55555555           
        5555445555          
       555544445555         
      55554433445555        
     5555444323445555       
    5555544321455555        
     555554430455555        
     555555444555555        
       555555555555         
        5555555555          
         55555555           
          55555             
           555              

Spiegazione:

  • {...}⎕ : leggi una riga dalla tastiera, valutala e passa il risultato alla funzione.
  • 0::0: se l'altro codice genera un errore, restituisce un singolo 0. Questo perché la matematica non riesce quando si tenta di calcolare la dimensione di un grafico con 0 nodi, che è il caso in cui dovrebbe essere l'output 0. (La versione precedente aveva ⍵=0:0, (se l'input è 0return, 0altrimenti crea il grafico), ma 0::0(basta provarlo e restituirlo 0se fallisce) è più breve.)
  • M←⌈4×.5*⍨3÷⍨+/!⍳⍵: supponendo che l'output sia un cerchio grezzo (funziona), sommare i fattoriali da 1a (= area di output), dividere per 3 (abbastanza vicino a pi), prendere la radice quadrata (fornendo il raggio di output), moltiplicare per 4, e prendi il soffitto. Questo dà il doppio del diametro del cerchio, quindi l'uscita si adatta allo spazio libero. Conservalo inM .
  • V←,⍳⍴Z←' '⍴⍨2/M: crea una matrice M-by-M di spazi e conservala in Z. Questo conterrà l'output. Memorizza un elenco delle coordinate di tutti gli elementi in V.
  • Z[G;G←⌈M÷2]←'0': imposta l'elemento centrale di Za 0.
  • Z⊢{... }¨⍳⍵: restituisce Z, dopo aver applicato la seguente funzione ai numeri 1a :
    • ⍵∘{... }V/,Z=⍕⍵-1: per ogni elemento in Zcon il valore del nodo precedente:
      • ⍵∘{...}⍺/⍺ : per il nodo corrente, N volte,
        • ⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺]: ottieni lo spazio libero più vicino al nodo corrente,
        • (... ⌷Z)←⍕⍵: e imposta quello spazio Zsul valore del nodo corrente.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.