String peta ke kurva Hilbert

27

Mari kita memetakan beberapa string ke ruang 2d, gaya fraktal. Tugas Anda adalah menghitung a kurva Hilbert dan meletakkan string di sepanjang itu.

Kurva Hilbert, iterasi 1 hingga 8

Tugas

Tugasnya adalah mengambil string input baris tunggal, dan meletakkannya di sepanjang kurva Hilbert yang cukup besar untuk menampungnya, tetapi tidak lebih besar. Cobalah untuk membuat jumlah byte serendah mungkin; ini adalah setelah semua!

Kondisi

  • Setiap celah harus diisi dengan spasi putih, tetapi bantalan tidak diperlukan di akhir baris.
  • Awal baris harus di sudut kiri atas, dan ujung di kiri bawah.
  • Anda dapat membuat program atau fungsi.
  • Mungkin ada beberapa test case baru yang muncul, jadi jangan hardcode apapun!

Bonus

Catatan: Bonus bertumpuk seperti ini: -50% & -20% on 100B= -20% on 50Batau -50% on 80B= 40B.

  • -50% Jika inputnya berupa string multi-baris, balikkan proses untuk membuat input asli. Kasing uji untuk bonus: cukup gunakan yang ada (termasuk kasing uji bonus!)
  • -20% Jika Anda menghapus semua spasi putih yang tidak perlu dari output (misalnya di akhir baris).
  • -5% Jika Anda tidak mencemari namespace global (Anda tahu apa yang saya maksud!)

Uji kasus

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

Dan untuk bonus pengupasan spasi:

No  hitespac  her 

Noher

hesc
itpa

Papan peringkat

Untuk memastikan bahwa jawaban Anda muncul, silakan mulai jawaban Anda dengan tajuk utama, menggunakan templat Penurunan harga berikut:

# Language Name, N bytes

di mana Nukuran kiriman Anda. Jika Anda meningkatkan skor Anda, Anda dapat menyimpan skor lama di headline, dengan mencoretnya. Contohnya:

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

Jika Anda ingin memasukkan beberapa angka dalam tajuk Anda (mis. Karena skor Anda adalah jumlah dari dua file atau Anda ingin membuat daftar hukuman penterjemah secara terpisah), pastikan bahwa skor sebenarnya adalah angka terakhir di tajuk:

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

Anda juga dapat membuat tautan nama bahasa yang kemudian akan muncul di cuplikan papan peringkat:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes
wizzwizz4
sumber
Jika ada yang bisa membuat beberapa testcases lagi, itu akan dihargai.
wizzwizz4
Jadi karakter harus diwakili oleh simpul kurva?
flawr
No..hitespac..her.di mana titik-titik adalah spasi akan menjadi ujian yang lebih baik untuk bonus. (Dan saat ini, test case tidak ada jejaknya .)
Martin Ender
Jika Anda mengambil pendekatan sistem-L, Anda mungkin juga ingin mencoba http: // codegolf / questions / 48697 / ascii-l-system-renderer . Ini bisa membantu Anda menjawab pertanyaan Anda.
wizzwizz4

Jawaban:

7

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

Terima kasih kepada Dennis untuk menghemat 1 byte.

Ini awal ...

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

Uji transformasi maju . Uji transformasi terbalik.

Saya yakin ada cara yang lebih pendek untuk menghasilkan kurva ...

Penjelasan

Pertama, saya mendefinisikan fungsi untuk memangkas beberapa elemen dari akhir array, karena saya membutuhkannya di beberapa tempat. Itu mengharapkan array dan elemen (di dalam array terpisah) di atas tumpukan.

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

Sekarang mayoritas kode menentukan ukuran kurva Hilbert yang diperlukan dan mengkonstruksinya sebagai array 2D di mana elemen-elemennya adalah indeks di sepanjang kurva. Saya membangun ini berdasarkan pengamatan berikut:

Pertimbangkan kurva 2x2 Hilbert:

01
32

Kurva 4x4 Hilbert adalah:

0345
1276
ed89
fcba

Jika kita mengurangi nilai minimum dari setiap kuadran (dan memisahkannya sedikit untuk kejelasan visual), kita mendapatkan:

03 01
12 32

21 01
30 32

Pola ini berlaku untuk berbagai ukuran. Ini berarti bahwa kita dapat membangun level berikutnya dari level saat ini, dengan menggunakan empat kuadran: a) transpos level saat ini, b) level saat itu sendiri, c) transpos di sepanjang anti-diagonal, d) lagi level saat ini sendiri. Dan kemudian kita mengimbangi mereka 0, 1, 3, 2 kali ukuran level saat ini, masing-masing.

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/

Akhirnya, kami menggunakan kurva indeks Hilbert ini untuk menerapkan transformasi yang sesuai untuk 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.
Martin Ender
sumber
3

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

Cara kerjanya adalah saya membuat kurva Hilbert menggunakan sistem Lindenmayer dan mengikuti instruksi kiri, kanan dan maju di sepanjang deretan string. Mungkin ada banyak cara ini bisa bermain golf lebih baik; terutama di conditional dan dalam membuat berbagai string. (Saya memang berusaha[" "*p for i in range(p)] tetapi string tidak mendukung penugasan item (rupanya). Jika saya bisa membuatnya berfungsi, saya bisa menyingkirkan bergabung juga)

Sunting: Mem Golf beberapa persyaratan dengan terima kasih Dennis . Dan saya bermain golf di deretan string. Dan perubahan no-byte karena hasilnya keluar ditransposisikan dibandingkan dengan contoh di atas.

Edit: Menerapkan bonus pengupasan spasi.

Edit: Memperbaiki bug dalam kode stripping spasi putih saya selama enam byte lagi

Sunting: Karena jawaban ini tidak mencemari namespace global, saya mendapatkan bonus 5%, menurut wizzwizz4 di sini .

Sunting: Mengubah cara gbertambah dan dikurangi. Sekarang menggunakan eval()danstr.translate .

Edit: Jawaban ini sekarang adalah program, bukan fungsi.

Sunting: Memperbaiki beberapa bug dari golf sebelumnya.

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

Tidak Disatukan:

# 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
sumber
Ingin tahu tentang bonus 5%. Apakah variabel secara otomatis lokal di Python?
edc65
@ edc65 Saya bertanya pada penulis tantangan hal serupa di sini: chat.stackexchange.com/transcript/240?m=28529277#28529277 . Semoga itu bisa membantu sedikit. Jika tidak, kita dapat melanjutkan diskusi dalam obrolan.
Sherlock9
2

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

Ini adalah kode Python saya dipindahkan ke Ruby. Saya harus menulis lebih banyak jawaban di Ruby. Ini adalah bahasa yang layak untuk bermain golf.

Sunting: Saya lupa bahwa fungsi tidak perlu disebutkan dalam pertanyaan ini.

Sunting: Karena jawaban ini tidak mencemari namespace global, saya mendapatkan bonus 5%, menurut wizzwizz4 di sini .

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

Tidak Disatukan:

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
sumber
Apakah kode ini memiliki lisensi ganda di bawah lisensi kode? Saya ingin menghasilkan karya turunan yang dirilis di bawah GPL (meskipun lisensi yang kompatibel dengan GPL akan bekerja dengan ini). Saat ini dirilis di bawah CC BY-SA 3.0.
wizzwizz4
@ wizzwizz4 Chat di sini: chat.stackexchange.com/rooms/56405/…
Sherlock9
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()}

Mencoba mendapat bonus 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 lebih besar

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

Uji

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
sumber
Apakah perlu menambahkan vars untuk mendapatkan bonus 5%?
wizzwizz4
var s,x,y,u,v,t,p,q,n,htidak itu tidak layak @ wizzwizz4
edc65
Anda bisa menempatkan varsebelum penggunaan pertama masing-masing ... Oh, itu lebih buruk.
wizzwizz4
@ wizzwizz4 semuanya, mungkin Anda ada benarnya ... saya sedang mencoba ... tidak. Sayang sekali
edc65