Калькулятор даты Забытых Царств

18

Чтобы выровнять игровое поле между языками со встроенными библиотеками дат и без, давайте поработаем с вымышленным календарем. Забытые Королевства - это ( ? ) Кампания для Dungeons & Dragons. Конечно, у каждого свой календарь.

Календарь Гарптос

Удобно, что год в Забытых Царствах также имеет 365 дней. Кроме того, календарь также имеет 12 месяцев. Тем не менее, это то, где это становится интересным. Каждый месяц длится ровно 30 дней. Оставшиеся 5 дней являются выходными, которые выпадают между месяцами. Вот месяцы и праздники по порядку (с отступом):

1   Deepwinter
        Midwinter
2   The Claw of Winter
3   The Claw of the Sunsets
4   The Claw of the Storms
        Greengrass
5   The Melting
6   The Time of Flowers
7   Summertide
        Midsummer
        [Shieldmeet]
8   Highsun
9   The Fading
        Highharvestide
10  Leaffall
11  The Rotting
        The Feast of the Moon
12  The Drawing Down

Обратите внимание, что я вставил шестой праздник в скобках. Это високосный день, который происходит только каждые четыре года (да, вот и все - никаких дополнительных махинаций с веками).

Дополнительное примечание об названиях месяцев: у каждого месяца есть формальное и общее название. Выше приведены общие имена. Я выбрал их, потому что я думаю, что они допускают более интересное сжатие.

Существует несколько нумераций лет, но наиболее распространенной является Dalereckoning , сокращенная до DR . (Кроме того, каждый год имеет одно или несколько имен , но мы не будем беспокоиться об этом.)

Компоненты даты должны быть разделены запятой и пробелом. В общем, действительная дата может выглядеть так:

4, The Melting, 1491 DR

или

Shieldmeet, 1464 DR

Обратите внимание, что для праздников нет номера дня. (Я полагаю, что 4th of The Meltingбыло бы лучше для дней месяцев, но я не хочу перетаскивать порядковые числа в это.)

Сноска. Я придумал это, когда xnor пожаловался на то, что для каждой отдельной даты требуется вычисление високосного года. Мне не удалось полностью его устранить, но, по крайней мере, в этом календаре только один модуль.

Соревнование

Если задана правильная дата Календаря Гарптос, а также целое число D, выведите дату Dчерез несколько дней. Обратите внимание, что это Dможет быть отрицательным, и в этом случае вы должны вернуть дату Dдней раньше.

Вы можете написать программу или функцию, принимая ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции и выводя результат через STDOUT (или ближайшую альтернативу), возвращаемое значение функции или параметр функции (out).

Вы можете предположить, что год положительный и меньше 2000.

Применяются стандартные правила .

Тестовые случаи

Первые дюжина или около того контрольных примеров должны проверять все крайние случаи, связанные с праздниками и високосными годами. Следующим набором является тестирование, которое охватывает несколько лет работы и все месяцы и праздники были реализованы. Во второй половине все те же тесты, но с отрицательными смещениями.

"30, Summertide, 1491 DR" 1                 => "Midsummer, 1491 DR"
"30, Summertide, 1491 DR" 2                 => "1, Highsun, 1491 DR"
"Midsummer, 1491 DR" 1                      => "1, Highsun, 1491 DR"
"30, Summertide, 1492 DR" 1                 => "Midsummer, 1492 DR"
"30, Summertide, 1492 DR" 2                 => "Shieldmeet, 1492 DR"
"30, Summertide, 1492 DR" 3                 => "1, Highsun, 1492 DR"
"Midsummer, 1492 DR" 1                      => "Shieldmeet, 1492 DR"
"Midsummer, 1492 DR" 2                      => "1, Highsun, 1492 DR"
"Shieldmeet, 1492 DR" 1                     => "1, Highsun, 1492 DR"
"1, Highsun, 1490 DR" 365                   => "1, Highsun, 1491 DR"
"1, Highsun, 1491 DR" 365                   => "Shieldmeet, 1492 DR"
"Shieldmeet, 1492 DR" 365                   => "Midsummer, 1493 DR"
"Midsummer, 1493 DR" 365                    => "Midsummer, 1494 DR"
"Shieldmeet, 1500 DR" 365                   => "Midsummer, 1501 DR"

"14, Deepwinter, 654 DR" 5069               => "The Feast of the Moon, 667 DR"
"Midwinter, 17 DR" 7897                     => "15, The Fading, 38 DR"
"3, The Claw of Winter, 1000 DR" 813        => "25, The Claw of the Storms, 1002 DR"
"Greengrass, 5 DR" 26246                    => "9, The Claw of the Sunsets, 77 DR"
"30, The Melting, 321 DR" 394               => "29, The Time of Flowers, 322 DR"
"17, The Time of Flowers, 867 DR" 13579     => "20, Highsun, 904 DR"
"Highharvestide, 1814 DR" 456               => "30, The Drawing Down, 1815 DR"
"23, The Rotting, 1814 DR" 3616             => "16, Leaffall, 1824 DR"
"1, Deepwinter, 1 DR" 730499                => "30, The Drawing Down, 2000 DR"

"Midsummer, 1491 DR" -1                     => "30, Summertide, 1491 DR"
"1, Highsun, 1491 DR" -2                    => "30, Summertide, 1491 DR"
"1, Highsun, 1491 DR" -1                    => "Midsummer, 1491 DR"
"Midsummer, 1492 DR" -1                     => "30, Summertide, 1492 DR"
"Shieldmeet, 1492 DR" -2                    => "30, Summertide, 1492 DR"
"1, Highsun, 1492 DR" -3                    => "30, Summertide, 1492 DR"
"Shieldmeet, 1492 DR" -1                    => "Midsummer, 1492 DR"
"1, Highsun, 1492 DR" -2                    => "Midsummer, 1492 DR"
"1, Highsun, 1492 DR" -1                    => "Shieldmeet, 1492 DR"
"1, Highsun, 1491 DR" -365                  => "1, Highsun, 1490 DR"
"Shieldmeet, 1492 DR" -365                  => "1, Highsun, 1491 DR"
"Midsummer, 1493 DR" -365                   => "Shieldmeet, 1492 DR"
"Midsummer, 1494 DR" -365                   => "Midsummer, 1493 DR"
"Midsummer, 1501 DR" -365                   => "Shieldmeet, 1500 DR"

"The Feast of the Moon, 667 DR" -5069       => "14, Deepwinter, 654 DR"
"15, The Fading, 38 DR" -7897               => "Midwinter, 17 DR"
"25, The Claw of the Storms, 1002 DR" -813  => "3, The Claw of Winter, 1000 DR"
"9, The Claw of the Sunsets, 77 DR" -26246  => "Greengrass, 5 DR"
"29, The Time of Flowers, 322 DR" -394      => "30, The Melting, 321 DR"
"20, Highsun, 904 DR" -13579                => "17, The Time of Flowers, 867 DR"
"30, The Drawing Down, 1815 DR" -456        => "Highharvestide, 1814 DR"
"16, Leaffall, 1824 DR" -3616               => "23, The Rotting, 1814 DR"
"30, The Drawing Down, 2000 DR" -730499     => "1, Deepwinter, 1 DR"
Мартин Эндер
источник
1
DragonLance - еще одна важная настройка кампании D & D. Я мало что могу вспомнить об их календаре, за исключением трех лун, орбиты которых подробно объяснялись в каком-то справочнике.
CJ Деннис

Ответы:

5

Рубин, 543 523 521 498 511 509 байт

Чтобы получить больше ответов на этот вопрос, я собираюсь опубликовать версию моего Python-ответа для Ruby, поскольку я подумал, что он будет короче. Этот ответ является короче , но не намного. Вы можете сделать лучше?

Изменить: Благодаря Мартина Бюттнера и его предложение здесь .

Изменить: я значительно упал в списке «количество дней в месяце».

Edit: В то время как игра в гольф вниз , как я обращался d[10]=r%4<1?1:0к d[10]=0**(r%4)за байтом, я заметил , что я ввел ошибку в то время как игра в гольф вниз d, количество списка дней, так что Шилдмит было 30 дней случайно. И вот, количество байтов снова увеличилось. Я также отредактирую ответ Python, чтобы исправить эту ошибку там.

Изменить: я забыл, что функции не должны быть названы в этом вопросе.

->s,n{x=s[0..-4].split(", ");x=x[2]?x:[1,*x];t=(["Deepwinter,Midwinter","Winter","Sunsets","the Storms,Greengrass,The Melting,The Time of Flowers,Summertide,Midsummer,Shieldmeet,Highsun,The Fading,Highharvestide,Leaffall,The Rotting,The Feast of the Moon,The Drawing Down"]*',The Claw of ').split(?,);p,q,r=x[0].to_i+n,t.index(x[1]),x[2].to_i;d=[30,1,30,30]*4+[1,30];d[10]=0**(r%4);(a=p<1?1:-1;q=(q-a)%18;p+=a*d[a<0?q-1:q];r-=a*0**q;d[10]=0**(r%4))until(1..d[q])===p;z=d[q]<2?[t[q],r]:[p,t[q],r];z*", "+" DR"}

Ungolfed:

def h(s,n)
  x=s[0..-4].split(", ")
  x=x[2]?x:[1,*x]
  t=["Deepwinter,Midwinter","Winter","Sunsets","the Storms,Greengrass,The Melting,The Time of Flowers,Summertide,Midsummer,Shieldmeet,Highsun,The Fading,Highharvestide,Leaffall,The Rotting,The Feast of the Moon,The Drawing Down"]
  t=t*',The Claw of '           # turns the above array into a string with "Claw"s inserted
  t=t.split(?,)                 # then splits that string back up again by ","
  p=x[0].to_i+n
  q=t.index(x[1])
  r=x[2].to_i
  d=[30,1,30,30]*4+[1,30]
  d[10]=0**(r%4)
  until(1..d[q])===p
    a=p<1?1:-1
    q=(q-a)%18
    p+=a*d[a<0?q-1:q]
    r-=a*0**q
    d[10]=0**(r%4)
  end
  z=d[q]<2?[t[q],r]:[p,t[q],r]  # putting z=[t[q],r] on another line saved me no bytes
  z*", "+" DR"
end
Sherlock9
источник
5

Python 3, 712 652 636 567 563 552 550 548 529 540 байт

Наконец-то я нашел время написать ответ на этот отличный вопрос. Это еще не очень удачно (список названий месяцев и список дней являются особенно вопиющими в этом случае , и тот факт, что обработка отрицательных Dзначений требует отдельного цикла while ), но, по крайней мере, это ответ.

Изменить: Исправление ошибки

def h(s,n):
 x=s[:-3].split(", ");x=[1]*(len(x)<3)+x;t="Deepwinter,Midwinter,The Claw of Winter,The Claw of the Sunsets,The Claw of the Storms,Greengrass,The Melting,The Time of Flowers,Summertide,Midsummer,Shieldmeet,Highsun,The Fading,Highharvestide,Leaffall,The Rotting,The Feast of the Moon,The Drawing Down".split(",");p,q,r=int(x[0])+n,t.index(x[1]),int(x[2]);d=[30,1,30,30]*4+[1,30];d[10]=r%4<1
 while p>d[q]or p<1:a=[-1,1][p<1];q=(q-a)%18;p+=a*d[q-(a<0)];r-=a*0**q;d[10]=r%4<1
 return', '.join([str(p)]*(d[q]>2)+[t[q],str(r)])+" DR"

Ungolfed:

def harptos(date, num):
    t = "Deepwinter,Midwinter,The Claw of Winter,The Claw of the Sunsets,The Claw of the Storms,Greengrass,The Melting,The Time of Flowers,Summertide,Midsummer,Shieldmeet,Highsun,The Fading,Highharvestide,Leaffall,The Rotting,The Feast of the Moon,The Drawing Down"
    t = t.split(",")        # split up the names of the months
    x = date[:-3]           # removes " DR"
    x = x.split(", ")
    if len(x) < 3:
        x = [1] + x         # if we have two items (holiday), append a "day of the month"
    p = int(x[0]) + num     # initialize the "date" by adding num to it
    q = t.index(x[1])
    r = int(x[2])
    d=[30,1,30,30]*4+[1,30] # all the month lengths
    d[10] = r%4 < 1         # leap year toggle
    while p > d[q]:         # while the "date" > the number of days in the current month
        p -= d[q]           # decrement by number of days in current month
        q = (q+1)%18        # increment month
        r += 0**q           # increment year if the incremented month == the first month
        d[10] = r%4 < 1     # leap year toggle
    while p < 1:            # while the "date" is negative
        q = (q-1)%18        # decrement month first
        p += d[q]           # add the number of days in the decremented month
        r -= 0**q            # decrement year if the decremented month == the first month
        d[10] = r%4 < 1     # leap year toggle
    m = [t[q],str(r)]       # start the result array
    if d[q] > 2:
        m = [str(p)] + m    # if the month is NOT a holiday, add the day
    return ", ".join(m) + " DR"
Sherlock9
источник