Рядок на карті на криву Гільберта


27

Давайте відобразимо кілька рядків на 2d простір, фрактальний стиль. Ваше завдання - обчислити криву Гільберта і прокласти по ній рядок.

Крива Гільберта, ітерації 1 - 8

Завдання

Завдання полягає в тому, щоб взяти однорядний вхідний рядок і викласти його по кривій Гільберта, достатньо великій, щоб містити його, але не більше. Постарайтеся зробити кількість байтів якомога меншою; це є в кінці кінців!

Умови

  • Будь-які прогалини, залиті пробілом, але прокладка не потрібна в кінці рядків.
  • Початок рядка повинен бути у верхньому лівому куті, а кінець у нижньому лівому.
  • Ви можете створити програму або функцію.
  • Можливо, з’являться нові тестові випадки, тому нічого не жорстко кодуйте!

Бонуси

Примітка: Бонуси складаються таким чином: -50% & -20% on 100B= -20% on 50Bабо -50% on 80B= 40B.

  • -50% Якщо вхід є рядковим рядком, оберніть процес, щоб створити початковий вхід. Тестові приклади бонусу: просто використовуйте наявні (включаючи тестові випадки бонусу!)
  • -20% Якщо ви викресліть все зайве пробіли з виводу (наприклад, в кінці рядка).
  • -5% Якщо ви не забруднюєте глобальний простір імен (ви знаєте, що я маю на увазі!)

Тестові справи

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

А для бонусу за знімання пробілів:

No  hitespac  her 

Noher

hesc
itpa

Таблиця лідерів

Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

# Language Name, N bytes

де Nрозмір вашого подання. Якщо ви покращите свій рахунок, ви можете зберегти старі бали у заголовку, прокресливши їх. Наприклад:

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

Якщо ви хочете включити у свій заголовок декілька чисел (наприклад, тому що ваш результат становить суму двох файлів або ви хочете окремо вказати штрафні санкції для перекладача), переконайтесь, що фактичний результат - це останнє число у заголовку:

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

Ви також можете зробити ім'я мови посиланням, яке потім з’явиться у фрагменті таблиць лідерів:

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

Якщо хтось може зробити ще кілька тестів, це буде вдячно.
wizzwizz4

Отже символи повинні бути представлені вершинами кривої?
недолік

No..hitespac..her.де пробіли крапки будуть кращим тестовим випадком для бонусу. (На даний момент у тестовому випадку відсутній пробіг .)
Мартін Ендер

Якщо ви використовуєте підхід L-системи, ви також можете спробувати http: // codegolf / questions / 48697 / ascii-l-system-renderer . Це може допомогти вам пограти у ваші відповіді.
wizzwizz4

Відповіді:


7

CJam, 119 117 113 112 109 * 0,5 * 0,8 = 43,6 байт

Завдяки Деннісу за збереження 1 байта.

Ось початок ...

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

Перевірка прямого перетворення . Перевірте зворотне перетворення.

Я впевнений, що існує коротший спосіб генерувати криву ...

Пояснення

По-перше, я визначаю функцію для обрізки якогось елемента з кінця масиву, тому що мені це потрібно в декількох місцях. Він очікує масив і елемент (всередині окремого масиву) вгорі стека.

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

Тепер більшість коду визначає розмір необхідної кривої Гільберта і будує її як 2D масив, де елементи є індексами по кривій. Я будую це на основі такого спостереження:

Розглянемо криву 2х2 Гільберта:

01
32

Крива Гільберта 4x4:

0345
1276
ed89
fcba

Якщо відняти мінімальне значення з кожного квадранта (і розділити їх трохи для наочності), отримаємо:

03 01
12 32

21 01
30 32

Ця модель справедлива для будь-якого розміру. Це означає, що ми можемо побудувати наступний рівень із поточного, використовуючи як чотири квадранти: а) перенесення поточного рівня, б) сам поточний рівень, в) перенесення уздовж антидіагоналі, г) знову сам поточний рівень. І тоді ми їх компенсуємо в 0, 1, 3, 2 рази більше від поточного рівня відповідно.

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/

Нарешті, ми використовуємо цю криву Гільбертових індексів, щоб застосувати відповідне перетворення до введення:

\_        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 байт

Як це працює, це те, що я роблю криву Гільберта, використовуючи систему Лінденмайєра, і слідую вліво, вправо та вперед вказівки вздовж масиву рядків. Напевно, існує багато способів, як це можна було б краще пограти в гольф; особливо в умовних умовах та при створенні масиву рядків. (Я робив спробу, [" "*p for i in range(p)]але рядки не підтримують призначення елемента (мабуть). Якби я міг змусити це працювати, я також міг би позбутися приєднання)

Редагувати: Дещо з кондиціонерів розіграв завдяки Деннісу . І я гольфував по низці струн. І безбайтне зміна, оскільки результати виходили транспонованими порівняно з прикладами вище.

Редагувати: реалізований бонус за позбавлення від пробілів.

Редагувати: виправлена ​​помилка в моєму коді, що знімає пробіли, ще на шість байтів

Редагувати: Оскільки ця відповідь не забруднює глобальний простір імен, я отримую 5% бонус, згідно з wizzwizz4 тут .

Редагувати: Змінено спосіб gзбільшення та зменшення. Зараз використовуємо eval()іstr.translate .

Редагувати: Ця відповідь тепер є програмою замість функції.

Редагувати: виправлено деякі помилки з попереднього гольфу.

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

Безголівки:

# 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

Цікаво про 5% бонус. Чи змінні автоматично локальні в Python?
edc65

@ edc65 Я запитав письменника-виклика подібну річ тут: chat.stackexchange.com/transcript/240?m=28529277#28529277 . Сподіваюся, що це мало допомагає. Якщо ні, ми можемо продовжити обговорення в чаті.
Шерлок9,

2

Рубі, 358 356 344 322 319 * 80% * 95% = 242,44 байт

Це мій код Python, перекладений на Ruby. Я повинен написати більше відповідей у ​​Рубі. Це гідна мова для гри в гольф.

Редагувати: я забув, що функції в цьому питанні не потрібно називати.

Редагувати: Оскільки ця відповідь не забруднює глобальний простір імен, я отримую 5% бонус, згідно з wizzwizz4 тут .

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

Безголівки:

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

Чи є цей код подвійним ліцензією за кодовою ліцензією? Я хотів би створити похідну роботу, яка випускається під GPL (хоча будь-яка ліцензія, сумісна з GPL, буде працювати з цим). Наразі випущено під CC BY-SA 3.0.
wizzwizz4


1

JavaScript (ES6), 227 - 20%: 181,6 байт

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

Намагаються отримати 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 більший

Менше гольфу

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
}  

Тест

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>


Чи варто додати vars, щоб отримати 5% бонус?
wizzwizz4

var s,x,y,u,v,t,p,q,n,hні, це не варто @ wizzwizz4
edc65

Ви можете просто поставити varперед першим використанням кожного ... О, це ще гірше.
wizzwizz4

@ wizzwizz4 загалом, можливо, у вас є точка ... я намагаюся ... ні. Шкода
edc65
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.