Menghindari Sungai

48

Latar Belakang

Dalam tipografi, sungai adalah kesenjangan visual dalam blok teks, yang terjadi karena penyelarasan spasi secara kebetulan. Ini sangat menjengkelkan karena otak Anda tampaknya mengambilnya dengan lebih mudah dalam penglihatan tepi, yang terus-menerus mengganggu mata Anda.

Sebagai contoh, ambil blok teks berikut ini, garis-garis patah sehingga lebar garis tidak melebihi 82 karakter :

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.

Ada sungai yang membentang enam garis di bagian kanan bawah, yang saya soroti di blok berikut:

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.

Kami dapat mengurangi ini dengan memilih lebar kolom yang sedikit berbeda. Misalnya, jika kita tata letak teks yang sama menggunakan baris tidak lebih dari 78 karakter , tidak ada sungai lebih dari dua baris:

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.

Perhatikan bahwa untuk keperluan pertanyaan ini, kami hanya mempertimbangkan font monospasi, sehingga sungai hanyalah kolom spasi vertikal. Panjang sungai adalah jumlah garis yang terbentang.

Selain itu: Jika Anda tertarik dalam deteksi sungai dalam font proporsional, ada beberapa posting menarik di sekitar jaringan.

Tantangan

Anda diberi serangkaian karakter ASCII yang dapat dicetak (titik kode 0x20 hingga 0x7E) - yaitu satu baris. Cetak teks ini, dengan lebar garis antara 70 dan 90 karakter (termasuk), sehingga panjang maksimum dari sungai mana pun dalam teks dapat diminimalkan. Jika ada beberapa lebar teks dengan panjang sungai maksimum yang sama (minimal), pilih lebar yang lebih sempit. Contoh di atas dengan 78 karakter adalah output yang benar untuk teks itu.

Untuk memecah garis, Anda harus mengganti karakter spasi (0x20) dengan jeda baris, sehingga garis yang dihasilkan memiliki karakter sebanyak mungkin, tetapi tidak lebih dari lebar teks yang dipilih. Perhatikan bahwa jeda baris yang dihasilkan itu sendiri bukan bagian dari penghitungan itu. Sebagai contoh, di blok terakhir di atas, Lorem[...]temporberisi 78 karakter, yang juga lebar teks.

Anda dapat berasumsi bahwa input tidak akan berisi spasi berurutan, dan tidak akan memiliki spasi di depan atau di belakang. Anda juga dapat mengasumsikan bahwa tidak ada kata (substring non-spasi berturut-turut) akan berisi lebih dari 70 karakter.

Anda dapat menulis program atau fungsi, mengambil input melalui STDIN, argumen baris perintah atau argumen fungsi dan mencetak hasilnya ke STDOUT.

Ini kode golf, jadi jawaban tersingkat (dalam byte) menang.

Martin Ender
sumber
Saya pikir dalam contoh bungkus kolom 78 dan 82 Anda, baris terakhir dan kedua ke terakhir salah. Dalam contoh 82, istirahat terakhir harus antara id dan est , dan dalam contoh 78 itu harus antara in dan culpa . Atau saya melakukan sesuatu yang salah?
Cristian Lupascu
@Optimizer Tie break adalah panjang teks, bukan panjang sungai.
FryAmTheEggman
Saya kira itu tidak dihitung sebagai sungai resmi, tetapi dalam contoh 78 karakter panjang maks, tampaknya ada sungai diagonal yang cukup panjang di daerah kiri-atas-ish teratas
markasoftware
Apakah kita menganggap kasus seperti ini sebagai sungai yang berkelanjutan?
Pengoptimal
Tantangan besar! Hm, yang berikutnya adalah tentang memiliki (bukan semata-mata vertikal) sungai yang membentuk huruf-huruf bawah sadar;)
Tobias Kienzler

Jawaban:

7

CJam, 116 106 99 84 77 72 byte

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

Mengambil input baris tunggal dan mencetak output yang benar ke STDOUT.

PEMBARUAN : Banyak ditingkatkan dan dihapus loop berlebihan dengan melakukan semua perhitungan dalam loop penyortiran itu sendiri. Juga memperbaiki bug dalam perhitungan panjang sungai.

Penjelasan segera (setelah saya golf lebih jauh)

Coba di sini

Pengoptimal
sumber
@Optimizer Anda bisa menggunakan input dari ARGV meskipun, maka Anda dapat melakukan ea~bukannya Xsetiap kali. Menghemat dua byte.
Martin Ender
12

Ruby 162 160 158 152 160 160 157 ( demo )

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

Versi tidak golf:

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
Cristian Lupascu
sumber
@ MartinBüttner %r{...}memungkinkan saya menggunakan interpolasi string. Saya baru saja mencoba 21.times, tetapi memiliki beberapa implikasi di jalan, dan saya belum berhasil mencapai solusi yang lebih pendek.
Cristian Lupascu
@ MartinBüttner Anda benar, itu tidak bekerja! Saya sudah mengedit jawaban saya. Terima kasih!
Cristian Lupascu
Ini tidak berfungsi dengan pastebin.com/vN2iAzNd
Joshpbarron
@ Joshpbarron Sangat terlihat! Saya memperbaikinya sekarang.
Cristian Lupascu
8

APL (105)

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

Penjelasan:

  • (K⊂⍨' '=K←' ',⍵): Tambahkan spasi di depan , lalu pisah pada spasi. Setiap kata mempertahankan ruang yang dimulai.
  • ∘{... }¨70+⍳21: dengan nilai itu, untuk setiap angka dalam rentang [71, 91]: (Karena cara kata-kata terpecah, masing-masing 'garis' berakhir dengan ruang ekstra di awal, yang akan dihapus kemudian. Rentang digeser oleh satu untuk mengimbangi ruang ekstra.)
    • ×⍴⍺:: jika masih ada kata yang tersisa,
      • z←⍵>+\≢¨⍺: dapatkan panjang untuk setiap kata, dan hitung total panjangnya, per kata. Tandai dengan 1semua kata yang dapat diambil untuk mengisi baris berikutnya, dan simpan di z.
      • (⊂z/⍺),⍵∇⍨⍺⍨~z: ambil kata-kata itu, lalu proseskan apa yang tersisa dari daftar.
    • ⋄⍺: jika tidak, kembali (yang sekarang kosong).
  • G←: menyimpan daftar daftar garis dalam G(satu untuk setiap panjang garis yang mungkin).
  • V←{... }¨G: untuk setiap kemungkinan, hitung panjang sungai terpanjang dan simpan di V:
    • +\↑≢¨¨⍵: dapatkan panjang setiap kata (lagi), dan buat matriks dari panjangnya. Hitung total yang berjalan untuk setiap baris pada baris matriks. (Dengan demikian, ruang ekstra di awal setiap baris diabaikan.)
    • 2≠⌿: untuk setiap kolom matriks, lihat apakah panjang garis saat ini pada titik itu tidak cocok dengan garis setelahnya. Jika demikian, tidak ada sungai di sana.
    • ⊂⍨¨↓⍉: pisahkan setiap kolom dari matriks dengan sendirinya (pada 1s). Ini memberikan daftar daftar, di mana untuk setiap sungai akan ada daftar [1, 0, 0, ...], tergantung pada panjang sungai. Jika tidak ada sungai, daftarnya akan ada [1].
    • ⌈/≢¨: dapatkan panjang setiap sungai, dan dapatkan nilai maksimumnya.
  • ⊃G/⍨V=⌊/V: from G, pilih item pertama dengan panjang sungai terpanjang sama dengan minimum untuk semua item.
  • {1↓∊⍵,3⊃⎕TC}¨: untuk setiap baris, gabungkan semua kata bersama, hapus item pertama (ruang ekstra dari awal), dan tambahkan baris baru ke akhir.
  • : gabungkan semua baris bersama.
marinus
sumber
Itu 200 byte, bukan 105.
user11153
3
@ user11153 Saya belum menentukan UTF-8 sebagai encoding. Rangkaian karakter APL cocok menjadi satu codepage tunggal (dan codepage itu ada ), yaitu ada pengkodean yang ada di mana masing-masing karakter tersebut cocok menjadi byte, dan karenanya 105 sangat baik-baik saja.
Martin Ender
Senang mendengarnya! :)
user11153
8

Bash + coreutils, 236 157 byte

Diedit dengan pendekatan yang berbeda - sedikit lebih pendek dari sebelumnya:

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<<<$@

Membaca string input dari baris perintah.

Dengan 3 jenis bersarang, saya ngeri memikirkan apa kompleksitas waktu-O besar untuk ini, tetapi tidak menyelesaikan contoh di bawah 10 detik pada mesin saya.

Trauma Digital
sumber
3

Python, 314 byte

Terima kasih banyak untuk SP3000, grc, dan 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')
Hosch250
sumber
2
Lainnya seperti Pi-thon
Pengoptimal
3

JavaScript (ES6) 194 202

Solusi berulang, mungkin lebih pendek jika dibuat rekursif

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

Dijelaskan

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

Uji di konsol 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.')

Keluaran

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.
edc65
sumber
3

Python 3, 329 byte

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

Versi tidak disatukan:

# 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)]))
erebos
sumber