Симметрия месяцев

32

Введение

Некоторые месяцы полностью симметричны , то есть они имеют центральную симметрию, а также симметрию отражения , например February of 2010:

     February 2010
┌──┬──┬──┬──┬──┬──┬──┐ 
│  │  │  │  │  │  │  │ 
├──┼──┼──┼──┼──┼──┼──┤ 
│  │  │  │  │  │  │  │ 
├──┼──┼──┼──┼──┼──┼──┤ 
│  │  │  │  │  │  │  │ 
├──┼──┼──┼──┼──┼──┼──┤ 
│  │  │  │  │  │  │  │ 
└──┴──┴──┴──┴──┴──┴──┘ 

Некоторые месяцы имеют только центральную симметрию, например, February of 1996или текущий месяц April of 2018:

      February 1996
          ┌──┬──┬──┬──┐
          │  │  │  │  │
 ┌──┬──┬──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┴──┴──┘
 │  │  │  │  │
 └──┴──┴──┴──┘

       April 2018  ┌──┐
                   │  │
 ┌──┬──┬──┬──┬──┬──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┼──┼──┼──┼──┼──┤
 │  │  │  │  │  │  │  │
 ├──┼──┴──┴──┴──┴──┴──┘
 │  │
 └──┘

А некоторые асимметричны , как и в предыдущем месяце March of 2018:

      March 2018
         ┌──┬──┬──┬──┐
         │  │  │  │  │
┌──┬──┬──┼──┼──┼──┼──┤
│  │  │  │  │  │  │  │
├──┼──┼──┼──┼──┼──┼──┤
│  │  │  │  │  │  │  │
├──┼──┼──┼──┼──┼──┼──┤
│  │  │  │  │  │  │  │
├──┼──┼──┼──┼──┼──┼──┘
│  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┘

задача

Примите данные в виде даты , например:

  • 2018.04
  • 2018.03
  • 2010.02
  • 1996.02

Выведите соответствующую симметрию , например

  • 2018.04 -> centrally symmetric
  • 2018.03 -> asymmetric
  • 2010.02 -> symmetric
  • 1996.02 -> centrally symmetric

правила

  • Это код гольф, поэтому выигрывает наименьшее количество байтов.
  • Стандартные лазейки явно не допускаются.
  • Предположим, что неделя начинается с понедельника (спасибо Ангсу и Арно за предложение).
  • Рассмотрим только годы между 1900 и 2100 ( включительно ).
  • Правила форматирования ввода и вывода являются разрешающими , то есть вы можете использовать любой эквивалентный формат, который является родным для языка по вашему выбору.
  • Основывайте свое решение на григорианском календаре .
mkierc
источник
7
Считайте, что даты странные , вы можете указать точно правила или ограничить возможный ввод небольшим диапазоном (скажем, 1901-2099)
user202729
2
Вещи, которые следует избегать при написании задач / Добавление ненужных вещей включает в себя «Создание ответов подсчитать f(x)для каждого xв списке». А как насчет "принять данные в виде даты"?
user202729
6
Добро пожаловать в PPCG и приятного первого испытания! Несмотря на то, что этот тест хорош, в будущем, если вы хотите получить отзыв о тесте перед публикацией, вы можете опубликовать его в песочнице .
user202729
2
Должен ли вывод быть строго упомянутыми строками или какими-то 3 различными значениями?
Уриэль
2
(подождите минуту, григорианский календарь или юлианский календарь? Я предложил [1901-2099], но вы решили использовать [1900-2100], чтобы они отличались для некоторых входных данных)
user202729

Ответы:

20

JavaScript (ES6), 55 байт

Сохранено 6 байтов благодаря @Neil

Принимает ввод в синтаксисе карри (year)(month). Возвращает falseдля асимметричного, trueдля центрально-симметричного и 0полностью симметричного.

y=>m=>(n=(g=_=>new Date(y,m--,7).getDay())()+g())&&n==7

Попробуйте онлайн!

Как?

Мы определяем функцию g (), которая возвращает день недели yyyy / mm / 01 как целое число от 0 = понедельник до 6 = воскресенье.

g = _ => new Date(y, m--, 7).getDay()

Поскольку getDay () изначально возвращает 0 = воскресенье на 6 = суббота, мы смещаем результат в ожидаемый диапазон, запрашивая вместо этого 7-й день.

Затем мы определяем:

n = g() + g()

Поскольку конструктор Date ожидает месяц с индексом 0 и поскольку g () уменьшает m после передачи его в Date , мы фактически сначала вычисляем день недели первого дня следующего месяца, а затем добавляем день недели текущего.

Полностью симметричные месяцы

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

- Feb --------------    - Mar --------------
Mo Tu We Th Fr Sa Su    Mo Tu We Th Fr Sa Su
--------------------    --------------------
01 02 03 04 05 06 07    01 02 03 04 05 06 07
08 09 10 11 12 13 14    08 09 10 11 12 13 14
15 16 17 18 19 20 21    15 16 17 18 19 20 21
22 23 24 25 26 27 28    22 23 24 25 26 27 28
                        29 30 31

Это приводит к n = 0 .

Центрально-симметричные месяцы

Центрально-симметричные месяцы - это месяцы, для которых сумма дня недели их первого дня и дня следующего месяца равна 7 .

- M ----------------    - M+1 --------------
Mo Tu We Th Fr Sa Su    Mo Tu We Th Fr Sa Su
--------------------    --------------------
 0  1 [2] 3  4  5  6     0  1  2  3  4 [5] 6
--------------------    --------------------
      01 02 03 04 05                   01 02
06 07 08 09 10 11 12    03 04 05 06 07 07 09
13 14 15 16 17 18 19    ...
20 21 22 23 24 25 26
27 28 29 30 31

Отсюда второй тест: n == 7 .


Нет встроенного, 93 байта

Использует конгруэнтность Целлера . Тот же формат ввода / вывода, что и в другой версии.

y=>m=>(n=(g=_=>(Y=y,((m+(m++>2||Y--&&13))*2.6|0)+Y+(Y>>2)-6*~(Y/=100)+(Y>>2))%7)()+g())&&n==7

Попробуйте онлайн!

Arnauld
источник
Я думал, что это было true, falseи filenotfoundвместо 0...
Анг
g=m=>new Date(y,m,7).getDay()экономит 6 байт.
Нейл
7

T-SQL , 213 байт (строгие правила ввода / вывода)

SET DATEFIRST 1SELECT CASE WHEN a+b<>8THEN'a'WHEN a=1THEN''ELSE'centrally 'END+'symetric'FROM(SELECT DATEPART(DW,f)a,DATEPART(DW,DATEADD(M,1,f)-1)b FROM (SELECT CONVERT(DATETIME,REPLACE(s,'.','')+'01')f FROM t)y)x

Приведенный выше запрос учитывает строгие правила форматирования ввода / вывода.

Входные данные взяты из столбца sтаблицы с именем t:

CREATE TABLE t (s CHAR(7))
INSERT INTO t VALUES ('2018.04'),('2018.03'),('2010.02'),('1996.02')

Ungolfed:

SET DATEFIRST 1
SELECT *, CASE WHEN a+b<>8 THEN 'a' WHEN a=1 AND b=7 THEN '' ELSE 'centrally ' END+'symetric'
FROM (
    SELECT *,DATEPART(WEEKDAY,f) a, 
        DATEPART(WEEKDAY,DATEADD(MONTH,1,f)-1) b 
    FROM (SELECT *,CONVERT(DATETIME,REPLACE(s,'.','')+'01')f FROM t)y
) x

SQLFiddle 1

T-SQL , 128 байт (разрешающие правила ввода-вывода)

SET DATEFIRST 1SELECT CASE WHEN a+b<>8THEN 1WHEN a=1THEN\END FROM(SELECT DATEPART(DW,d)a,DATEPART(DW,DATEADD(M,1,d)-1)b FROM t)x

Если формат ввода и вывода можно изменить, я бы выбрал ввод первого дня месяца в datetimeстолбце с именем d:

CREATE TABLE t (d DATETIME)
INSERT INTO t VALUES ('20180401'),('20180301'),('20100201'),('19960201')

Выход будет 1 для асимметричного, 0 для симметричного, NULL для центрально-симметричного.

Если мы сможем запустить его на сервере (или с именем входа), настроенном на британский язык, мы сможем удалить SET DATEFIRST 1сохранение еще 15 байтов.

SQLFiddle 2

Разван Соколь
источник
1
Хорошо сделано. Не уверен, что он будет работать во всех версиях, но в SQL 2012 я смог сэкономить 15 байтов, используя CONVERT(DATETIME,s+'.01')вместо REPLACE. Вы также можете FROM (SELECT
оставить
1
Это работает, но это зависит от DATEFORMATнастроек. Например, если мы используем SET LANGUAGE BRITISH, то CONVERT(DATETIME,'2018.02.01')будет 2 января, а не 1 февраля.
Разван Соколь
5

Haskell, 170 байт

import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
a%b=((\(_,_,a)->a).toWeekDate.fromGregorian a b$1)!gregorianMonthLength a b
1!28=2
4!29=1
7!30=1
3!31=1
_!_=0

Возвращает 2 для центрально-симметричного, 1 для симметричного и 0 для асимметричного

Angs
источник
@TuukkaX Извините за путаницу - это мой первый вызов, я изменил правила, чтобы они также допускали разрешающие форматы вывода, чтобы это могло быть больше "в духе" кода-гольфа.
mkierc
5

Python 2, 118 104 байта

Спасибо Джонатану Аллану и Мертвому Опоссуму за улучшения!

from calendar import*
def f(*d):_=monthcalendar(*d);print all(sum(_,[]))+(_[0].count(0)==_[-1].count(0))

Python 3, 122 105 байт

from calendar import*
def f(*d):_=monthcalendar(*d);print(all(sum(_,[]))+(_[0].count(0)==_[-1].count(0)))

вход

  • Первый год
  • Второй месяц


Выход

  • 0 = нет симметрии
  • 1 = центральная симметрия
  • 2 = полная симметрия
Валет Пики
источник
3
Добро пожаловать на сайт! Вы не можете предполагать, что входные данные хранятся в переменной (например, Yили M), поэтому в настоящее время это фрагмент и недопустимый. Однако если вы измените переменные на вызовы input(), это будет совершенно нормально.
Кэрд coinheringaahing
1
@cairdcoinheringaahing Спасибо за прием! Исправлен пользовательский ввод :)
Jack of all Spades
Добро пожаловать! Твики для -9 байт здесь - все импорт, распакованный ввод, _[0]+_[-1]->sum(..)
Мертвый Опоссум
1
Некоторые хитрости, чтобы получить 13 байтов здесь
Джонатан Аллан
1
... и еще один байт, использующий трюк с суммой Мертвого Опоссума - здесь
Джонатан Аллан
4

Красный , 199, 168 161 байт

func[d][t: split d"."y: do t/1 m: do t/2 a: to-date[1 m y]b: a + 31
b/day: 1 b: b - 1 if(1 = s: a/weekday)and(7 = e: b/weekday)[return 1]if 8 - e = s[return 2]0]

Попробуйте онлайн!

0 - асимметричный

1 - симметричный

2 - центрально-симметричный

Более читабельно:

f: func[d][                  ; Takes the input as a string
    t: split d "."           ; splits the string at '.'
    y: do t/1                ; stores the year in y 
    m: do t/2                ; stores the month in m
    a: to-date[1 m y]        ; set date a to the first day of the month
    b: a + 31                ; set date b in the next month  
    b/day: 1                 ; and set the day to 1st
    b: b - 1                 ; find the end day of the month starting on a
    s: a/weekday             ; find the day of the week of a 
    e: b/weekday             ; find the day of the week of b
    if(s = 1) and (e = 7)    ; if the month starts at Monday and ends on Sunday
        [return 1]           ; return 1 fo symmetric
    if 8 - e = s             ; if the month starts and ends on the same day of the week
        [return 2]           ; return 2 for centrally symmetric  
    0                        ; else return 0 for assymetric
]
Гален Иванов
источник
2

Mathematica, 137 байт

a=#~DateValue~"DayName"&;b=a/@{2}~DateRange~{3};Which[{##}=={0,6},1,+##>5,0,1>0,-1]&@@(Position[b,a@#][[1,1]]~Mod~7&)/@{{##},{#,#2+1,0}}&

Чистая функция. Принимает год и месяц в качестве входных данных и возвращает -1асимметричные месяцы, 0центрально-симметричные месяцы и 1полностью симметричные месяцы. Не уверен, почему этот язык не может конвертировать из дня недели в число по умолчанию ...

LegionMammal978
источник
2

Утилиты Bash + GNU, 70

date -f- +%u<<<"$1/1+1month-1day
$1/1"|dc -e??sad8*la-55-rla+8-d*64*+p

Ввод отформатирован как YYYY/MM.

Вывод числовой:

  • меньше 0: центрально-симметричный
  • точно 0: симметричный
  • больше 0: асимметричный

Я предполагаю, что этот формат вывода является приемлемым для этого вопроса.

Попробуйте онлайн!

Цифровая травма
источник
1

C 111 байтов

a;g(y,m){y-=a=m<3;return(y/100*21/4+y%100*5/4+(13*m+16*a+8)/5)%7;}f(y,m){a=g(y,m)+g(y,m+1);return(a>0)+(a==7);}

Вызвать f(year, month), 0 для полностью симметричного, 1 для асимметричного, 2 для центрально-симметричного.

ТТГ
источник
IIRC вы можете злоупотреблять UB на GCC, заменив returnс y=(первым параметром) и выпадением функции.
Квентин,
1

Perl 6 , 74 байта

{{{$_==30??2!!$_%7==2}(2*.day-of-week+.days-in-month)}(Date.new("$_-01"))}

Голый блок, неявно функция с 1 аргументом, строка типа "2012-02". Возвращает:

2     # Fully symmetric
True  # Centrally symmetric
False # Asymmetric

Когда шаблон симметричен, так как .day-of-week увеличивается на 1, .days-in-month нужно будет сдвинуть на 2, чтобы все еще совпадать (месяц должен начинаться днем ​​позже, но должен заканчиваться днем ​​ранее ), поэтому 2 * .day-of-week + .days-in-monthдает нам меру этого разрыва. По модулю 7 это должно быть 1, чтобы получить симметрию, но мы можем сначала дешево проверить на отсутствие високосного февраля, проверив это общее количество перед модулем (понедельник и 28 дней в месяц - минимально возможная комбинация).

Я удивлен, что это занимает так много байтов, но для создания даты и получения дня недели и дней в этом месяце необходимо 36 байтов.

Фил Х
источник