Рассчитать китайский знак зодиака

10

Учитывая, что наступает китайский Новый год, перед нами стоит задача расчета китайского зодиака, стихии и тайдзюду для данной даты.

На входе должна быть дата:

1/31/2014

Дата, используемая здесь, является стилем США mm/dd/yyyy, но альтернативно может быть стилем ISO-8601: yyyy-mm-ddпоэтому стиль ввода даты не является строгим.

На выходе должен быть знак животного в китайском зодиаке, включая элемент, соответствующий дате, и его аналог Taijitu :

Horse - Wood - Yang

Таблицу, показывающую отношение Зодиак - элемент - Тайцзюту можно увидеть здесь: Китайский Зодиак - Годы

Формат вывода не является строгим, но должен содержать звери, элемент и компонент Taijitu, и должен каким-то образом разделяться.

Примеры правильного вывода на вышеуказанную дату могут включать:

(horse, wood, yang)
["Horse", "Wood", "Yang"]

Ваша программа должна возвращать действительные выходные данные в течение как минимум 100 лет, включая сегодняшнюю дату. Это означает, что он должен учитывать как минимум два 60-летних ( Sexagenary ) цикла.

Эдуард Флоринеску
источник
3
У вас есть удобная ссылка на то, как рассчитать начало года зодиака?
Hand-E-Food
3
Вы не представляете, как рассчитать год зодиака, но он «кажется довольно простым». Возможно, нам следует закрыть этот вопрос и открыть его снова, когда эти мелкие детали будут проработаны?
1
Следует также отметить, что это всегда между 21 января и 21 февраля включительно.
Джастин
3
Таблица, на которую вы ссылаетесь, бесполезна, если вы не добавите ограничение, что нет необходимости давать правильный вывод для дат вне этого диапазона.
Питер Тейлор
2
Эдуард Флоринеску, две вещи, которые вы должны уточнить в этом вопросе: 1) вводить диапазон дат, как указывает @PeterTaylor, и 2) должен ли выходной формат быть точно таким, как вы указали в своем примере? Каждый персонаж имеет значение, поэтому, пожалуйста, сделайте эту цель. Спасибо.
Даррен Стоун

Ответы:

4

Mathematica 63

Хорошо, это может быть старым, но это работает (ввод данных неоднозначен во многих случаях):

z=WolframAlpha[#<>" Chinese zodiac",{{"Result",1},"Plaintext"}] &

Пример:

z@"1/31/2014"

"Лошадь (Ян Вуд)"

Ив Клетт
источник
Широта Mathematica поражает меня. Ваш формат вывода неправильный, но я уверен, что это легко исправить.
Даррен Стоун
1
@DarrenStone это несколько бесславно, потому что Mathematica просто вызывает W | A. Как вы думаете, вывод должен точно соответствовать форматированию OP?
Ив Клетт
Похоже, что другие ответы отформатированы точно так же, как и в примере вывода вопроса, и, безусловно, для этого требуется дополнительный код на любом языке. Но это действительно вопрос для @EduardFlorinescu
Даррен Стоун
@DarrenStone правда. Это, безусловно, добавит немного накладных расходов. W & C ...
Ив Клетт
4

C # - 357 337 339 байт

string Z(System.DateTime d){var c=new System.Globalization.ChineseLunisolarCalendar();var y=c.GetSexagenaryYear(d);var s=c.GetCelestialStem(y)-1;return",Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig".Split(',')[c.GetTerrestrialBranch(y)]+" - "+"Wood,Fire,Earth,Metal,Water".Split(',')[s/2]+" - Y"+(s%2>0?"in":"ang");}

отформатирован:

string Z(System.DateTime d)
{
  var c = new System.Globalization.ChineseLunisolarCalendar();
  var y = c.GetSexagenaryYear(d);
  var s = c.GetCelestialStem(y) - 1;
  return
    ",Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig".Split(',')[c.GetTerrestrialBranch(y)]
    + " - "
    + "Wood,Fire,Earth,Metal,Water".Split(',')[s / 2]
    + " - Y" + (s % 2 > 0 ? "in" : "ang");
}
Mormegil
источник
+1 Кроме того, вы можете сохранить более 20 символов, избегая string.Format.
Hand-E-Food
Да, правильно, спасибо, я попытался сыграть в гольф с различными% 2 == 0 и т. Д. И забыл большой. :-) И, собственно, это было ровно 20 символов, IIANM.
Мормегил
4

Python 2: 360 * 387 586 594 - Персонажи

Снижается дальше

m,n,p=map(int,raw_input().split("/"));p-=1924;d=int("5od2nauh6qe4obvj8rf5pd2math6re3ocvi8sf5pd2l9uh6rf3nbvi7sg5pd2k9th6rf4navj7sg5oc1m9ti7qe3navj8sg5pc1math6qd3nbvj8sf4oc1ma"[p],36);p-=31*m-31+n<(d<21)*31+d;print"Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig".split()[p%12],"Wood Fire Earth Metal Water".split()[p%10/2],["Yang","Yin"][p%2]

Приведенный выше код работает для следующего интервала: 5 февраля 1924 г. - 31 декабря 2043 г.

Пример: после вставки вышеуказанного кода в курсор интерпретатора Python

>>> m,n,p=map(int,raw_input().split("/"));p-=1924;d=int("5od2nauh6qe4obvj8rf5pd2math6re3ocvi8sf5pd2l9uh6rf3nbvi7sg5pd2k9th6rf4navj7sg5oc1m9ti7qe3navj8sg5pc1math6qd3nbvj8sf4oc1ma"[p],36);p-=31*m-31+n<(d<21)*31+d;print"Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig".split()[p%12],"Wood Fire Earth Metal Water".split()[p%10/2],["Yang","Yin"][p%2]

и затем нажмите Enter, введите дату, подобную этой

6/13/2018

и затем нажмите еще Enterраз, вывод будет

Dog Earth Yang


* уменьшено еще на 27 байт с помощью Брайана, см. комментарии.

Эдуард Флоринеску
источник
2
Вы заметили, что ваш номер базы 36 содержит «математику» дважды? :)
Тимви
1
@Timwi: D Нет, я не сделал, и это и приятно и жутко!
Эдуард Флоринеску
Эдуард, не могли бы вы объяснить часть d = int (base 36 number)? Я наткнулся на ваш ответ, проводя исследование в stackoverflow для аналогичной проблемы. Мне нужно расширить вычисления года до диапазона 1500 - 2043 года. Заранее спасибо за любую помощь.
Луис Мигель
1
Вы можете сохранить еще 23 символа с некоторыми микрооптимизациями. Смотрите reddit.com/r/Python/comments/2oqobw/…
Брайан,
1
@ Тимви 1math6и 2math6. Даже предыдущие 5 и последующие 3 отражаются между разными символами. Это 3spooky5me.
Волшебная Урна Осьминога
3

Рубин, 340

m,d,y=gets.split(?/).map(&:to_i);y+=1if 31*m+d-51>"d88jac8mlbuppp21ygmkjsnfsd4n3xsrhha4abnq9zgo6g2jupc39zav84434f75op4ftfhdcsa3xhc8nsw1ssw8p9qns1tf14mncy8j18msr9rsb7j7".to_i(36)>>5*y-9625&31
$><<[%w(Goat Monkey Rooster Dog Pig Rat Ox Tiger Rabbit Dragon Snake Horse)[y%12],%w(Metal Water Wood Fire Earth)[(y-1)/2%5],%w(Yin Yang)[y%2]]*' - '

Это будет работать для дат между 5 февраля 1924 года и 29 января 2044 года.

Даррен Стоун
источник
Какого черта это "волшебное" число?
Томсминг
1
@tomsmeding, это 600-битное целое число, закодированное в Base 36 для компактности. Разбитая на битовые поля, это таблица первого дня лунного календаря для каждого года между 1924 и 1944 годами.
Даррен Стоун,
3

GolfScript (212 символов)

Здесь используются непечатаемые символы, поэтому вот вывод из xxd:

0000000: 272d 272f 6e2a 7e5c 2833 312a 2b5c 3a5e  '-'/n*~\(31*+\:^
0000010: 3139 2a22 d4e3 275a 747f 878c 70cb 996d  19*"..'Zt...p..m
0000020: a4f9 19e9 699e d818 bb61 c4e3 2232 3536  ....i....a.."256
0000030: 6261 7365 2033 6261 7365 5e31 3932 322d  base 3base^1922-
0000040: 3c7b 282d 7d2f 3330 2532 312b 3e5e 352d  <{(-}/30%21+>^5-
0000050: 2b3a 5e31 3225 2752 6174 0a4f 780a 5469  +:^12%'Rat.Ox.Ti
0000060: 6765 720a 5261 6262 6974 0a44 7261 676f  ger.Rabbit.Drago
0000070: 6e0a 536e 616b 650a 486f 7273 650a 476f  n.Snake.Horse.Go
0000080: 6174 0a4d 6f6e 6b65 790a 526f 6f73 7465  at.Monkey.Rooste
0000090: 720a 446f 670a 5069 6727 6e2f 3d6e 5e32  r.Dog.Pig'n/=n^2
00000a0: 2f35 2527 576f 6f64 0a46 6972 650a 4561  /5%'Wood.Fire.Ea
00000b0: 7274 680a 4d65 7461 6c0a 5761 7465 7227  rth.Metal.Water'
00000c0: 6e2f 3d6e 5e31 2627 5961 6e67 0a59 696e  n/=n^1&'Yang.Yin
00000d0: 276e 2f3d                                'n/=

Эквивалентная программа, которая использует экранирование строк и, следовательно, немного длиннее:

'-'/n*~\(31*+\:^19*"\xD4\xE3'Zt\x87\x8Cp\xCB\x99m\xA4\xF9\x19\xE9i\x9E\xD8\x18\xBBa\xC4\xE3"256base 3base^1922-<{(-}/30%21+>^5-+:^12%'Rat
Ox
Tiger
Rabbit
Dragon
Snake
Horse
Goat
Monkey
Rooster
Dog
Pig'n/=n^2/5%'Wood
Fire
Earth
Metal
Water'n/=n^1&'Yang
Yin'n/=

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

Простой расчет есть day_of_year = 21 + (19 * year % 30). Термин ошибки в диапазоне от 0до 8более интересующего диапазона (1924 до 2044), и никогда не меняется из года в год более чем на один, так что таблица перекодировки кодируются в сбалансированном тройном и вычисляется ошибка путем суммирования условия погрешности префикс таблицы.

Питер Тейлор
источник
Хороший, самый короткий, пока Mathematica использует внешний ресурс. +1
Эдуард Флоринеску
2

C #, 630 611 604 572 570 байт, 120 лет

(добавьте ~ 2⅔ байта за дополнительный год, если вы знаете смещение)

Это хорошо для людей, рожденных с 31 января 1900 года по 24 января 2020 года, и, вероятно, потерпит крах за пределами этого диапазона. Есть ли бонусные баллы за количество лет?

string Z(DateTime date)
{
    int[] days = new int[] {  3, 22, 11,  1, 19,  7, -3, 16,  5, -6, 13,  2,
                             21,  9, -2, 17,  6, -5, 14,  4, 23, 11,  0, 19,
                              8, -3, 16,  5, -5, 13,  2, 20,  9, -2, 17,  7,
                             -4, 14,  3, 22, 11, -1, 18,  8, -3, 16,  5, -6,
                             13,  1, 20,  9, -1, 17,  6, -4, 15,  3, 21, 11,
                              0, 18,  8, -3, 16,  5, -7, 12,  2, 20,  9, -1,
                             18,  6, -5, 14,  3, 21, 10,  0, 19,  8, -3, 16,
                              5, 23, 12,  1, 20,  9, -1, 18,  7, -5, 13,  3,
                             22, 10,  0, 19,  8, -4, 15,  4, -6, 12,  1, 21,
                             10, -2, 17,  6, -5, 13,  3, 22, 11,  0, 19,  8 };
    string[] signs = "Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig".Split(',');
    string[] elements = "Metal,Water,Wood,Fire,Earth".Split(',');
    string[] polarities = new string[] { "Yang", "Yin" };
    int year = date.Year - 1900;
    int x = year - (date.DayOfYear < days[year] + 28 ? 1 : 0);
    return signs[x % 12] + " - " + elements[x / 2 % 5] + " - " + polarities[x % 2];
}

Или сжатый (с добавлением разрывов строк):

string Z(DateTime d){
int y=d.Year-1900,
x=y-(d.DayOfYear<new[]{3,22,11,1,19,7,-3,16,5,-6,13,2,21,9,-2,17,6,-5,14,4,23,11,0,19,8,-3,16,5,-5,13,2,20,9,-2,17,7,-4,14,3,22,11,-1,18,8,-3,16,5,-6,13,1,20,9,-1,17,6,-4,15,3,21,11,0,18,8,-3,16,5,-7,12,2,20,9,-1,18,6,-5,14,3,21,10,0,19,8,-3,16,5,23,12,1,20,9,-1,18,7,-5,13,3,22,10,0,19,8,-4,15,4,-6,12,1,21,10,-2,17,6,-5,13,3,22,11,0,19,8}[y]+28?1:0);
return "Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig".Split(',')[x%12]+" - "+"Metal,Water,Wood,Fire,Earth".Split(',')[x/2%5]+" - "+new[]{"Yang","Yin"}[x%2];
}

Один из приемов состоял в том, чтобы иметь происхождение таблицы смещения в 28 января. Это оказалось самым низким количеством символов.

Если случайно настаивает, что ввод является строкой, добавьте 22 символа, чтобы изменить сигнатуру метода на:

string Z(string i){

и добавьте строку:

var d=DateTime.Parse(i);

правок:

  • Поместите все строки в один массив и добавьте смещения к выходным селекторам.
  • Изменено смещение дня на 28 января.
  • string.Split()Вдохновение взято из ответа Эдуарда Флоринеску .
  • Подчеркнул все массивы. Это спасло мне только 2 персонажа. : - /
Hand-E-Food
источник
Сохраните 5 символов, изменив " - "+new[]{"Yang","Yin"}[x%2]на " - Y"+(x%2<1?"ang":"in"):)
Timwi
-1

Довольно просто с PHP, используя оператор Switch .

  • Расчет так далеко, как вы хотите ...

    <?php
    
    // input the year
    $Y = 2020;
    
    // calculate the Z sign
    switch (($Y - 4) % 12) {
      case  0: $z = 'Rat';break;
      case  1: $z = 'Ox';break;
      case  2: $z = 'Tiger';break;
      case  3: $z = 'Rabbit';break;
      case  4: $z = 'Dragon';break;
      case  5: $z = 'Snake';break;
      case  6: $z = 'Horse';break;
      case  7: $z = 'Goat';break;
      case  8: $z = 'Monkey';break;
      case  9: $z = 'Rooster'; break;
      case 10: $z = 'Dog';break;
      case 11: $z = 'Pig';break;
    }
    
    // calculate the e
    switch (($Y / 2) % 5) {
      case  0: $e = 'Metal';break;
      case  1: $e = 'Water';break;
      case  2: $e = 'Wood'; break;
      case  3: $e = 'Fire'; break;
      case  4: $e = 'Earth'; break;
    }
    
    // calculate the polarity
     switch ($Y % 2) {
        case  0: $p = 'Yang';break;
        case  1: $p = 'Yin';break;
    
    }
    
     echo '$Y is $z - $e - $p.';
    
MACboyet
источник
1
Добро пожаловать в PPCG! Мы требуем, чтобы все ответы были серьезными конкурентами , поэтому в случае код-гольфа нам требуются ответы, чтобы приложить усилия для сокращения кода. Например, однобуквенные имена переменных, удаление лишних пробелов и т. Д.
Embodiment of Ignorance,
1
Добро пожаловать в PPCG, ваш код работает только годы, а не полные даты
Эдуард Флоринеску
это правда. Это сложнее, чем я думаю ...
MACboyet
убрал пробелы и сократил уже. спасибо за информацию
MACboyet