Planificador de calendario ASCII

11

Dada una lista de actividades y su fecha / hora de inicio, elabore un calendario de arte ASCII que muestre las actividades en los días apropiados. Se garantiza que todas las actividades se realizarán en el mismo mes, no habrá dos actividades el mismo día, y se garantiza que todas las actividades encajan en el cuadro del calendario.

El calendario tiene la fecha en la esquina superior izquierda de cada cuadro, los cuadros tienen 9 espacios de ancho por 5 espacios de alto, rodeados por -y |. La abreviatura de dos letras para el día de la semana está centrada sobre la primera fila, y las semanas comienzan con el domingo.

Por ejemplo, dadas las siguientes actividades:

10/5/2018 - 9:00am - Sandbox calendar challenge
10/9/2018 - 9:00am - Post challenge to main
10/10/2018 - 10:00am - Profit
10/31/2018 - 7:30pm - Halloween party

Salida de este calendario correspondiente:

    Su        Mo        Tu        We        Th        Fr        Sa     
-----------------------------------------------------------------------
|         |1        |2        |3        |4        |5        |6        |
|         |         |         |         |         |9:00am   |         |
|         |         |         |         |         |Sandbox  |         |
|         |         |         |         |         |calendar |         |
|         |         |         |         |         |challenge|         |
-----------------------------------------------------------------------
|7        |8        |9        |10       |11       |12       |13       |
|         |         |9:00am   |10:00am  |         |         |         |
|         |         |Post     |Profit   |         |         |         |
|         |         |challenge|         |         |         |         |
|         |         |to main  |         |         |         |         |
-----------------------------------------------------------------------
|14       |15       |16       |17       |18       |19       |20       |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
-----------------------------------------------------------------------
|21       |22       |23       |24       |25       |26       |27       |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
|         |         |         |         |         |         |         |
-----------------------------------------------------------------------
|28       |29       |30       |31       |         |         |         |
|         |         |         |7:30pm   |         |         |         |
|         |         |         |Halloween|         |         |         |
|         |         |         |party    |         |         |         |
|         |         |         |         |         |         |         |
-----------------------------------------------------------------------

Aclaraciones

  • Las palabras de programación (que coinciden con [A-Za-z] +) se delimitarán con un solo espacio entre ellas (como en el ejemplo).
  • Dividir el texto en límites de palabras es suficiente. No hay necesidad de separar palabras.
  • Si febrero comienza un domingo en un año no bisiesto, solo tendrá cuatro filas de calendario.
  • Si un mes de 31 días (por ejemplo, agosto) comienza tarde en la semana, es posible que deba generar seis filas de calendario.

E / S y reglas

  • Su código debe manejar fechas al menos entre 0001-01-01y 9999-12-31en el calendario gregoriano, incluidos los años bisiestos, según corresponda. Por ejemplo, si se le da entrada 2016-02-13 9:00am Test, el calendario de salida debería tener el 29 de febrero.
  • El formato de fecha de entrada puede estar en cualquier formato deseado. ISO 8601, un datetimeobjeto, una cadena con un formato particular, etc. El análisis de entrada no es la parte interesante de este desafío.
  • La entrada y salida pueden ser por cualquier método conveniente .
  • Las nuevas líneas iniciales / finales u otros espacios en blanco son opcionales, siempre que los caracteres se alineen adecuadamente.
  • Un programa completo o una función son aceptables. Si es una función, puede devolver el resultado en lugar de imprimirlo.
  • La salida puede ser a la consola, devuelta como una lista de cadenas, devuelta como una sola cadena, etc.
  • Las lagunas estándar están prohibidas.
  • Este es el por lo que se aplican todas las reglas habituales de golf, y gana el código más corto (en bytes).
AdmBorkBork
fuente
1.) ¿Tiene que dividir los nombres de las actividades en los límites de las palabras? 2.) Cuando tienes un febrero no lectivo que comienza un domingo, ¿tienes solo 4 filas? 3.) ¿Cuándo necesitarías 6 filas para mostrar el mes (por ejemplo, agosto a partir del sábado) qué sucede?
nedla2004
Relacionado (más fácil).
Arnauld
@ nedla2004 1) Sí, los límites de palabras funcionarán bien. 2) Eso es correcto, 4 filas. 3) Su calendario deberá mostrar 6 filas. Lo editaré en aclaraciones.
AdmBorkBork
@Arnauld Sí, es una suposición justa
AdmBorkBork
1
1752-09-02 - 09:00am - Wife's Birthday Tomorrow (14th!)
ngm

Respuestas:

10

JavaScript (ES8), 380 ... 321 320 bytes

Toma entrada como (y,m,e)donde:

  • y es el año
  • m es el mes, 0 indexado
  • ees un objeto cuyas claves son los días y cuyos valores son los eventos en [hour, task]formato
(y,m,e)=>`SuMoTuWeThFrSa
`.split(/(..)/).join`    `+(p='-'.repeat(d=71)+`
`)+(g=i=>++d<1|(x=G`getMonth`==m)|i%7?`|${[h,t]=e[d]||E,o=[x*d,h],q=E,t&&t.split` `.map(s=>q=(u=q?q+' '+s:s)[9]?o.push(q)&&s:u),[...o,q][r%5]||E}`.padEnd(10)+(++i%7?E:`|
`+(++r%5?(d-=7,E):p))+g(i):E)(E=r='',d=-(G=s=>new Date(y,m,d)[s]())`getDay`)

Pruébalo en línea!

¿Cómo?

A continuación hay algunas partes importantes en el código.

Encabezamiento

La línea de encabezado se genera con:

'SuMoTuWeThFrSa\n'.split(/(..)/).join`    `

Cuando split()se usa con una expresión regular que contiene un grupo de captura, este grupo se incluye en la matriz de salida. En este caso, da:

[ '', 'Su', '', 'Mo', '', 'Tu', '', 'We', '', 'Th', '', 'Fr', '', 'Sa', '\n' ]

Unimos esta matriz con 4 espacios, lo que lleva a:

'    Su        Mo        Tu        We        Th        Fr        Sa    \n'

que es exactamente lo que queremos

Estructura del mes

Gymd

G = s => new Date(y, m, d)[s]()

x

Formateo de eventos

El siguiente código se usa para formatear un evento.

[h, t] = e[d] || E,           // split the content of the event into h and t
o = [x * d, h],               // set the first 2 entries of o[]: day and hour
q = E,                        // we start with q = empty string
t &&                          // skip this .map() loop entirely if t is not defined
t.split` `                    // split the string on spaces
.map(s =>                     // for each word s:
  q =                         //   update q:
    (u = q ? q + ' ' + s : s) //     u is the concatenation of the previous string with
                              //     the new word, separated by a space if needed
    [9] ?                     //     if u is more than 9 character long:
      o.push(q)               //       push the previous string in o[]
      && s                    //       and reset q to s
    :                         //     else:
      u                       //       update q to u
),                            // end of map()
[...o, q][r % 5]              // append the last pending part to o[] and extract the
|| E                          // relevant row; or use an empty string by default
Arnauld
fuente
3

Python 2 , 326 324 315 312 307 bytes

import calendar as c,textwrap as t
c.setfirstweekday(6)
y,m,e=input()
print' Su Mo Tu We Th Fr Sa\n'.replace(' ',' '*8)[4:]+'-'*71
for w in c.monthcalendar(y,m):
 for l in zip(*[[d or'',a]+(t.wrap(b,9)+['']*3)[:3]for d in w for a,b in[e.get(d,'  ')]]):print'|'+'|'.join('%-9s'%v for v in l)+'|'
 print'-'*71

Pruébalo en línea!

La misma entrada que la respuesta JS de Arnauld :

Toma entrada como (y,m,e)donde:

  • y es el año
  • m es el mes, 1 indexado
  • ees un objeto cuyas claves son los días y cuyos valores son los eventos en (hour, task)formato
TFeld
fuente
3

Carbón , 215 206 bytes

Sθ≔I⪪§⪪θ ⁰/η≔⁻⁺×¹²⊟η⊟η²η≔EE²⁻ηι﹪Σ⟦÷ι⁴⁸⁰⁰±÷ι¹²⁰⁰÷ι⁴⁸÷ι¹²÷×¹³⁺⁴﹪ι¹²¦⁵⟧⁷η≔±⊟ηζ≔⁺²⁸﹪⁺⊟ηζ⁷ε⭆⪪SuMoTuWeThFrSa²◨◧ι⁶χ↓←⁷¹W‹ζε«↘F⁷«P↓⁵→≦⊕ζF⁼Iζ§⪪θ/⁰«≔⪪θ - θ≔⟦ω◨§θ¹¦⁹⟧δF⪪⊟θ ⊞δ⎇‹⁺L§δ±¹Lμ⁹⁺⁺⊟δ μμP⪫δ¶Sθ»◨×››ζ⁰›ζεIζ⁹»↓⁵←⁷¹

Pruébalo en línea! El enlace es a la versión detallada del código. Toma fechas en formato d / m / aaaa. Explicación:

Sθ

Ingrese el primer evento.

≔I⪪§⪪θ ⁰/η

Extraer la fecha y dividir en /s.

≔⁻⁺×¹²⊟η⊟η²η

Convertir a meses desde marzo, 1 a. C. Quiero calcular el día de la semana del primero del mes próximo y del mes actual, y trabajar en meses es más fácil que mantener los meses y años separados y llevarlos al final del año, además de que también me permite comenzar a contar meses que comienzan en marzo en lugar de enero, lo cual es requerido por la congruencia de Zeller.

≔EE²⁻ηι﹪Σ⟦÷ι⁴⁸⁰⁰±÷ι¹²⁰⁰÷ι⁴⁸÷ι¹²÷×¹³⁺⁴﹪ι¹²¦⁵⟧⁷η

Use una congruencia de Zeller modificada para extraer el día de la semana del primer día del próximo mes y este mes. La parte básica se basa en el hecho de que el número de días desde el 30 de octubre del año anterior hasta el 1 de un mes dado donde m = 4para marzo y m = 14enero del año siguiente viene dado por la fórmula m * 153 / 5, sin embargo, podemos restar 140 porque solo preocuparse por el día de la semana. Luego queda hacer ajustes debido al año; cada año agrega un día, cada 4to año agrega un día adicional, cada 100 años resta un día y cada 400 años agrega un día nuevamente. (Como estoy trabajando en meses, estos valores se multiplican por 12). Más bien convenientemente, esto me da directamente la respuesta en términos de una semana indexada el domingo (normalmente agregaría el día del mes y comenzaría a contar el sábado).

≔±⊟ηζ

Niegue el día de la semana y guárdelo como el día actual del mes.

≔⁺²⁸﹪⁺⊟ηζ⁷ε

Calcule el número de días en el mes a partir del día de la semana de los dos meses.

⭆⪪SuMoTuWeThFrSa²◨◧ι⁶χ

Salida de los encabezados del día.

↓←⁷¹

Imprima la fila superior de -s.

W‹ζε«

Lazo hasta el último día del mes ha salido.

Mueva el cursor al inicio de la siguiente fila.

F⁷«

Procesar 7 días a la vez.

P↓⁵→

Imprima la columna de |s a la izquierda.

≦⊕ζ

Incremente el día actual del mes.

F⁼Iζ§⪪θ/⁰«

Si el día actual del mes es el día del evento actual, ...

≔⪪θ - θ

... extraer las otras partes del evento, ...

≔⟦ω◨§θ¹¦⁹⟧δ

... rellene el tiempo con 9 espacios y guárdelo con una cadena vacía como una lista, ...

F⪪⊟θ 

... dividir la descripción en espacios y recorrerlos, ...

⊞δ⎇‹⁺L§δ±¹Lμ⁹⁺⁺⊟δ μμ

... agregando cada palabra a la palabra anterior si cabe; ...

P⪫δ¶

... muestra el tiempo y la descripción ( Pδno funciona, ¿podría ser un error de carbón?), ...

Sθ»

... e ingrese el próximo evento.

◨×››ζ⁰›ζεIζ⁹»

Si el día actual del mes está comprendido entre 1 y el último día del mes, imprímalo, de lo contrario, solo genere suficientes espacios para pasar al día siguiente.

↓⁵←⁷¹

Al final de la semana, imprima la columna derecha de |sy la fila inferior de -s.

Neil
fuente
Tal vez lo salté en su detallado código TIO, pero ¿está seguro de que la implementación de congruencia de su Zeller está completa? Parece ser correcto para los meses de marzo a diciembre, pero para los meses de enero y febrero year-1deben usarse en lugar de yeary month+12deben usarse en lugar de month. ¿O simplificó de alguna manera el algoritmo que mencioné en esta respuesta 05AB1E que es igual al de Wikipedia ?
Kevin Cruijssen
@KevinCruijssen Esta es básicamente la razón por la que calculo el número de meses transcurridos desde marzo del 1 a. C., pero es demasiado complicado explicarlo más en un comentario.
Neil
1
@KevinCruijssen He actualizado mi explicación; Espero que le sea útil.
Neil
¡Gracias! De hecho, es una buena fórmula modificada, y ahora entiendo el razonamiento detrás de ella. Muchas gracias por agregarlo a la explicación. +1 de mi parte
Kevin Cruijssen
2

Java (JDK) , 538 439 428 425 bytes

Posiblemente la solución de Code Golf más larga que he publicado. Todavía trato de jugar golf desde aquí, pero es una lucha.

Se las arregló para eliminar 99 bytes cambiando el formato de entrada y utilizando algunos análisis de expresiones regulares y otros 11 de bits varios.

¡3 bytes adicionales de descuento gracias a Kevin!

Inspirándose en otras respuestas, toma datos como el año, mes y un Mapa de días para una Cadena que representa la hora y el evento en el formato <time>-<event>.

(y,m,M)->{var C=java.util.Calendar.getInstance();C.set(y,m-1,1);String r=",Su,,Mo,,Tu,,We,,Th,,Fr,,Sa\n".replace(",","    "),e;for(int x=C.getActualMaximum(5),l=0,b=0,j,c,i=0;i<7;r+="\n",l+=b<=x&++i>6?7*(i=1):0)for(j=0;j<71;b=l+j/10+2-C.get(7),e=(e=M.get(b))!=null?e.replaceAll("([^-]{1,9})(-| |$)","$1-")+" - ":null,r+=e=i%6<1?"-":c<1?"|":c*i<2&b>0&b<=x?b+"":c<2&e!=null?e.split("-")[i-2]:" ",j+=e.length())c=j%10;return r;}

Pruébalo en línea!


Sin golf

(y,m,M)->{                                              // Lambda taking input as a year, month and map
  var C=java.util.Calendar.getInstance();               // Creates a new Calendar instance
  C.set(y,m-1,1);                                       // Sets the calendar to the first of the month in the given year    
  String r=",Su,,Mo,,Tu,,We,,Th,,Fr,,Sa\n"              // Creates the header row by replacing
    .replace(",","    "),e;                             // commas with 4 sets of spaces

  for(                                                  // Creates 7 rows for a calendar row
      int x=C.getActualMaximum(5)                       // Stores last day of the month
      ,l=0,b=0,j,c,i=0;i<7;                             // Initialises other integers
      r+="\n",                                          // Add new line each row
      l+=b<=x&++i>6                                     // If end of a calendar row is reached, and current day is less than max
        ?7*(i=1)                                        // Set i to 1 and add 7 to line count to create another calendar row
        :0)                                             // Otherwise do nothing

    for(j=0;j<71;                                       // Loop 71 times, appending characters to create a row
        b=l+j/10+2-C.get(7),                            // Determine the day of the box we're in
        e=(e=M.get(b))!=null?                           // Get the event for this day from the map and if not null
            e.replaceAll("([^-]{1,9})(-| |$)","$1-")      // Do some regex to separate the line entries by hyphens
            +" - "                                      // Append extra hyphen to prevent array out of bounds
            :null,                                      // Otherwise do nothing
        r+=e=i%6<1?"-":                                 // If it's the first line of a calendar row, append -
           c<1?"|":                                     // If it's the first column of a box, append |
           c*i<2&b>0&b<=x?b+"":                         // If it's the second column of a box, the second row, 
                                                        // and less than the max day, append the day
           c<2&e!=null?e.split("-")[i-2]:               // If it's any other row and there is an event then split and append correct line
           " ",                                         // Else just append a space
        j+=e.length())                                  // Increase the row character count by the length to append
          c=j%10;                                       // Set the column of box (this is the only thing in the loop so happens first)

  return r;                                             // return the calendar string!
}
Luke Stevens
fuente
&&(i=1)<2?7:0puede ser ?7*(i=1):0para guardar 3 bytes.
Kevin Cruijssen
@KevinCruijssen Un buen gracias!
Luke Stevens
Sugerir en b>x|i++<6?0:7*(i=1)lugar de b<=x&++i>6?7*(i=1):0y en c*i>1|b<1|b>x?c<2&e!=null?e.split("-")[i-2]:" ":b+""lugar dec*i<2&b>0&b<=x?b+"":c<2&e!=null?e.split("-")[i-2]:" "
ceilingcat
1

Rojo , 674651 bytes

func[a][z: func[a b c][to-tuple reduce[a b c]]c: a/1 c/4: 1 d: c + 31
d/4: 1 d: d - 1 e: 1 + c/weekday % 7 if e = 0[e: 7]foreach
t[:Su:Mo:Tu:We:Th:Fr:Sa][prin pad pad/left t 6 10]h:
pad/with"-"71 #"-"print["^/"h]m: copy[]foreach[i b]a[put m z r:(t: e - 1)+
i/4 / 7 + 1 n: i/4 % 7 + t 2 b/1 t: split b/2" "l: 0
until[if t/2[if 10 >((length? t/1)+ length? t/2)[t/1:
rejoin reduce[t/1" "take next t]]]put m z r n 2 + l: l + 1 take t
tail? t]i: 0]n: k: 0 repeat v(g: e - 1 + d/4)/ 7 + sign? g % 7[repeat
r 5[repeat i 7[t: copy"|"if i = e[k: 1]if all[k = 1 r = 1 n < d/4][append t
n: n + 1]if s: select m z v i r[append t s]prin pad t 10]print"|"]print h]]

Pruébalo en línea!

Más legible:

func [ a ] [
    c: d: a/1
    c/4: d/4: 1
    d: d + 31
    d/4: 1
    d: d - 1
    e: 1 + c/weekday % 7
    if e = 0[e: 7]
    g: e - 1 + d/4
    w: g / 7 + sign? g % 7
    foreach t [ :Su :Mo :Tu :We :Th :Fr :Sa ] [
        prin pad pad/left t 6 10
    ]
    h: pad/with "-" 71 #"-"
    print[ "^/" h ]
    m: copy #()
    foreach[ i b ] a [
        n: i/4 % 7 + t: e - 1
        r: t + i/4 / 7 + 1
        put m to-tuple reduce[ r n 2 ] b/1
        t: split b/2" "
        i: 0
        until [
            if t/2 [ if 9 >= ((length? t/1) + (length? t/2)) [
                t/1: rejoin reduce[t/1" "take next t]
                ]
            ]
            put m to-tuple reduce [ r n 2 + i: i + 1 ] take t
            tail? t
        ]

    ]
    n: 0
    g: off
    repeat v w [
        repeat r 5 [
           repeat i 7 [
                t: copy "|"
                if i = e[ g: on ]
                if all [ g r = 1 n < d/4 ] [ append t n: n + 1 ]
                if s: select m to-tuple reduce [ v i r ]
                    [ append t s ]
                prin pad t 10
            ]
            print "|"
        ]
        print h
    ]
]
Galen Ivanov
fuente
if e = 0[e: 7]se puede quitar, ¿verdad? Usas e: 1 + c/weekday % 7, por elo que siempre estará en el rango [1, 7].
Kevin Cruijssen
@KevinCruijssen: Tal vez me estoy perdiendo algo, pero creo que lo necesito. La indexación roja se basa en 1. Eche un vistazo a esto: >> c: ahora / hora / fecha == 12-oct-2018 >> c: c + 1 == 13-oct-2018 >> 1 + c / día de la semana% 7 == 0; >> 1 + 2 * 3 es 9 en rojo, no 7
Galen Ivanov
1
EDITAR: Ah, nvm ... 1 + Primero sucede ... Ok, veo mi error Estoy acostumbrado %y /tengo prioridad sobre el operador +.
Kevin Cruijssen
1
@KevinCruijssen Sí, exactamente. No hay precedencia de operadores en rojo, uno debe usar () en su lugar
Galen Ivanov