Evitar los ríos

48

Antecedentes

En la tipografía, los ríos son espacios visuales en un bloque de texto, que se producen debido a la alineación coincidente de los espacios. Estos son particularmente molestos ya que su cerebro parece captarlos más fácilmente en la visión periférica, lo que distrae constantemente sus ojos.

Como ejemplo, tome el siguiente bloque de texto, líneas discontinuas de modo que el ancho de la línea no exceda los 82 caracteres :

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.

Hay un río que abarca seis líneas en la parte inferior derecha, que he resaltado en el siguiente bloque:

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.

Podemos mitigar esto eligiendo un ancho de columna ligeramente diferente. Por ejemplo, si diseñamos el mismo texto usando líneas que no tengan más de 78 caracteres , no habrá un río con más de dos líneas:

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.

Tenga en cuenta que para el propósito de esta pregunta solo estamos considerando fuentes monoespaciadas, de modo que los ríos son simplemente columnas verticales de espacios. La longitud de un río es la cantidad de líneas que abarca.

Aparte: si le interesa la detección de ríos en fuentes proporcionales, hay algunas publicaciones interesantes en la red.

El reto

Se le proporciona una cadena de caracteres ASCII imprimibles (punto de código 0x20 a 0x7E), es decir, una sola línea. Imprima este texto, con un ancho de línea entre 70 y 90 caracteres (inclusive), de modo que se minimice la longitud máxima de cualquier río en el texto. Si hay varios anchos de texto con la misma longitud de río máxima (mínima), elija el ancho más estrecho. El ejemplo anterior con 78 caracteres es la salida correcta para ese texto.

Para dividir líneas, debe reemplazar los caracteres de espacio (0x20) con saltos de línea, de modo que las líneas resultantes tengan tantos caracteres como sea posible, pero no más que el ancho de texto elegido. Tenga en cuenta que el salto de línea resultante en sí mismo no es parte de ese recuento. Como ejemplo, en el último bloque anterior, Lorem[...]temporcontiene 78 caracteres, que también es el ancho del texto.

Puede suponer que la entrada no contendrá espacios consecutivos y no tendrá espacios iniciales o finales. También puede suponer que ninguna palabra (subcadena consecutiva de no espacios) contendrá más de 70 caracteres.

Puede escribir un programa o función, tomando datos a través de STDIN, argumento de línea de comando o argumento de función e imprimiendo el resultado en STDOUT.

Este es el código de golf, por lo que gana la respuesta más corta (en bytes).

Martin Ender
fuente
Creo que en sus ejemplos de ajuste de columna 78 y 82, la última y la penúltima línea son incorrectas. En el ejemplo 82, el último descanso debería ser entre id y est , y en el ejemplo 78 debería ser entre in y culpa . ¿O estoy haciendo algo mal?
Cristian Lupascu
@Optimizer El desempate es la longitud del texto, no la longitud del río.
FryAmTheEggman
Supongo que no cuenta como un río oficial, pero en el ejemplo de 78 caracteres de longitud máxima, parece haber un río diagonal bastante largo en el área de arriba a la izquierda
markasoftware
¿Consideramos casos como este a medida que continúan los ríos?
Optimizador
¡Gran reto! Hm, el siguiente podría ser sobre tener ríos (no puramente verticales) que
formen

Respuestas:

7

CJam, 116106 99 84 77 72 bytes

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

Toma la entrada de una sola línea e imprime la salida correcta en STDOUT.

ACTUALIZACIÓN : mejoró mucho y eliminó los bucles redundantes al hacer todos los cálculos en el propio bucle de clasificación. También se corrigió un error en el cálculo de la longitud del río.

Explicación pronto (después de jugar golf aún más)

Pruébalo aquí

Optimizador
fuente
@Optimizer Sin embargo, puede usar la entrada de ARGV, luego puede hacerlo en ea~lugar de Xcada vez. Guarda dos bytes.
Martin Ender
12

Rubí 162 160 158 152 160 157 ( de demostración )

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

La versión sin 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
fuente
@ MartinBüttner %r{...}me permite usar la interpolación de cadenas. Acabo de intentarlo 21.times, pero tiene algunas implicaciones más en el futuro, y no he logrado llegar a una solución más corta.
Cristian Lupascu
@ MartinBüttner Tiene usted razón, se hace el trabajo! He editado mi respuesta. ¡Gracias!
Cristian Lupascu
Esto no funciona con pastebin.com/vN2iAzNd
Joshpbarron
@Joshpbarron Muy bien visto! Lo arreglé ahora.
Cristian Lupascu
8

APL (105)

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

Explicación:

  • (K⊂⍨' '=K←' ',⍵): Agregue un espacio delante y luego divida en los espacios. Cada palabra retiene el espacio con el que comienza.
  • ∘{... }¨70+⍳21: con ese valor, para cada número en el rango [71, 91]: (Debido a la forma en que se dividen las palabras, cada 'línea' termina con un espacio adicional al principio, que se eliminará más adelante. El rango se desplaza por uno para compensar el espacio extra.)
    • ×⍴⍺:: si todavía quedan palabras,
      • z←⍵>+\≢¨⍺: obtenga la longitud de cada palabra y calcule un total acumulado de la longitud, por palabra. Marque con 1todas las palabras que se pueden tomar para completar la siguiente línea y guárdelo z.
      • (⊂z/⍺),⍵∇⍨⍺⍨~z: toma esas palabras y luego procesa lo que queda de la lista.
    • ⋄⍺: si no, return (que ahora está vacío).
  • G←: almacena la lista de listas de líneas en G(una para cada longitud de línea posible).
  • V←{... }¨G: para cada posibilidad, calcule la longitud del río más largo y guárdelo en V:
    • +\↑≢¨¨⍵: obtenga la longitud de cada palabra (nuevamente), y haga una matriz con las longitudes. Calcule el total acumulado de cada línea en las filas de la matriz. (Por lo tanto, se ignora el espacio adicional al comienzo de cada línea).
    • 2≠⌿: para cada columna de la matriz, vea si la longitud actual de la línea en ese punto no coincide con la línea que sigue. Si es así, hay no un río allí.
    • ⊂⍨¨↓⍉: divide cada columna de la matriz por sí misma (en la 1s). Esto proporciona una lista de listas, donde para cada río habrá una lista [1, 0, 0, ...], dependiendo de la longitud del río. Si no hay río, la lista estará [1].
    • ⌈/≢¨: obtenga la longitud de cada río y obtenga el valor máximo de eso.
  • ⊃G/⍨V=⌊/V: desde G, seleccione el primer elemento para el que la longitud del río más largo es igual al mínimo para todos los elementos.
  • {1↓∊⍵,3⊃⎕TC}¨: para cada línea, unir todas las palabras, eliminar el elemento de puño (el espacio extra desde el principio) y agregar una nueva línea al final.
  • : une todas las líneas juntas.
marinus
fuente
Eso es 200 bytes, no 105.
user11153
3
@ user11153 No he especificado UTF-8 como codificación. El juego de caracteres APL se ajusta a una sola página de códigos (y esa página de códigos existe ), es decir, hay una codificación existente por la cual cada uno de esos caracteres se ajusta a un byte, y por lo tanto 105 está perfectamente bien.
Martin Ender
¡Bueno saber! :)
user11153
8

Bash + Coreutils 236 157 bytes

Editado con un enfoque diferente, bastante más corto que antes:

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

Lee la cadena de entrada desde la línea de comando.

Con 3 clases anidadas, me estremezco al pensar cuál es la complejidad del tiempo Big-O para esto, pero completa el ejemplo en menos de 10 segundos en mi máquina.

Trauma digital
fuente
3

Python, 314 bytes

Muchas gracias a SP3000, grc y 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
fuente
2
Más como Pi-thon
Optimizer
3

JavaScript (ES6) 194 202

Solución iterativa, quizás más corta si se hace recursiva

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

Explicado

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

Prueba en la consola 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.')

Salida

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
fuente
3

Python 3, 329 bytes

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ón sin golf:

# 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
fuente