Planowanie kalendarza ASCII

11

Biorąc pod uwagę listę działań oraz ich datę / godzinę rozpoczęcia, wydrukuj kalendarz ASCII-art przedstawiający działania w odpowiednich dniach. Wszystkie działania odbywają się w tym samym miesiącu, żadne dwa działania nie będą miały tego samego dnia, a wszystkie działania mieszczą się w polu kalendarza.

Kalendarz ma datę w lewym górnym rogu każdego pola, pola mają szerokość 9 pól i wysokość 5 pól, otoczone -i |. Dwuliterowy skrót oznaczający dzień tygodnia jest wyśrodkowany nad pierwszym rzędem, a tygodnie rozpoczynają się od niedzieli.

Na przykład biorąc pod uwagę następujące działania:

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

Wydrukuj ten odpowiedni kalendarz:

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

Wyjaśnienia

  • Słowa harmonogramu (pasujące [A-Za-z] +) zostaną oddzielone pojedynczym odstępem między nimi (jak w przykładzie).
  • Wystarczy podzielić tekst na granice słów. Nie ma potrzeby dzielenia wyrazów.
  • Jeśli luty rozpocznie się w niedzielę w roku przestępnym, będziesz mieć tylko cztery wiersze kalendarza.
  • Jeśli 31-dniowy miesiąc (np. Sierpień) rozpocznie się późno w tygodniu, być może trzeba wydrukować sześć wierszy kalendarza.

I / O i reguły

  • Twój kod musi obsługiwać daty przynajmniej między kalendarzem gregoriańskim 0001-01-01i 9999-12-31w nim, w tym, odpowiednio, lata przestępne. Na przykład, jeśli podano dane wejściowe 2016-02-13 9:00am Test, kalendarz wyjściowy powinien mieć 29 lutego.
  • Format daty wejściowej może być w dowolnym żądanym formacie. ISO 8601, datetimeobiekt, szczególnie sformatowany ciąg znaków itp. Analiza wejściowa nie jest interesującą częścią tego wyzwania.
  • Wejście i wyjście może odbywać się dowolną dogodną metodą .
  • Wiodące / końcowe znaki nowej linii lub inne białe znaki są opcjonalne, pod warunkiem, że znaki są odpowiednio ustawione.
  • Dopuszczalny jest pełny program lub funkcja. Jeśli funkcja, możesz zwrócić dane wyjściowe zamiast je drukować.
  • Dane wyjściowe mogą być wysyłane do konsoli, zwracane jako lista ciągów, zwracane jako pojedynczy ciąg itp.
  • Standardowe luki są zabronione.
  • To jest więc obowiązują wszystkie zwykłe zasady gry w golfa, a wygrywa najkrótszy kod (w bajtach).
AdmBorkBork
źródło
1.) Czy musisz podzielić nazwy działań na granicach słów? 2.) Czy w lutym rozpoczynającym się w niedzielę w niedzielę masz tylko 4 rzędy? 3.) Kiedy potrzebujesz 6 wierszy, aby pokazać miesiąc (np. Sierpień od soboty), co się stanie?
nedla2004,
Powiązane (łatwiej).
Arnauld,
@ nedla2004 1) Tak, granice słów będą działać poprawnie. 2) To prawda, 4 rzędy. 3) Twój kalendarz będzie musiał pokazywać 6 wierszy. Przeredaguję w wyjaśnieniach.
AdmBorkBork,
@Arnauld Tak, to uczciwe założenie
AdmBorkBork,
1
1752-09-02 - 09:00am - Wife's Birthday Tomorrow (14th!)
ngm,

Odpowiedzi:

10

JavaScript (ES8), 380321 320 bajtów

Pobiera dane wejściowe, gdy (y,m,e):

  • y jest rok
  • m jest miesiącem 0-indeksowanym
  • eto obiekt, którego kluczami są dni, a których wartościami są zdarzenia w [hour, task]formacie
(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`)

Wypróbuj online!

W jaki sposób?

Poniżej znajduje się kilka ważnych części kodu.

nagłówek

Linia nagłówka jest generowana za pomocą:

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

Gdy split()jest używana z wyrażeniem regularnym zawierającym grupę przechwytującą, ta grupa jest zawarta w tablicy wyjściowej. W takim przypadku daje:

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

Łączymy tę tablicę z 4 spacjami, co prowadzi do:

'    Su        Mo        Tu        We        Th        Fr        Sa    \n'

dokładnie tego chcemy.

Struktura miesiąca

Gymd

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

x

Formatowanie zdarzeń

Poniższy kod służy do formatowania zdarzenia.

[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
źródło
3

Python 2 , 326 324 315 312 307 bajtów

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

Wypróbuj online!

Taki sam wkład jak odpowiedź JS Arnaulda :

Pobiera dane wejściowe, gdy (y,m,e):

  • y jest rok
  • m oznacza miesiąc zindeksowany 1
  • eto obiekt, którego kluczami są dni, a których wartościami są zdarzenia w (hour, task)formacie
TFeld
źródło
3

Węgiel drzewny , 215 206 bajtów

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

Wypróbuj online! Link jest do pełnej wersji kodu. Przyjmuje daty w formacie d / m / rrrr. Wyjaśnienie:

Sθ

Wprowadź pierwsze zdarzenie.

≔I⪪§⪪θ ⁰/η

Wyodrębnij datę i podziel na /s.

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

Przelicz na miesiące od marca 1 pne. Chcę obliczyć dzień tygodnia pierwszego zarówno następnego, jak i bieżącego miesiąca, a praca w miesiącach jest łatwiejsza niż oddzielenie miesięcy i lat od siebie pod koniec roku, a także pozwala mi zacząć liczyć miesiące zaczynające się w marcu zamiast w styczniu, co jest wymagane przez zgodność Zellera.

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

Użyj zmodyfikowanej zgodności Zellera, aby wyodrębnić dzień tygodnia pierwszego dnia następnego miesiąca i tego miesiąca. Podstawowa część polega na tym, że liczba dni od 30 października poprzedniego roku do 1 dnia danego miesiąca, gdzie m = 4dla marca i m = 14stycznia następnego roku jest podana wzorem m * 153 / 5, jednak możemy odjąć 140, ponieważ tylko dbać o dzień tygodnia. Następnie pozostaje dokonać korekt z powodu roku; każdy rok dodaje dzień, każdy 4 rok dodaje dodatkowy dzień, każdy 100 rok odejmuje dzień, a każdy 400 rok dodaje dzień ponownie. (Ponieważ pracuję od miesięcy, wszystkie te wartości są mnożone przez 12.) Raczej wygodnie to bezpośrednio daje mi odpowiedź w kategoriach tygodnia indeksowanego w niedzielę (zwykle dodaje się dzień miesiąca i zaczyna liczyć w sobotę).

≔±⊟ηζ

Neguj dzień tygodnia i zapisz go jako bieżący dzień miesiąca.

≔⁺²⁸﹪⁺⊟ηζ⁷ε

Oblicz liczbę dni w miesiącu od dnia tygodnia dwóch miesięcy.

⭆⪪SuMoTuWeThFrSa²◨◧ι⁶χ

Wyjście nagłówków dnia.

↓←⁷¹

Wydrukuj górny wiersz -s.

W‹ζε«

Pętla do ostatniego dnia miesiąca została wygenerowana.

Przesuń kursor na początek następnego wiersza.

F⁷«

Przetwarzaj 7 dni na raz.

P↓⁵→

Wydrukuj kolumnę |s po lewej stronie.

≦⊕ζ

Zwiększ aktualny dzień miesiąca.

F⁼Iζ§⪪θ/⁰«

Jeśli bieżącym dniem miesiąca jest dzień bieżącego wydarzenia, ...

≔⪪θ - θ

... wypakuj pozostałe części wydarzenia, ...

≔⟦ω◨§θ¹¦⁹⟧δ

... uzupełnij czas do 9 spacji i zapisz go oraz pusty ciąg jako listę, ...

F⪪⊟θ 

... podziel opis na spacje i zapętlaj nad nimi, ...

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

... dodając każde słowo do poprzedniego słowa, jeśli będzie pasować; ...

P⪫δ¶

... wypisuje czas i opis ( Pδnie działa, może to być błąd węgla drzewnego?), ...

Sθ»

... i wprowadź następne zdarzenie.

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

Jeśli bieżący dzień miesiąca mieści się w przedziale od 1 do ostatniego dnia miesiąca, wyślij go, w przeciwnym razie po prostu wypuść wystarczająco dużo miejsca, aby przejść do następnego dnia.

↓⁵←⁷¹

Pod koniec tygodnia wydrukuj prawą kolumnę |s i dolny rząd -s.

Neil
źródło
Może pominąłem to w twoim pełnym kodzie TIO, ale czy jesteś pewien, że twoja zgodność Zellera jest ukończona? Wydaje się, że jest to poprawne dla miesięcy od marca do grudnia, ale dla miesięcy od stycznia i lutego year-1należy użyć zamiast yeari month+12należy je stosować zamiast month. Czy może w jakiś sposób uprościłeś algorytm, o którym wspomniałem w tej mojej odpowiedzi 05AB1E, która jest równa tej z Wikipedii ?
Kevin Cruijssen
@KevinCruijssen Właśnie dlatego obliczam liczbę miesięcy od 1 marca pne, ale jest to zbyt skomplikowane, aby wyjaśnić je dalej w komentarzu.
Neil,
1
@KevinCruijssen Zaktualizowałem moje wyjaśnienie; Mam nadzieję, że będzie to dla ciebie pomocne.
Neil,
Dzięki! To rzeczywiście fajna zmodyfikowana formuła i teraz rozumiem jej uzasadnienie. Wielkie dzięki za dodanie go do wyjaśnienia. +1 ode mnie
Kevin Cruijssen
2

Java (JDK) , 538 439 428 425 bajtów

Prawdopodobnie najdłuższe rozwiązanie Code Golf, jakie kiedykolwiek opublikowałem. Wciąż próbuję zagrać w golfa stąd, ale to walka.

Udało się wyeliminować 99 bajtów, zmieniając format wejściowy i używając parsowania wyrażeń regularnych, a kolejne 11 z różnych bitów.

3 dodatkowe bajty wyłączone dzięki Kevinowi!

Czerpiąc inspirację z innych odpowiedzi, pobiera dane wejściowe jako rok, miesiąc i mapę dni do ciągu reprezentującego czas i zdarzenie w formacie <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;}

Wypróbuj online!


Nie golfił

(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
źródło
&&(i=1)<2?7:0można ?7*(i=1):0zapisać 3 bajty.
Kevin Cruijssen
@KevinCruijssen Ładne dzięki!
Luke Stevens,
Zaproponuj b>x|i++<6?0:7*(i=1)zamiast b<=x&++i>6?7*(i=1):0i c*i>1|b<1|b>x?c<2&e!=null?e.split("-")[i-2]:" ":b+""zamiastc*i<2&b>0&b<=x?b+"":c<2&e!=null?e.split("-")[i-2]:" "
ceilingcat 27.09.19
1

Czerwony , 674 651 bajtów

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

Wypróbuj online!

Bardziej czytelny:

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 Iwanow
źródło
if e = 0[e: 7]można usunąć, prawda? Używasz e: 1 + c/weekday % 7, więc ezawsze będzie w zasięgu [1, 7].
Kevin Cruijssen
@KevinCruijssen: Może czegoś mi brakuje, ale myślę, że tego potrzebuję. Czerwone indeksowanie jest oparte na 1. Spójrz na to: >> c: teraz / czas / data == 12-paź-2018 >> c: c + 1 == 13-paź-2018 >> 1 + c / dzień tygodnia% 7 == 0; >> 1 + 2 * 3 ma 9 na czerwono, a nie 7
Galen Iwanow
1
EDYCJA: Ah, nvm .. 1 + Dzieje się to najpierw .. Ok, widzę mój błąd. Jestem przyzwyczajony %i /mam pierwszeństwo przed operatorem +.
Kevin Cruijssen
1
@KevinCruijssen Tak, dokładnie. W Red nie ma pierwszeństwa operatorów, zamiast tego należy użyć ()
Galen Iwanow