Odwzoruj ciąg znaków na krzywą Hilberta

27

Zmapujmy niektóre ciągi znaków na przestrzeń 2d, styl fraktalny. Twoim zadaniem jest obliczenie krzywej Hilberta i ułożenie na niej sznurka.

Krzywa Hilberta, iteracje od 1 do 8

Zadanie

Zadanie polega na pobraniu wejściowego ciągu jednowierszowego i ułożeniu go wzdłuż krzywej Hilberta wystarczająco dużej, aby go pomieścić, ale nie większej. Staraj się, aby liczba bajtów była jak najniższa; w końcu to jest !

Warunki

  • Wszelkie odstępy należy uzupełnić spacjami, ale wypełnienie nie jest wymagane na końcu linii.
  • Początek linii powinien znajdować się w lewym górnym rogu, a koniec w lewym dolnym rogu.
  • Możesz utworzyć program lub funkcję.
  • Mogą pojawić się nowe przypadki testowe, więc nie koduj niczego!

Bonusy

Uwaga: Premie kumulują się w ten sposób: -50% & -20% on 100B= -20% on 50Blub -50% on 80B= 40B.

  • -50% Jeśli wejście jest ciągiem zawierającym wiele wierszy, odwróć proces, aby utworzyć oryginalne wejście. Przypadki testowe dla bonusu: wystarczy skorzystać z istniejących (w tym dodatkowe przypadki testowe!)
  • -20% Jeśli usuniesz wszystkie niepotrzebne białe znaki z wydruku (np. Na końcu wiersza).
  • -5% Jeśli nie zanieczyścisz globalnej przestrzeni nazw (wiesz o co mi chodzi!)

Przypadki testowe

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

A dla premii za usuwanie białych znaków:

No  hitespac  her 

Noher

hesc
itpa

Tabela liderów

Aby upewnić się, że Twoja odpowiedź się pojawi, zacznij od nagłówka, korzystając z następującego szablonu Markdown:

# Language Name, N bytes

gdzie Njest rozmiar twojego zgłoszenia. Jeśli poprawić swój wynik, to może zachować stare porachunki w nagłówku, uderzając je przez. Na przykład:

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

Jeśli chcesz umieścić w nagłówku wiele liczb (np. Ponieważ twój wynik jest sumą dwóch plików lub chcesz osobno wymienić kary za flagi tłumacza), upewnij się, że rzeczywisty wynik jest ostatnią liczbą w nagłówku:

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

Możesz także ustawić nazwę języka jako link, który pojawi się we fragmencie tabeli wyników:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes
wizzwizz4
źródło
Byłoby to mile widziane, jeśli ktoś mógłby zrobić więcej testów.
wizzwizz4,
Więc znaki powinny być reprezentowane przez wierzchołki krzywej?
flawr
No..hitespac..her.gdzie kropki są spacjami, byłby to lepszy przypadek testowy dla premii. (A obecnie przypadek testowy nie ma końca .)
Martin Ender,
Jeśli stosujesz podejście oparte na systemie L, możesz także spróbować http: // codegolf / pytania / 48697 / ascii-l-system-renderer . To może pomóc w golfa odpowiedzi.
wizzwizz4,

Odpowiedzi:

7

CJam, 119 117 113 112 109 * 0,5 * 0,8 = 43,6 bajtów

Dzięki Dennisowi za zaoszczędzenie 1 bajtu.

Oto początek ...

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

Sprawdź transformację do przodu . Sprawdź transformację odwrotną.

Jestem pewien, że istnieje krótszy sposób na wygenerowanie krzywej ...

Wyjaśnienie

Najpierw definiuję funkcję do przycinania jakiegoś elementu z końca tablicy, ponieważ potrzebuję go w kilku miejscach. Oczekuje tablicy i elementu (w osobnej tablicy) na górze stosu.

{
  +  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.

Teraz większość kodu określa rozmiar wymaganej krzywej Hilberta i konstruuje ją jako tablicę 2D, w której elementy są indeksami wzdłuż krzywej. Konstruuję to na podstawie następującej obserwacji:

Rozważ krzywą Hilberta 2x2:

01
32

Krzywa Hilberta 4x4 to:

0345
1276
ed89
fcba

Jeśli odejmiemy minimalną wartość od każdej ćwiartki (i oddzielimy ją trochę dla przejrzystości wizualnej), otrzymamy:

03 01
12 32

21 01
30 32

Ten wzór pasuje do każdego rozmiaru. Oznacza to, że możemy zbudować następny poziom z obecnego, używając jako czterech kwadrantów: a) transpozycji obecnego poziomu, b) samego poziomu prądu, c) transpozycji wzdłuż anty-przekątnej, d) ponownie obecny poziom. A następnie wyrównujemy je odpowiednio 0, 1, 3, 2 razy wielkości bieżącego poziomu.

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/

Na koniec używamy tej krzywej Hilberta indeksów, aby zastosować odpowiednią transformację do danych wejściowych:

\_        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.
Martin Ender
źródło
3

Pytona 3 467 434 423 457 451 426 386 374 342 291 304 * 80% * 95% = 231.04 bajtów

Działa to tak, że tworzę krzywą Hilberta za pomocą systemu Lindenmayera i postępuję zgodnie z instrukcjami po lewej, prawej i do przodu wzdłuż szeregu ciągów. Istnieje jednak prawdopodobnie wiele sposobów na lepszą grę w golfa; szczególnie w warunkach i tworzeniu tablicy ciągów. (Próbowałem, [" "*p for i in range(p)]ale łańcuchy nie obsługują przypisania elementów (najwyraźniej). Gdybym mógł to sprawić, mógłbym również pozbyć się przyłączenia)

Edycja: Grał w golfa dzięki warunkom dzięki Dennisowi . I grałem w golfa w szeregu strun. I zmiana bez bajtu, ponieważ wyniki były transponowane w porównaniu do powyższych przykładów.

Edycja: Wprowadzono premię za usuwanie białych znaków.

Edycja: Naprawiono błąd w moim kodzie usuwania białych znaków dla kolejnych sześciu bajtów

Edycja: Ponieważ ta odpowiedź nie zanieczyszcza globalnej przestrzeni nazw, otrzymuję 5% premii, zgodnie z wizzwizz4 tutaj .

Edycja: Zmieniono sposób gzwiększania i zmniejszania. Teraz za pomocą eval()i str.translate.

Edycja: Ta odpowiedź jest teraz programem zamiast funkcji.

Edycja: Naprawiono kilka błędów z poprzedniego golfa.

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

Nie golfowany:

# 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
Sherlock9
źródło
Ciekawy około 5% premii. Czy zmienne są automatycznie lokalne w Pythonie?
edc65
@ edc65 Poprosiłem pisarza o podobne pytanie tutaj: chat.stackexchange.com/transcript/240?m=28529277#28529277 . Mam nadzieję, że to trochę pomoże. Jeśli nie, możemy kontynuować dyskusję na czacie.
Sherlock9,
2

Rubinowy, 358 356 344 322 319 * 80% * 95% = 242,44 bajtów

To jest mój kod Pythona przeniesiony do Ruby. Powinienem pisać więcej odpowiedzi w Ruby. To dobry język do gry w golfa.

Edycja: Zapomniałem, że funkcje nie muszą być nazwane w tym pytaniu.

Edycja: Ponieważ ta odpowiedź nie zanieczyszcza globalnej przestrzeni nazw, otrzymuję 5% premii, zgodnie z wizzwizz4 tutaj .

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

Nie golfowany:

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
Sherlock9
źródło
Czy ten kod jest podwójnie licencjonowany na podstawie licencji na kod? Chciałbym stworzyć dzieło pochodne, które zostało wydane na licencji GPL (chociaż dowolna licencja zgodna z GPL będzie z tym współpracować). Jest obecnie wydany na licencji CC BY-SA 3.0.
wizzwizz4
@ wizzwizz4 Czat tutaj: chat.stackexchange.com/rooms/56405/…
Sherlock9
1

JavaScript (ES6), 227 - 20%: 181,6 bajtów

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

Próbuję zdobyć 5% bonusu

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 większy

Mniej golfa

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>

edc65
źródło
Czy warto dodać vars, aby uzyskać 5% bonus?
wizzwizz4
var s,x,y,u,v,t,p,q,n,hnie, to nie jest warte @ wizzwizz4
edc65
Możesz po prostu postawić varprzed pierwszym użyciem każdego ... To jeszcze gorzej.
wizzwizz4,
@ wizzwizz4 w sumie, może masz rację ... próbuję ... nie. Szkoda
edc65