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


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

Правила

  • Це кодовий гольф, тому виграє найменша кількість байтів.
  • Стандартні лазівки явно не допускаються.
  • Припустимо , що тиждень починається з понеділка (спасибі Angs і Arnauld за пропозицією).
  • Розглянемо лише роки між 1900 та 2100 ( включно ).
  • Правила форматування введення та виведення є дозволеними , тобто ви можете використовувати будь-який еквівалентний формат, який є власною мовою, яку ви обрали.
  • Обґрунтуйте своє рішення на григоріанському календарі .

7
Вважайте, що дати дивні , ви можете точно вказати правила або обмежити можливий вхід невеликим діапазоном (скажімо, 1901-2099)
user202729

2
Що слід уникати під час написання викликів / Додавання непотрібних матеріалів включає в себе "Складання відповідей, обчислених f(x)для кожного xзі списку. А як щодо "приймати дані у формі дати"?
користувач202729

6
Ласкаво просимо до PPCG та приємного першого виклику! Незважаючи на те, що це завдання добре, у майбутньому, якщо ви хочете отримати зворотній зв'язок щодо виклику перед публікацією, ви можете опублікувати його в пісочниці .
користувач202729

2
Чи слід виводити строго згадані рядки або будь-які 3 різних значення?
Уріель

2
(зачекайте хвилинку, григоріанський календар чи юліанський календар? Я запропонував [1901-2099], але ви вирішите використовувати [1900-2100], щоб вони були різними для деяких входів)
user202729

Відповіді:


20

JavaScript (ES6), 55 байт

Збережено 6 байт завдяки @Neil

Здійснює введення в синтаксис currying (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

Спробуйте в Інтернеті!


Я подумав, що це було true, falseа filenotfoundзамість 0
Angs

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

Безголівки:

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

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 для асиметричного


@TuukkaX Вибачте за плутанину - це мій перший виклик, я змінив правила, щоб вони також дозволяли дозвільні формати виводу, щоб він міг бути більш «по духу» коду-гольфу.
mkierc

5

Python 2, 118 104 байт

Дякуємо Джонатану Аллану та Dead Possum за покращення!

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()однак це буде абсолютно добре.
caird coinheringaahing

1
@cairdcoinheringaahing Дякую за привіт! Фіксований користувальницький вклад :)
Джек всіх піків

Ласкаво просимо! Твіки для -9 байт тут - все імпорт, розпакований вхід, _[0]+_[-1]->sum(..)
Dead Опосум

1
Деякі хитрощі , щоб отримати його 13 байт тут
Jonathan Allan

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

Математика, 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за повністю симетричні місяці. Не впевнений, чому ця мова не може конвертувати з будня в число за замовчуванням ...


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-місяць потрібно буде перемістити на 2, щоб все-таки збігатися (місяць починається на наступний день, але його потрібно закінчити на день раніше ), тому 2 * .day-of-week + .days-in-monthдає нам міру цього розриву. У модулі 7 це повинно бути 1, щоб отримати симетрію, але ми можемо спочатку дешево перевірити неприскорений лютий, перевіривши цю загальну суму перед модулем (понеділок та 28 днів на місяць - це мінімально можлива комбінація).

Я здивований, що для цього потрібно стільки байтів, але повністю потрібно 36 байтів, щоб просто зробити дату і отримати день тижня та дні в цьому місяці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.