Mappa stringa sulla curva di Hilbert


27

Mappiamo alcune stringhe sullo spazio 2d, in stile frattale. Il tuo compito è calcolare una curva di Hilbert e posare una stringa lungo di essa.

La curva di Hilbert, iterazioni da 1 a 8

Compito

Il compito è prendere la stringa di input a linea singola e disporla lungo una curva di Hilbert abbastanza grande da contenerla, ma non più grande. Prova a rendere il conteggio dei byte il più basso possibile; dopo tutto questo è !

condizioni

  • Eventuali spazi vuoti devono essere riempiti con spazi bianchi, ma non è richiesto il riempimento alla fine delle linee.
  • L'inizio della linea dovrebbe essere nell'angolo in alto a sinistra e la fine in basso a sinistra.
  • È possibile creare un programma o una funzione.
  • Potrebbero comparire alcuni nuovi casi di test, quindi non codificare nulla!

bonus

Nota: i bonus si accumulano in questo modo: -50% & -20% on 100B= -20% on 50Bo -50% on 80B= 40B.

  • -50% Se l'input è una stringa multilinea, invertire il processo per creare l'input originale. Casi di prova per il bonus: basta usare quelli esistenti (compresi i casi di prova bonus!)
  • -20% Se si rimuove tutto lo spazio bianco non necessario dall'output (ad esempio alla fine di una riga).
  • -5% Se non inquini lo spazio dei nomi globale (sai cosa intendo!)

Casi test

abcdefghijklmn

adef
bchg
 nij
 mlk


The quick brown fox jumps over the lazy dog.

Thn f ju
 ewooxpm
qckr rs 
ui btevo
    hlaz
    e  y
      do
      .g

E per il bonus di stripping degli spazi bianchi:

No  hitespac  her 

Noher

hesc
itpa

Classifica

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, utilizzando il seguente modello Markdown:

# Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Se si desidera includere più numeri nell'intestazione (ad es. Perché il punteggio è la somma di due file o si desidera elencare separatamente le penalità del flag dell'interprete), assicurarsi che il punteggio effettivo sia l' ultimo numero nell'intestazione:

# Perl, 43 + 2 (-p flag) = 45 bytes

Puoi anche rendere il nome della lingua un collegamento che verrà quindi visualizzato nello snippet della classifica:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

Se qualcuno potesse fare qualche altro test, sarebbe apprezzato.
wizzwizz4,

Quindi i caratteri dovrebbero essere rappresentati dai vertici della curva?
flawr

No..hitespac..her.dove i punti sono spazi sarebbe un caso di prova migliore per il bonus. (E attualmente, nel test case manca il finale .)
Martin Ender,

Se stai adottando l'approccio L-system, potresti anche provare http: // codegolf / questions / 48697 / ascii-l-system-renderer . Potrebbe aiutarti a golfare le tue risposte.
wizzwizz4,

Risposte:


7

CJam, 119 117 113 112 109 * 0,5 * 0,8 = 43,6 byte

Grazie a Dennis per aver salvato 1 byte.

Ecco un inizio ...

{+e`W<e~}:F;q_N-,4mLm]0aa{4\#4e!1=f*\:G[zGGW%zW%G].ff+2/{~.+~}%}@:L/\_N&{N/]z:z:~$1f>sS}{4L#' e]f{f=SF}N*N}?F

Prova la trasformazione in avanti . Prova la trasformazione inversa.

Sono sicuro che c'è un modo più breve per generare la curva ...

Spiegazione

Innanzitutto, definisco una funzione per tagliare alcuni elementi dalla fine di un array, perché ne ho bisogno in diversi punti. Si aspetta l'array e l'elemento (all'interno di un array separato) in cima allo stack.

{
  +  e# Append the element to the array.
  e` e# Run-length encode.
  W< e# Discard last run.
  e~ e# Run-length decode.
}:F; e# Store in F and discard.

Ora la maggior parte del codice determina la dimensione della curva di Hilbert richiesta e la costruisce come matrice 2D in cui gli elementi sono indici lungo la curva. Costruisco questo sulla base della seguente osservazione:

Considera la curva di Hilbert 2x2:

01
32

La curva di Hilbert 4x4 è:

0345
1276
ed89
fcba

Se sottraggiamo il valore minimo da ciascun quadrante (e li separiamo un po 'per chiarezza visiva), otteniamo:

03 01
12 32

21 01
30 32

Questo modello vale per qualsiasi dimensione. Significa che possiamo costruire il livello successivo da quello attuale, usando come i quattro quadranti: a) il recepimento del livello corrente, b) il livello corrente stesso, c) il recepimento lungo l'anti-diagonale, d) di nuovo il livello attuale stesso. E poi li compensiamo 0, 1, 3, 2 volte la dimensione del livello corrente, rispettivamente.

q           e# Read input.
_N-         e# Make a copy and remove all linefeeds.
,4mLm]      e# Take that string's length's logarithm with base 4, rounded up.
            e# This is the Hilbert curve level we need.
0aa         e# Push [[0]] as the level-0 Hilbert curve.
{           e# Store the Hilbert curve level in L. Then for each i from 0 to L-1...
  4\#       e#   Compute 4^i. This is the offset of the four quadrants.
  4e!1=     e#   Get [0 1 3 2] as the second permutation returned by 4e!.
  f*        e#   Multiply each of them by the offset.
  \:G       e#   Swap with the Hilbert curve so far and call it G.
  [         e#   Create an array with...
    z       e#     The transpose of G.
    G       e#     G itself.
    GW%zW%  e#     The anti-diagonal transpose of G.
    G       e#     G itself.
  ]
  .ff+      e#   Add the appropriate offsets to the indices in each of the four quadrants.
  2/        e# Split into a 2x2 grid.
  {         e# Map this onto each pair of quadrants...
    ~       e#   Dump both quadrants on the stack.
    .+      e#   Concatenate them line by line.
    ~       e#   Dump the lines on the stack.
  }%        e# Since this is a map, the lines will automatically be collected in an array.
}@:L/

Infine, utilizziamo questa curva di indici di Hilbert per applicare la trasformazione appropriata all'input:

\_        e# Swap the curve with the input and make another copy.
N&{       e# If the input contains linefeeds, execute the first block, else the second...
  N/      e#   Split the input into lines. The stack now has a grid of indices and a grid
          e#   of characters.
  ]z:z:~  e#   This is some weird transposition magic which zips up the indices with the
          e#   corresponding characters from both grids, and finally flattens the grid
          e#   into a linear list of index/character pairs. Those cells that don't have
          e#   characters due to trimmed whitespace in the input will be turned into
          e#   arrays containing only an index.
  $       e#   Sort the pairs (which sorts them by indices).
  1f>     e#   Discard the indices.
  s       e#   Flatten the result into a single string.
  S       e#   Leave a space on the stack to be trim trailing spaces later.
}{        e# or...
  4L#     e#   Compute the size of the Hilbert curve.
  ' e]    e#   Pad the input to that size with spaces.
  f{      e#   Map this block over lines of the curve, passing the padding input as an
          e#   additional parameter...
    f=    e#     For each index in the current line, select the appropriate character
          e#     from the padded input.
    SF    e#     Trim spaces from the end of the line.
  }
  N*      e#   Join the lines with linefeed characters.
  N       e#   Leave a linefeed on the stack to be trim trailing linefeeds later.
}?
F         e# We left either a space or a linefeed on stack... trim that character from
          e# the end of the string.

3

Python 3, 467 434 423 457 451 426 386 374 342 291 304 * 80% * 95% = 231,04 byte

Il modo in cui funziona è che creo la curva di Hilbert usando un sistema Lindenmayer e seguo le istruzioni sinistra, destra e avanti lungo una serie di stringhe. Tuttavia, ci sono probabilmente molti modi in cui questo potrebbe essere giocato a golf meglio; specialmente nei condizionali e nel creare la matrice di stringhe. (Ho tentato [" "*p for i in range(p)]ma le stringhe non supportano l'assegnazione degli oggetti (apparentemente). Se potessi farlo funzionare, potrei anche liberarmi del join)

Modifica: golfato alcuni dei condizionali grazie a Dennis . E ho giocato a golf lungo la serie di stringhe. E una modifica senza byte perché i risultati stavano venendo trasposti rispetto agli esempi sopra.

Modifica: implementato il bonus di stripping degli spazi bianchi.

Modifica: risolto un bug nel mio codice di stripping degli spazi bianchi per altri sei byte

Modifica: poiché questa risposta non inquina lo spazio dei nomi globale, ottengo il bonus del 5%, secondo wizzwizz4 qui .

Modifica: modificato il modo in cui gviene incrementato e decrementato. Ora usando eval()e str.translate.

Modifica: questa risposta ora è un programma anziché una funzione.

Modifica: risolti alcuni bug del golf precedente.

s=input();m=(len(bin(len(s)-1))-1)//2;t=eval("[' ']*2**m,"*2**m);t[0][0],*s=s;x=y=g=0;b="A";exec("b=b.translate({65:'-BF+AFA+FB-',66:'+AF-BFB-FA+'});"*m)
while s:
 c,*b=b;g+=(c<"-")-(c=="-")
 if"B"<c:x,y=[[x+1-g%4,y],[x,y+g%4-2]][g%2];t[x][y],*s=s
print("\n".join(''.join(i).rstrip()for i in t).rstrip())

Ungolfed:

# hilbert(it) is now implemented in the code with exec("b=b.translate")

def hilbert(it):
    s="A"
    n=""
    for i in range(it):
        for c in s:
            if c == "A":
                n += "-BF+AFA+FB-"
            elif c == "B":
                n += "+AF-BFB-FA+"
            else:
                n += c
        s=n;n=""
    return s

def string_to_hilbert(string):
    length = len(string)
    it = (len(bin(length-1))-1)//2
    hil = hilbert(it)
    pow_2 = 2**it
    # we use eval("[' ']*pow_2,"*pow_2) in the code, but the following is equivalent
    output = [[" "for j in range(pow_2)] for i in range(pow_2)]
    output[0][0] = string[0]
    x = 0
    y = 0
    heading = 0
    while string: # while there are still characters in string
        char, *hil = hil
        if char == "-": heading = heading - 1
        elif char == "+": heading = heading + 1
        elif char == "F":
            if heading % 4 == 3: y += 1
            elif heading % 4 == 2: x -= 1
            elif heading % 4 == 1: y -= 1
            else: x += 1
            output[x][y], *string = string
    array = [''.join(i).rstrip()for i in output]
    array = "\n".join(array).rstrip()
    print(array)
    return

Curioso del bonus del 5%. Le variabili sono automaticamente locali in Python?
edc65,

@ edc65 Ho chiesto allo sceneggiatore una cosa simile qui: chat.stackexchange.com/transcript/240?m=28529277#28529277 . Spero che aiuti un po '. In caso contrario, possiamo continuare la discussione in chat.
Sherlock9

2

Rubino, 358 356 344 322 319 * 80% * 95% = 242,44 byte

Questo è il mio codice Python traspilato in Ruby. Dovrei scrivere più risposte in Ruby. È una lingua decente per giocare a golf.

Modifica: ho dimenticato che le funzioni non hanno bisogno di essere nominate in questa domanda.

Modifica: poiché questa risposta non inquina lo spazio dei nomi globale, ottengo il bonus del 5%, secondo wizzwizz4 qui .

->s{l=s.size;m=((l-1).bit_length+1)/2;x=2**m;t=(1..x).map{[" "]*x};t[0][0]=s[0];x=y=g=z=0;d=1;b=?A;m.times{b=b.split("").map{|c|c==?A?"-BF+AFA+FB-":c==?B?"+AF-BFB-FA+":c}.join("")};(c=b[z];z+=1;g+=c<?-?1:c==?-?-1:0;(g%2>0?y+=g%4-2:x+=1-g%4;t[x][y]=s[d];d+=1)if c>?B)while d<l;puts (t.map{|i|(i*'').rstrip}*"\n").rstrip}

Ungolfed:

def map_string(string)
  len = string.size
  m = ((len-1).bit_length+1)/2
  pow = 2**m
  output = (1..pow).map{[" "]*pow}
  output[0][0] = s[0]
  x = y = heading = char_index = 0
  chars_in_output = 1
  b = ?A
  m.times do |j|
    a = b.split("").map do |char|
      if char == "A"
        "-BF+AFA+FB-"
      else if char == "B"
        "+AF-BFB-FA+"
      else
        char
      end
    end
    b = a.join("")
  end
  while chars_in_output < len
    char = b[char_index]
    char_index += 1
    if char == "-"
      heading += -1
    else if char == "+"
      heading += 1
    else if char == "F"
      if heading % 2 == 0
        y += heading % 4 - 2
      else
        x += 1 - heading % 4
      end
    end
    output[x][y] = string[char_index]
    char_index += 1
  end
  return (output.map{|i|(i*'').rstrip}*"\n").rstrip

Questo codice ha una doppia licenza sotto una licenza di codice? Vorrei produrre un lavoro derivato rilasciato sotto licenza GPL (anche se qualsiasi licenza compatibile con GPL funzionerà con questo). È attualmente rilasciato sotto CC BY-SA 3.0.
wizzwizz4,


1

JavaScript (ES6), 227 - 20%: 181,6 byte

m=>{for(n=1<<((33-Math.clz32(m.length-1))/2),t='',y=0;y<n;y++,t+=`
`)for(x=0;x<n;x++,t+=m[h]||' ')for(u=y,v=x,h=0,s=n;s>>=1;q||(p&&(u=s+~u,v=s+~v),[u,v]=[v,u]))h+=s*s*(3*!!(p=u&s)^!!(q=v&s));return t.replace(/ +$/mg,'').trim()}

Cercare di ottenere il bonus del 5%

m=>{for(var n=1<<((33-Math.clz32(m.length-1))/2),t='',x,y=0;y<n;y++,t+=`
`)for(x=0;x<n;x++,t+=m[h]||' ')for(var p,q,u=y,v=x,h=0,s=n;s>>=1;q||(p&&(u=s+~u,v=s+~v),[u,v]=[v,u]))h+=s*s*(3*!!(p=u&s)^!!(q=v&s));return t.replace(/ +$/mg,'').trim()}

241 * 0,8 * 0,95: 183,16 più grande

Meno golf

m=>
{
  // calc the size of the bounding square, clz32 is a bit shorter than ceil(log2()
  n = 1<<( (33-Math.clz32(m.length-1)) / 2); 
  t = '';
  for(y = 0; y < n; y++) 
  {
    for(x = 0 ; x < n; x++)
    {
      // for each position x,y inside the square
      // get the index postion in the hilbert curve
      // see https://en.wikipedia.org/wiki/Hilbert_curve (convert x,y to d)
      for(u=y, v=x, h=0, s=n; s >>= 1; )
      {
        h += s*s*(3 * !!(p = u & s) ^ !!(q = v & s));
        q || (p && (u = s+~u, v = s+~v),[u,v]=[v,u])
      }
      // add char at given index to output  
      t += m[h]||' '; // blank if beyond the length of m
    }
    t += '\n'; // add newline add end line
  }
  return t.replace(/ +$/mg,'').trim() // to get the 20% bonus
}  

Test

F=m=>{for(n=1<<((33-Math.clz32(m.length-1))/2),t='',y=0;y<n;y++,t+=`
`)for(x=0;x<n;x++,t+=m[h]||' ')for(u=y,v=x,h=0,s=n;s>>=1;q||(p&&(u=s+~u,v=s+~v),[u,v]=[v,u]))h+=s*s*(3*!!(p=u&s)^!!(q=v&s));return t.replace(/ +$/mg,'').trim()}

function Test() { O.textContent = F(I.value) }

Test()
#I { width: 90% }
#O { border: 1px solid #ccc}
<input id=I oninput='Test()' value='The quick brown fox jumps over the lazy dog.'>
<pre id=O></pre>


Varrebbe la pena aggiungere vars per ottenere il bonus del 5%?
wizzwizz4,

var s,x,y,u,v,t,p,q,n,hno non vale la pena @ wizzwizz4
edc65

Puoi solo mettere varprima del primo utilizzo di ciascuno ... Oh, è anche peggio.
wizzwizz4,

@ wizzwizz4 tutto sommato, forse hai ragione ... ci sto provando ... no. Peccato
edc65 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.