Уникнення річок


48

Фон

У типографії річки - це візуальні прогалини в текстовому блоці, які виникають через збіг узгоджених просторів. Це особливо дратує, оскільки ваш мозок, здається, перебирає їх легше в периферійному зорі, який постійно відволікає ваш погляд.

Як приклад, візьміть наступний блок тексту, рядки розбиті таким чином, щоб ширина рядка не перевищувала 82 символи :

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet,
consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore
maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.

У правій нижній частині є річка, що охоплює шість рядків, яку я виділив у наступному блоці:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum. Lorem█ipsum dolor sit amet,
consectetur adipisicing elit, sed do eismod tempor█incididunt ut labore et dolore
maga aliqua. Ut enim ad minim veniam, quis nostrud█exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute█irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla█pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui█officia deserunt mollit anim id
est laborum.

Ми можемо пом’якшити це, вибравши дещо іншу ширину стовпця. Наприклад, якщо ми розміщуємо один і той же текст, використовуючи рядки довжиною не більше 78 символів , немає річки довше двох рядків:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor
sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut
labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

Зауважте, що для цього питання ми розглядаємо лише шрифти з односхилим розміром, так що річки є просто вертикальними стовпцями пробілів. Довжина річки - це кількість ліній, які вона проходить.

Убік: Якщо вам цікаво виявлення річки пропорційними шрифтами, у мережі є кілька цікавих публікацій .

Змагання

Вам надається рядок символів для друку ASCII (кодова точка від 0x20 до 0x7E) - тобто один рядок. Роздрукуйте цей текст із шириною рядка від 70 до 90 символів (включно), щоб максимальна довжина будь-якої річки в тексті була мінімізована. Якщо є кілька ширин тексту з однаковою (мінімальною) максимальною довжиною річки, виберіть більш вузьку ширину. Наведений вище приклад із 78 символами - це правильний вихід для цього тексту.

Для розриву рядків слід замінити пробіли символів (0x20) на розриви рядків, щоб отримані рядки мали якомога більше символів, але не більше вибраної ширини тексту. Зауважте, що отриманий розрив рядка сам по собі не є частиною цього підрахунку. Наприклад, в останньому блоці вище Lorem[...]tempor78 символів, що також є шириною тексту.

Ви можете припустити, що вхід не буде містити послідовних пробілів і не матиме провідних чи кінцевих пробілів. Ви також можете припустити, що жодне слово (послідовна підрядка не пропусків) не містить більше 70 символів.

Ви можете написати програму або функцію, взявши введення через STDIN, аргумент командного рядка або аргумент функції та роздрукувавши результат на STDOUT.

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.


Я думаю, що у ваших прикладах обгортання стовпців 78 і 82 останній та другий-останній рядки невірні. У прикладі 82 останній розрив повинен бути між id і est , а в 78 прикладі - між in і culpa . Або я роблю щось не так?
Крістіан Лупаску

@Optimizer Розрив зв'язку - це довжина тексту, а не довжина річки.
FryAmTheEggman

Я думаю, що це не вважається офіційною річкою, але в прикладі максимальної довжини 78 символів, здається, є досить довга діагональна річка у верхньому лівому лівому районі
markasoftware

Як ми розглянемо випадки , як це , як триває річки?
Оптимізатор

Великий виклик! Гм, наступний міг би говорити про те, щоб (не суто вертикальні) річки формували підсвітні букви;)
Тобіас Кіенцлер

Відповіді:


7

CJam, 116 106 99 84 77 72 байт

l:X;93,72>{:D;OOXS/{S+_2$+,D<{+}{@@);a+\}?}/a+}%{z'K*S/:!0a/1fb$W=}$0=N*

Бере вхід в один рядок і друкує правильний вихід на STDOUT.

ОНОВЛЕННЯ : Багато покращили та видалили зайві петлі, виконавши всі обчислення в самому циклі сортування. Виправлено помилку в розрахунку довжини річки.

Пояснення незабаром (після того, як я пограю ще більше)

Спробуйте тут


@Optimizer Ви можете використовувати вхід з ARGV, але ви можете робити це ea~замість Xкожного разу. Зберігає два байти.
Мартін Ендер

12

Ruby 162 160 158 158 152 160 157 ( демонстрація )

i=gets+' '
(69..s=r=89).map{|c|w=i.scan(/(.{1,#{c}}\S) /).flatten
m=(0..c).map{|i|w.map{|l|l[i]}+[?x]}.join.scan(/ +/).map(&:size).max
m<s&&(s=m;r=w)}
puts r

Версія без гольфу:

input = gets+' '

result = ''

(69..smallest_max=89).each{|w|
  #split text into words of at most w characters
  wrap = (input+' ').scan(/(.{1,#{w}}\S) /).flatten

  #transpose lines and find biggest "river"
  max_crt_river = (0..99).map{|i| wrap.map{|l|l[i]} }.flatten.join.scan(/ +/).max_by(&:size).size

  if max_crt_river < smallest_max
    smallest_max = max_crt_river
    result = wrap.join ?\n
  end
}
puts result

@ MartinBüttner %r{...}дозволяє мені використовувати стропову інтерполяцію. Я просто спробував 21.times, але це має ще декілька наслідків у дорозі, і я не зумів досягти коротшого рішення.
Крістіан Лупаску

@ MartinBüttner Ви маєте рацію, це робить роботу! Я відредагував свою відповідь. Дякую!
Крістіан Лупаску

Це не працює з pastebin.com/vN2iAzNd
Joshpbarron

@Joshpbarron Дуже добре помічений! Я зараз це виправив.
Крістіан Лупаску

8

APL (105)

{∊{1↓∊⍵,3⊃⎕TC}¨⊃G/⍨V=⌊/V←{⌈/≢¨⊂⍨¨↓⍉2≠⌿+\↑≢¨¨⍵}¨G←(K⊂⍨' '=K←' ',⍵)∘{×⍴⍺:(⊂z/⍺),⍵∇⍨⍺/⍨~z←⍵>+\≢¨⍺⋄⍺}¨70+⍳21}

Пояснення:

  • (K⊂⍨' '=K←' ',⍵): Додайте пробіл перед , а потім розділіть пробіли. Кожне слово зберігає простір, з якого починається.
  • ∘{... }¨70+⍳21: з цим значенням для кожного числа в діапазоні [71, 91]: (Через те, як слова розділені, кожен 'рядок' закінчується додатковим пробілом на початку, який буде видалено пізніше. Діапазон зміщується на один, щоб компенсувати додатковий простір.)
    • ×⍴⍺:: якщо залишилися слова,
      • z←⍵>+\≢¨⍺: отримайте довжину для кожного слова та обчисліть загальну кількість довжини за кожне слово. Позначте 1всі слова, які можна взяти для заповнення наступного рядка, і збережіть його z.
      • (⊂z/⍺),⍵∇⍨⍺⍨~z: візьміть ці слова, а потім обробіть те, що залишилося від списку.
    • ⋄⍺: якщо ні, поверніться (який тепер порожній).
  • G←: зберігає список списків рядків у G(по одному для кожної можливої ​​довжини рядка).
  • V←{... }¨G: для кожної можливості обчисліть довжину найдовшої річки і зберігайте її в V:
    • +\↑≢¨¨⍵: отримайте довжину кожного слова (знову) і складіть матрицю з довжин. Обчисліть загальну кількість ходу для кожного рядка в рядках матриці. (Таким чином, додатковий пробіл на початку кожного рядка ігнорується.)
    • 2≠⌿: для кожного стовпця матриці подивіться, чи поточна довжина рядка в цій точці не відповідає лінії після неї. Якщо так, то є НЕ річка там.
    • ⊂⍨¨↓⍉: розділіть кожен стовпчик матриці самостійно (на 1s). Це дає список списків, де для кожної річки буде список [1, 0, 0, ...], залежно від довжини річки. Якщо річки немає, список буде [1].
    • ⌈/≢¨: отримайте довжину кожної річки та отримайте максимальне значення.
  • ⊃G/⍨V=⌊/V: з G, виберіть перший пункт, для якого довжина найдовшої річки дорівнює мінімуму для всіх предметів.
  • {1↓∊⍵,3⊃⎕TC}¨: для кожного рядка з'єднайте всі слова разом, вийміть елемент кулака (додатковий пробіл з початку) та додайте новий рядок до кінця.
  • : об'єднайте всі рядки разом.

Це 200 байт, а не 105.
user11153

3
@ user11153 Я не вказав UTF-8 як кодування. Набір символів APL вписується в одну кодову сторінку (і ця кодова сторінка існує ), тобто існує існуюче кодування, за допомогою якого кожен з цих символів вписується в байт, а значить, 105 ідеально добре.
Мартін Ендер

Добре знати! :)
користувач11153

8

Bash + coreutils, 236 157 байт

Відредаговано з іншим підходом - зовсім трохи коротше, ніж раніше:

a=(`for i in {71..91};{
for((b=1;b++<i;));{
fold -s$i<<<$@|cut -b$b|uniq -c|sort -nr|grep -m1 "[0-9]  "
}|sort -nr|sed q
}|nl -v71|sort -nk2`)
fold -s$a<<<$@

Читає рядок введення з командного рядка.

Маючи 3 вкладені сорти, я здригнувся думати, яка для цього велика складність часу, але це завершує приклад за 10 секунд на моїй машині.


3

Пітон, 314 байт

Велике спасибі SP3000, grc та FryAmTheEggman:

b=range;x=len
def p(i):
 l=[];z=''
 for n in t:
  if x(z)+x(n)<=i:z+=n+' '
  else:l+=[z];z=n+' '
 return l+[z]*(z!=l[x(l)-1])
t=input().split();q=[]
for i in b(70,91):l=p(i);q+=[max(sum(x(l[k+1])>j<x(l[k])and l[k][j]is' '==l[k+1][j]for k in b(x(l)-1))for j in b(i))]
print(*p(q.index(min(q))+70),sep='\n')

2
Більше схожий на Пі-Тхон
Оптимізатор

3

JavaScript (ES6) 194 202

Ітеративне рішення, можливо, коротше, якщо воно робиться рекурсивним

F=s=>{
  for(m=1e6,b=' ',n=70;n<91;n++)
    l=b+'x'.repeat(n),x=r=q='',
    (s+l).split(b).map(w=>
      (t=l,l+=b+w)[n]&&(
        l=w,r=r?[...t].map((c,p)=>x<(v=c>b?0:-~r[p])?x=v:v,q+=t+'\n'):[]
      )
    ),x<m&&(o=q,m=x);
  alert(o)
}

Пояснив

F=s=> {
  m = 1e9; // global max river length, start at high value
  for(n=70; n < 91; n++) // loop on line length
  {
    l=' '+'x'.repeat(n), // a too long first word, to force a split and start
    x=0, // current max river length
    q='', // current line splitted text
    r=0, // current river length for each column (start 0 to mark first loop)
    (s+l) // add a too long word to force a last split. Last and first row will not be managed
    .split(' ').map(w=> // repeat for each word 
      (
        t=l, // current partial row in t (first one will be dropped)
        (l += ' '+w)[n] // add word to partial row and check if too long
        &&
        (
          l = w, // start a new partial row with current word
          r=r? // update array r if not at first loop
          ( 
            q+=t+'\n', // current row + newline added to complete text 
            [...t].map((c,p)=>( // for each char c at position p in row t
              v = c != ' ' 
                ? 0 // if c is not space, reset river length at 0
                : -~r[p], // if c is space, increment river length
              x<v ? x=v : v // if current > max, update max
            ))
          ):[]  
        )  
      )
    )
    x < m && ( // if current max less than global max, save current text and current max
      o = q,
      m = x
    )
  }
  console.log(o,m)
}

Тест в консолі FireFox / FireBug.

F('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.')

Вихід

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor
sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut
labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

3

Python 3, 329 байт

import re,itertools as s
def b(t,n):
 l=0;o=""
 for i in t.split():
  if l+len(i)>n:o=o[:-1]+'\n';l=0
  l+=len(i)+1;o+=i+' '
 return o
t=input();o={}
for n in range(90,69,-1):o[max([len(max(re.findall('\s+',x),default='')) for x in ["".join(i) for i in s.zip_longest(*b(t,n).split('\n'),fillvalue='')]])]=n
print(b(t,o[min(o)]))

Безгольова версія:

# Iterates over words until length > n, then replaces ' ' with '\n'
def b(t,n):
    l = 0
    o = ""
    for i in t.split():
        if l + len(i) > n:
            o = o[:-1] + '\n'
            l = 0
        l += len(i) + 1
        o += i + ' '
    return o

t = input()
o = {}
# range from 90 to 70, to add to dict in right order
for n in range(90,69,-1):
    # break text at length n and split text into lines
    temp = b(t,n).split('\n')
    # convert columns into rows
    temp = itertools.zip_longest(*temp, fillvalue='')
    # convert the char tuples to strings
    temp = ["".join(i) for i in temp]
    # findall runs of spaces, get longest run and get length
    temp = [len(max(re.findall('\s+',x),default='')) for x in temp]
    # add max river length as dict key, with line length as value
    o[max(temp)] = n

print(b(t,o[min(o)]))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.