计算十二生肖


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
您不知道如何计算Zodaic年,但它“似乎非常简单”。也许我们现在应该暂时关闭该问题,然后在解决这些小细节后重新打开它?

1
另一件事要注意的是,它总是在1月21日到2月21日之间(包括当日)。
贾斯汀

3
链接的表没有任何用处,除非您添加一个限制,即没有必要为超出该范围的日期提供正确的输出。
彼得·泰勒

2
Eduard Florinescu,您需要在问题中阐明两点:1)输入日期范围,如@PeterTaylor所指出的,以及2)输出格式是否必须与示例中指定的完全相同?每个角色都很重要,因此请实现此目标。谢谢。
达伦·斯通

Answers:


4

Mathematica 63

好的,这可能会变老,但是可以正常工作(在许多情况下,日期输入不明确):

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

例:

z@"1/31/2014"

“马(杨木)”


Mathematica的广度令我惊讶。您的输出格式不正确,但是我相信可以轻松解决。
达伦·斯通

1
@DarrenStone这有点不光彩,因为Mathematica只是称W | A。您是否认为输出必须完全符合OP的格式?
伊夫·克莱特

看起来其他答案的格式与问题的示例输出完全相同,并且肯定需要额外的代码才能以任何语言进行。但这确实是@EduardFlorinescu的问题
Darren Stone

@DarrenStone是。这无疑会增加很多开销。W&C ...
Yves Klett 2014年

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");
}

+1另外,您可以避免使用来保存20个以上的字符string.Format
Hand-E-Food

是的,对,谢谢,我尝试打高尔夫球各种s%2 == 0等,却忘了大个。:-)实际上,这恰好是20个字符,IIANM。
Mormegil 2014年

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]

上面的代码在以下间隔内起作用:1924年2月5日至2043年12月31日

示例:将以上代码粘贴到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


* 在Brian的帮助下,进一步减少了27个字节。


2
您是否注意到基数36包含两次“数学”?:)
Timwi

1
@Timwi:D不,我没有,这既不错又诡异!
Eduard Florinescu 2014年

爱德华,您能解释一下d = int(基数为36的数字)部分吗?我遇到了您的答案,对类似问题进行了stackoverflow研究。我需要将年的计算范围扩展到1500-2043年。在此先感谢您的帮助。
路易斯·米格尔

1
您还可以通过一些微优化来保存另外23个字符。参见reddit.com/r/Python/comments/2oqobw/…–
Brian

1
@Timwi 1math62math6。甚至前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]]*' - '

这将适用于1924年2月5日至2044年1月29日之间的日期。


这个“魔术”数字到底是什么?
tomsmeding

1
@tomsmeding,它是在Base 36中编码的600位整数,以实现紧凑性。碎成位域,它是每年农历的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/=

给定日期,最有趣的部分是计算该日期是在公历年的农历新年之前还是之后。从我在上一个问题中使用过的Easter计算算法的灵感中,我寻求了对新年日期的合理简单的计算。最后,我使用了一个简单的公式,该公式可以帮助我了解大部分情况,还有一个用于查找错误项的查找表。

简单的计算是day_of_year = 21 + (19 * year % 30)。误差项的范围是从08感兴趣的范围(1924年至2044年),并且每年之间的变化永远不会超过一个,因此,查找表以平衡三进制编码,并且通过将a的误差项求和来计算误差。表的前缀。


不错,到目前为止最短,但Mathematica除外,它使用的是外部资源。+1
Eduard Florinescu 2014年

2

C#,630 611 604 572 570个字节,120年

(如果知道偏移量,则每增加一年增加2个字节)

这对出生于1900年1月31日至2020年1月24日的人来说是一件好事,并且可能会崩溃。所涵盖的年数是否有奖励积分?

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

技巧之一是使偏移量表的起源为1月28日。事实证明这是最少的字符数。

如果偶然坚持认为输入是字符串,请添加22个字符以将方法签名更改为:

string Z(string i){

并添加以下行:

var d=DateTime.Parse(i);

编辑:


通过更改" - "+new[]{"Yang","Yin"}[x%2]" - Y"+(x%2<1?"ang":"in"):) 来保存5个字符
Timwi'2

-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.';
    

1
欢迎来到PPCG!我们要求所有答案都是认真的竞争者,因此对于代码高尔夫球,我们要求答案以努力缩短代码。例如,单字母变量名称,删除多余的空格等
Ignorance的体现,

1
欢迎使用PPCG,您的代码仅可用于数年而不是完整日期
Eduard Florinescu

那是真实的。这比我想象的要难……
MACboyet

删除空格并缩短var。感谢您的信息
MACboyet
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.