Sculture magnetiche


14

Questa è una continuazione libera della mia precedente sfida sulla costruzione di grafici .

sfondo

Un artista eccentrico ti ha assunto per stimare l'integrità strutturale delle sue sculture. Crea le sue opere d'arte prendendo un gruppo di magneti a forma di cubo e facendoli cadere uno ad uno in una pila enorme. Per analizzare meglio il suo metodo, utilizziamo il seguente modello bidimensionale. Iniziamo con un piano vuoto e rilasciamo un magnete #su qualsiasi coordinata intera, ad esempio 0:

       |
       v
       #
===============
       0

Se un altro magnete viene lasciato cadere 0, finisce sopra a quello precedente:

       |
       v
       #
       #
===============
       0

Ora lasciamo cadere un altro magnete su 0, e poi uno su 1:

        |
       #v
       ##
       #
===============
       0

Come visto sopra, un magnete che cade si attacca al secondo magnete che passa (il primo semplicemente lo rallenta). Il secondo magnete non deve essere direttamente sotto il primo e un magnete su entrambi i lati conta comunque come un magnete:

      #   #
      ##|##
      # v #
      ### #
      #   #
===============
       0

L'artista vuole che calcoli il massimo spazio verticale nella scultura finale, ovvero il numero massimo di spazi vuoti tra due magneti sulla stessa colonna o un magnete e il terreno sottostante. Nell'immagine sopra, questo numero sarebbe 3 (sulla colonna 2).

Ingresso

Un elenco di numeri interi, che rappresentano le coordinate in cui l'artista rilascia i suoi magneti, letti da sinistra a destra. Si può presumere che le coordinate soddisfino -1024 <= i < 1024e che la lunghezza dell'elenco sia al massimo 1024, se ciò aiuta.

Produzione

Il massimo divario verticale nella scultura finale. La scultura vuota ha spazio -1, e questo caso deve essere incluso, poiché il nostro scultore è un dadaista.

Regole aggiuntive

Puoi dare una funzione o un programma completo. Vince il conteggio dei byte più corto e le scappatoie standard non sono ammesse. Il codice con spiegazioni è preferito.

Casi test

[] -> -1
[0,2,1] -> 0
[0,0,0,0,0,1,-1] -> 3
[0,0,0,0,0,1,1,1,2] -> 4
[1,1,2,2,2,2,2,2,1] -> 2
[1,1,2,2,2,2,2,2,1,0,1,0] -> 2
[1,2,1,2,1,2,1,2,2,2,2,1,0] -> 3
[-1,-1,-1,1,1,1,0] -> 1
[-1,-1,-1,-1,2,2,1,1,2,2,2,1,0] -> 2
[-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,4,4,5,5,5,6] -> 6

Risposte:


1

Dyalog APL, 73 70 caratteri

{y←⍬⋄⌈/¯1,,¯1-2-/0,x⊢⌸{y,←⌈/(1+y/⍨0=⍵),Y⊃⍨2⊃⍒Y←1 1,∪y/⍨1=⍵}¨|x-¯1↓¨,\x←⍵}

{y←⍬⋄¯1⌈⌈/,¯1-2-/¯1,⍵⊢⌸{y,←⌈/(1+y/⍨0=⍵),⊃1↓{⍵[⍒⍵]}∪y/⍨1=⍵}¨|⍵-¯1↓¨,\⍵}

First statement:
       y←⍬  initialize semi-global variable y with an empty vector
Second statement, from right to left:
         ⍵  the vector of x coordinates
       ,\⍵  concat-scan: all prefixes of ⍵ of length 1, 2, ..., ≢⍵
   ¯1↓¨,\⍵  drop the last element of each prefix, lengths are 0, 1, ..., (≢⍵)-1
|⍵-¯1↓¨,\⍵  for each x: magnitudes of differences between x and its predecessors
 {...}¨...  execute the code in parens for each item of the argument
         ⍵  is now a single vector of differences from those described above
       1=⍵  boolean mask, where are our neighbouring xs?
    y/⍨1=⍵  select the ys corresponding to our neighbouring xs
   ∪y/⍨1=⍵  unique ys
   {⍵[⍒⍵]}  sort descending
       ⊃1↓  first of one-drop, i.e. get the second element if it exists, otherwise 0
       0=⍵  which previous xs are the same as our x?
  1+y/⍨0=⍵  select the corresponding ys and add 1 to them
        ⌈/  maximum of all the ys described so far
       y,←  append to the semi-global y
            the result from {} will be identical to y
  ⍵⊢⌸{...}  a matrix of ys, grouped in rows by x (which is now in ⍵) and zero-padded
       ¯1,  prepend ¯1 to the left of each row
       2-/  differences between consecutive horizontal elements, result is a matrix
       ¯1-  negative one minus each element of the matrix
         ,  ravel the matrix (linearize it to a vector)
        ⌈/  maximum; if the vector is empty, return ¯1.8e308, a very small number
     ¯1⌈⌈/  greater of ¯1 and the ⌈/  to avoid the very small number

Nota: questa lunghezza è di 122 byte (la sfida è in byte), presupponendo UTF-8.
MtnViewMark


Sono abbastanza comprensivo: spesso sono stato oscurato dall'uso di caratteri non ASCII nel mio Haskell da golf. Da allora sono stato abbastanza attento se la Q specifica il conteggio per caratteri o byte.
MtnViewMark

@MtnViewMark Il punteggio per byte non significa un punteggio per UTF-8 byte. Farlo per APL significa punirlo per essere troppo vecchio per riconoscere ASCII come uno standard importante. Il set di caratteri di APL si adatta facilmente all'interno di una tabella codici a byte singolo e quella tabella codici esiste . Quindi, usando quella tabella codici come codifica, ogni carattere è un byte. D'altra parte, se usi caratteri non ASCII in Haskell, dovrai usare una codifica che contiene sia i caratteri ASCII che non ASCII - e di solito è UTF-8.
Martin Ender,

@ngn - dopo aver letto la maggior parte dei meta post su questo, sembra che le cose siano purtroppo ancora confuse. Tuttavia, forse sarebbe meglio, quando la sfida è segnata in byte, segnare APL in byte, ma menzionare da qualche parte la codifica utilizzata.
MtnViewMark

4

Haskell - 217 185 182 byte

import Data.List
r g n m|m==n=max(head(g m)+1)((reverse.(0:).nub.sort$g(m-1)++g(m+1))!!1):g m|1<3=g m
j x=(-1)-minimum(0:(map(foldl r(\_->[0])x)[-1024..1024]>>=(tail>>=zipWith(-))))

Uso:

j [1,2,1,2,1,2,1,2,2,2,2,1,0]

Questa funzione crea un'altra funzione che restituisce un elenco di posizioni y del magnete per una data posizione x. Con esso, calcola gli spazi per tutte le posizioni x -1024 .. 1024 e prende il massimo (Modifica: ora sto prendendo il minimo, perché gli spazi sono negativi: più basso è il numero più grande è lo spazio).


Approccio intelligente! Spero non ti dispiaccia che io abbia smesso di giocare un po '.
MtnViewMark,

@MtnViewMark: Niente affatto. Ho trovato altri 3 byte da salvare: non flipil -, vai con numeri negativi e prendi il minimum.
nimi,

Nel mio repository, è possibile trovare questo codice, 42997-Magnetic.hs che include anche un cablaggio di prova per i casi di test e un visualizzatore che visualizza le sculture.
MtnViewMark

3

Javascript, 201 193

F=P=>{m=[];for(p of P){s=2;c=m[p]=m[p]||[];for(i=1e4;~i&&s;i--){if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;if(c[i-1]) s=0}c[++i]=1}g=-1;m.map(c=>{ d=0;for(i in c){g=i-d>g?i-d:g;d=++i} });return g}

F ([1,1,2,2,2,2,2,2,1]) === 2

O versione leggibile

F=P=>{
  m=[];  // magnet positions
  for(p of P){ // every dropped magnet
    s=2; // initial speed
    c=m[p]=m[p]||[]; // column where magnet is dropping
    for(i=1e4;~i&&s;i--){ // continue until at floor or zero speed
      if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;  // magnet on either side, decrease speed
      if(c[i-1]) s=0; // magnet is directly below
    }
    c[++i]=1;
  }
  g=-1; // maximum gap
  m.map(c=>{ 
          d=0;for(i in c){g=i-d>g?i-d:g;d=++i;} 
       });
  return g;
};

2

Python 2.7, 327

from itertools import * 
s=input()
if s:m=min(s);l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i];c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:];j=len(c)-c.index(1)-1-len(r) if any(c) else 0;l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

Prima del golf degli spazi bianchi, è simile al seguente:

from itertools import * 
s=input()
if s:
    m=min(s)
    l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i]
    c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:]
    j=len(c)-c.index(1)-1-len(r) if any(c) else 0
    l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

Ecco una spiegazione delle linee più complesse, principalmente a mio vantaggio.

l=[[] for _ in range(max(s)-m+3)] 

Questo crea una matrice di elenchi vuoti di lunghezza massima (gocce) -min (gocce) +1 più un segnaposto su entrambi i lati. Voglio sempre scrivere [[]] * K per costruire una matrice di elenchi vuoti, ma ciò rende K puntatori allo stesso elenco vuoto.

c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:] 

La funzione izip_longest di itertools è come zip, ma riempie l'elenco più breve con Nessuno per comprimere gli elenchi insieme. Lo slicing [:: - 1] inverte l'elenco di 0 e 1 dal confronto "o". L'elenco è invertito per utilizzare il metodo index nella riga successiva, che trova la prima istanza di un elemento. Poiché l'ultimo elemento di una colonna non vuota deve essere 1, questo è il primo elemento nell'elenco invertito e viene ignorato tramite la sezione [1:].

j=len(c)-c.index(1)-1-len(r) if any(c) else 0 
l[i]=r+[0]*j+[1]

Calcola innanzitutto la differenza tra la lunghezza della colonna i e la posizione del secondo 1 nelle colonne adiacenti. Se la differenza è positiva, aggiungi molti zeri alla colonna i prima di aggiungere un 1. Qualsiasi numero non positivo volte [0] è l'elenco vuoto.

max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

La funzione groupby di itertools divide un elenco in sottosequenze di elementi consecutivi. Questa riga trova il massimo delle lunghezze di tutte le sottosequenze di zeri in tutte le colonne. È necessario eseguire il cast di ogni sottosequenza q in un elenco, perché groupby restituisce un generatore (come tutte le funzioni di itertools) che naturalmente non supporta un metodo len.


1

Java - 281 byte

Abbastanza diretto.

Prima costruisce la scultura in una matrice

Quindi trova il divario più grande.

int a(int[]b){
        int[][]d=new int[9999][9999];
        int g,r,t,y=-1;
        for(int c:b){
            c+=5000;
            g=0;
            for(r=9998;r>=0;r--){
                if(r==0||d[c][r-1]==1){d[c][r]=1;break;}
                if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}
            }
        }
        for(int[] k:d){
            t=0;
            for(int i:k){
                if(i==0)t++;
                else{if(t>y)y=t;t=0;}
            }
        }
        return y;
    }

piccolo -

int a(int[]b){int[][]d=new int[9999][9999];int g,r,t,y=-1;for(int c:b){c+=5000;g=0;for(r=9998;r>=0;r--){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[] k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}

È possibile salvare un byte sostituendo il primo ||con |. Inoltre, la restituzione yanziché la stampa consente di risparmiare 9 byte.
Ypnypn,

@Ypnypn, grazie! A proposito, la tua prima affermazione sembra generare un'eccezione ArrayIndexOutOfBounds (-1). (Non ho molta esperienza con gli operatori bit a bit)
Stretch Maniac

E 'stato di circa 1,5 anni, ma si può golf ancora un po': ( 272 byte ): int a(int[]b){int z=9999,d[][]=new int[z][z],g,r,t,y=-1;for(int c:b){c+=z/2;g=0;for(r=z;--r>-2;){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1|d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[]k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}. Riepilogo delle modifiche: z=9999è stato aggiunto e utilizzato; inte l' int[][]inizializzazione dei campi è stata fusa in una; il secondo ||è sostituito da |; for(r=9998;r>=0;r--)è stato modificato infor(r=z;--r>-2;)
Kevin Cruijssen il
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.