ASCII日历计划器


11

给定活动列表及其开始时间/日期,请输出一个ASCII艺术日历,显示相应日期的活动。保证所有活动都在同一个月内进行,没有两个活动可以在同一天进行,并且保证所有活动都可以放在日历框中。

日历的日期在每个框的左上角,这些框宽9乘5高,由-和包围|。星期几的两个字母的缩写位于第一行的上方,而星期几则从星期日开始。

例如,给定以下活动:

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

输出此相应的日历:

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

澄清说明

  • 调度字(匹配[A-Za-z] +)将由它们之间的单个空格分隔(如示例中所示)。
  • 在单词边界上分割文本就足够了。无需连字。
  • 如果2月在非le年的星期日开始,则只有4个日历行。
  • 如果一个31天的月份(例如,八月)在一周中的晚些时候开始,则可能必须输出六行日历。

I / O和规则

  • 您的代码必须至少处理公历之间0001-01-019999-12-31之中的日期,包括适当的leap年。例如,如果给定input 2016-02-13 9:00am Test,则输出日历应具有2月29日。
  • 输入日期格式可以是任何所需的格式。ISO 8601,datetime对象,格式特殊的字符串等。输入解析不是此挑战的有趣部分。
  • 输入和输出可以通过任何方便的方法
  • 前导/尾随换行符或其他空格是可选的,前提是这些字符必须正确排列。
  • 完整的程序或功能都是可以接受的。如果是函数,则可以返回输出而不是打印输出。
  • 输出可以发送到控制台,以字符串列表形式返回,以单个字符串形式返回,等等。
  • 禁止出现标准漏洞
  • 这是因此所有常用的高尔夫规则都适用,并且最短的代码(以字节为单位)获胜。

1.)您是否必须在单词边界处拆分活动名称?2)当您在星期日开始的非-年2月时,是否只有4行?3.)当您需要6行来显示月份(例如,从周六开始的8月)时,会发生什么?
nedla2004 '18 -10-10

相关(更容易)。
阿纳尔德

@ nedla2004 1)是的,单词边界可以正常工作。2)是的,是4行。3)您的日历将需要显示6行。我将进行澄清说明。
AdmBorkBork

@Arnauld是的,这是一个合理的假设
AdmBorkBork

1
1752-09-02 - 09:00am - Wife's Birthday Tomorrow (14th!)
ngm

Answers:


10

JavaScript(ES8),380321 320字节

将输入作为以下(y,m,e)位置:

  • y 是一年
  • m 是月份,索引为0
  • e是一个对象,其键是日期,值是事件,[hour, task]格式为
(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`)

在线尝试!

怎么样?

以下是代码中的一些重要部分。

标头

标题行的生成是:

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

split()与包含捕获组的正则表达式一起使用时,此组将包含在输出数组中。在这种情况下,它给出:

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

我们将这个数组与4个空格连接起来,结果是:

'    Su        Mo        Tu        We        Th        Fr        Sa    \n'

这正是我们想要的。

月结构

Gÿd

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

X

事件格式

以下代码用于格式化事件。

[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

3

Python 2中326个 324 315 312 307字节

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

在线尝试!

Arnauld的JS答案相同的输入:

将输入作为以下(y,m,e)位置:

  • y 是一年
  • m 是1索引的月份
  • e是一个对象,其键是日期,值是事件,(hour, task)格式为

3

木炭215206字节

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

在线尝试!链接是详细版本的代码。采用d / m / yyyy格式的日期。说明:

Sθ

输入第一个事件。

≔I⪪§⪪θ ⁰/η

提取日期并在上分割/

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

自公元前3月1日起转换为月数。我想计算下个月和当前月份的第一天的星期几,用几个月工作要比将月份和年份分开并在年底进行比较容易,而且它还允许我开始计算从Zeller的全等出发,从3月开始而不是1月开始的几个月。

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

使用修改后的Zeller同余来提取下个月和本月第一天的星期几。基本部分依赖于这样一个事实,即从上一年的10月30日到给定月份的1号的天数(公式中给出m = 4了3月和m = 14次年1月的天数)m * 153 / 5,但是我们可以减去140,因为关心星期几。然后,仍需根据年份进行调整;每年增加一天,第4年增加一天,第100年减去一天,第400年又增加一天。(因为我在几个月中工作,所以所有这些值都乘以12。)相反,这很方便地直接为我提供了以周日为索引的星期的答案(通常您会添加一个月中的某天,然后从周六开始计数)。

≔±⊟ηζ

否定星期几并将其保存为该月的当前日期。

≔⁺²⁸﹪⁺⊟ηζ⁷ε

从两个月中的星期几开始计算一个月中的天数。

⭆⪪SuMoTuWeThFrSa²◨◧ι⁶χ

输出日期标题。

↓←⁷¹

打印-s 的第一行。

W‹ζε«

循环播放直到输出该月的最后一天。

将光标移到下一行的开头。

F⁷«

一次处理7天。

P↓⁵→

|s 列打印到左侧。

≦⊕ζ

增加月份中的当前日期。

F⁼Iζ§⪪θ/⁰«

如果该月的当前日期是当前事件的日期,则...

≔⪪θ - θ

...提取事件的其他部分,...

≔⟦ω◨§θ¹¦⁹⟧δ

...将时间填充到9个空格并将其和一个空字符串保存为列表,...

F⪪⊟θ 

...将空格的描述分割并循环遍历...

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

...将每个单词添加到前一个单词(如果合适);...

P⪫δ¶

...输出时间和描述(Pδ不起作用,可能是木炭虫?),...

Sθ»

...并输入下一个事件。

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

如果该月的当前日期在1到该月的最后一天之间,则输出该日期,否则仅输出足够的空间以移至第二天。

↓⁵←⁷¹

在一周结束时,打印|s 的右列和s的底行-


也许我在您详细的TIO代码中跳过了它,但是您确定Zeller的一致性实现是完整的吗?从3月到12月,这似乎是正确的,但对于1月和2月,year-1应该使用代替,yearmonth+12应使用1和2月份代替month。还是您以某种方式简化了我我的05AB1E答案中提到的算法,该算法与Wikipedia的算法相同?
凯文·克鲁伊森

@KevinCruijssen这基本上就是我计算自1BC年3月以来的月数的原因,但是它太复杂了,无法在评论中进一步解释。
尼尔,

1
@KevinCruijssen我已经更新了我的解释;我希望你觉得这对你有帮助。
尼尔

谢谢!这确实是一个不错的修改公式,我现在了解其背后的原因。非常感谢您将其添加到说明中。向我+1。
凯文·克鲁伊森

2

爪哇(JDK) 538个 439 428 425字节

我发布的代码高尔夫可能是最长的解决方案。仍在尝试从这里打高尔夫球,但这很困难。

通过更改输入格式并使用一些正则表达式解析来设法删除了99个字节,并从其他位中删除了11个字节。

多亏Kevin的支持,额外的3个字节!

从其他答案中汲取灵感,它将输入作为年,月和天映射到以格式表示时间和事件的字符串<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;}

在线尝试!


不打高尔夫球

(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!
}

&&(i=1)<2?7:0可以?7*(i=1):0节省3个字节。
凯文·克鲁伊森

@KevinCruijssen很好,谢谢!
路加·史蒂文斯

推荐b>x|i++<6?0:7*(i=1)替代b<=x&++i>6?7*(i=1):0c*i>1|b<1|b>x?c<2&e!=null?e.split("-")[i-2]:" ":b+""取代c*i<2&b>0&b<=x?b+"":c<2&e!=null?e.split("-")[i-2]:" "
ceilingcat

1

红色674651字节

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

在线尝试!

更具可读性:

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

if e = 0[e: 7]可以移走吧?您使用e: 1 + c/weekday % 7,因此e将始终在范围内[1, 7]
凯文·克鲁伊森

@KevinCruijssen:也许我缺少了一些东西,但我认为我需要它。红色索引基于1。请查看以下内容:>> c:现在/时间/日期== 2018年10月12日>> c:c + 1 == 2018年10月13日>> 1 + c /工作日%7 == 0; >> 1 + 2 * 3是红色的9,而不是7
Galen Ivanov '18

1
编辑:啊,nvm。。首先1 + 发生。。好吧,我看到了我的错误。我已经习惯了%,并/有超过运算符优先级+
凯文·克鲁伊森

1
@KevinCruijssen是的,完全是。Red中没有运算符优先级,需要使用()代替
Galen Ivanov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.