Calcular signo do zodíaco chinês

10

Dado que o Ano Novo Chinês está chegando, aqui está um desafio para calcular o Zodíaco Chinês, o elemento e o Taijitu para uma determinada data.

A entrada deve ser uma data:

1/31/2014

A data usada aqui é o estilo dos EUA mm/dd/yyyy, mas, alternativamente, pode ser o estilo ISO-8601: yyyy-mm-ddportanto, o estilo da entrada de data não é rigoroso.

A saída deve ser o signo do animal no zodíaco chinês, incluindo o elemento que corresponde à data e seu equivalente no Taijitu :

Horse - Wood - Yang

Uma tabela mostrando a relação Zodíaco - elemento - Taijitu pode ser vista aqui: Zodíaco Chinês - Anos

O formato de saída não é rigoroso, mas deve conter animal, elemento e componente Taijitu e deve ser delimitado de alguma maneira.

Exemplos de saída válida para a data acima podem incluir:

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

Seu programa deve retornar uma saída válida por um período de pelo menos 100 anos, incluindo a data de hoje. Isso significa que será necessário contabilizar pelo menos dois ciclos de 60 anos ( Sexagenary ).

Eduard Florinescu
fonte
3
Você tem um link conveniente para calcular o início de um ano do zodíaco?
Mão-E-Comida
3
Você não tem idéia de como calcular o ano zodaico, mas "parece bastante simples". Talvez devêssemos encerrar esta questão por enquanto e reabri-la quando tiver esses pequenos detalhes resolvidos?
11
Outro aspecto a ser observado é que é sempre entre 21 de janeiro e 21 de fevereiro, inclusive.
Justin
3
A tabela que você vincula não tem utilidade, a menos que você adicione uma restrição de que não é necessário fornecer a saída correta para datas fora desse intervalo.
Peter Taylor
2
Eduard Florinescu, duas coisas que você deve esclarecer na pergunta: 1) insira o período como @PeterTaylor aponta e 2) o formato de saída precisa ser exatamente o especificado no seu exemplo? Cada personagem conta, então faça este objetivo. Obrigado.
Darren Stone

Respostas:

4

Mathematica 63

Ok, isso pode estar ficando velho, mas funciona (a entrada de data é ambígua em muitos casos):

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

Exemplo:

z@"1/31/2014"

"Cavalo (madeira de Yang)"

Yves Klett
fonte
A amplitude do Mathematica me surpreende. Seu formato de saída está incorreto, mas tenho certeza de que é facilmente corrigido.
Darren Pedra
11
@DarrenStone é um tanto inglório porque o Mathematica simplesmente chama W | A. Você acha que a saída precisa se encaixar exatamente na formatação do OP?
precisa saber é o seguinte
Parece que outras respostas estão formatadas exatamente como o exemplo de saída da pergunta e certamente é necessário código extra para fazê-lo em qualquer idioma. Mas isso é realmente uma questão de @EduardFlorinescu
Darren Pedra
@DarrenStone true. Isso certamente adicionará um pouco de sobrecarga. W & C ...
Yves Klett
4

C # - 357 337 339 bytes

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

Formatado:

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
fonte
+1 Além disso, você pode salvar mais de 20 caracteres, evitando string.Format.
Hand-E-Food
Sim, obrigado, tentei jogar golfe nos vários% 2 == 0 etc., e esqueci o grande. :-) E, na verdade, eram exatamente 20 caracteres, IIANM.
Mormegil
4

Python 2: 360 * 387 586 594 - Personagens

Reduzido ainda mais

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]

O código acima funciona para o seguinte intervalo: 5 de fevereiro de 1924 - 31 de dezembro de 2043

Exemplo: após colar o código acima no cursor do interpretador 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]

e pressione Enter, insira uma data como esta

6/13/2018

e pressione Enternovamente, a saída será

Dog Earth Yang


* reduziu mais 27 bytes com a ajuda de Brian para ver comentários.

Eduard Florinescu
fonte
2
Você notou que o número da sua base 36 contém "matemática" duas vezes? :)
Timwi
11
@ Timwi: D Não, eu não fiz, e isso é legal e assustador!
Eduard Florinescu
Eduard, você poderia explicar a parte d = int (número da base 36)? Encontrei sua resposta fazendo pesquisas no stackoverflow para um problema semelhante. Preciso expandir os cálculos do ano para o intervalo de anos 1500 a 2043. Agradecemos antecipadamente por qualquer ajuda.
Luis Miguel
11
Você pode salvar outros 23 caracteres com algumas microoptimizações. Veja reddit.com/r/Python/comments/2oqobw/…
Brian
11
@Timwi 1math6e 2math6. Mesmo os 5 anteriores e os 3 seguintes são espelhados com caracteres diferentes entre eles. Isso é 3spooky5me.
Urna de polvo mágico
3

Ruby, 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]]*' - '

Isso funcionará para datas entre 5 de fevereiro de 1924 e 29 de janeiro de 2044.

Darren Stone
fonte
Que diabos é esse número "mágico"?
tomsmeding
11
@tomsmeding, é um número inteiro de 600 bits codificado na Base 36 para compacidade. Dividida em campos de bits, é uma tabela do primeiro dia do calendário lunar de cada ano entre 1924 e 1944.
Darren Stone
3

GolfScript (212 caracteres)

Isso usa caracteres não imprimíveis, então aqui está a saída do 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/=

Um programa equivalente que usa escape de string e, portanto, é um pouco mais longo é:

'-'/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/=

A parte interessante é a computação, dada a data, seja antes ou depois do Ano Novo Chinês, que cai naquele ano gregoriano. Inspirando-me no algoritmo de cálculo da Páscoa que usei em uma pergunta anterior, procurei um cálculo razoavelmente simples da data do Ano Novo. No final, adotei uma fórmula simples que me leva até o fim, além de uma tabela de pesquisa para o termo do erro.

O cálculo simples é day_of_year = 21 + (19 * year % 30). O termo do erro varia de 0até 8o intervalo de interesse (1924 a 2044) e nunca muda de ano para ano em mais de um, portanto, a tabela de pesquisa é codificada em ternário balanceado e o erro é calculado somando os termos de erro de um prefixo da tabela.

Peter Taylor
fonte
Bom, o mais curto até agora, exceto pelo Mathematica, que está usando um recurso externo. +1
Eduard Florinescu
2

C #, 630 611 604 572 570 bytes, 120 anos

(adicione ~ 2⅔ bytes por ano adicional, se você souber o deslocamento)

Isso é bom para as pessoas nascidas de 31 de janeiro de 1900 a 24 de janeiro de 2020 e provavelmente cairá fora desse intervalo. Existem pontos de bônus para o número de anos cobertos?

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

Ou condensado (com quebras de linha adicionais):

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

Um dos truques era ter a origem da mesa de compensação em 28 de janeiro. Isso provou ter a menor contagem de caracteres.

Se por acaso insistir que a entrada é uma sequência, adicione 22 caracteres para alterar a assinatura do método para:

string Z(string i){

e adicione a linha:

var d=DateTime.Parse(i);

EDITAR% S:

  • Coloque todas as seqüências de caracteres em uma matriz e inclua deslocamentos nos seletores de saída.
  • Alterado o deslocamento do dia para 28 de janeiro.
  • string.Split()Inspiração tirada da resposta de Eduard Florinescu .
  • Inline todas as matrizes. Isso só me salvou 2 caracteres. : - /
Mão-E-Comida
fonte
Guardar 5 caracteres, alterando " - "+new[]{"Yang","Yin"}[x%2]a " - Y"+(x%2<1?"ang":"in"):)
Timwi
-1

Bem direto com o PHP usando a instrução Switch .

  • O cálculo é o quanto você deseja ...

    <?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
fonte
11
Bem-vindo ao PPCG! Exigimos que todas as respostas sejam concorrentes sérios ; portanto, no caso do code-golf, solicitamos respostas para tentar reduzir o código. Por exemplo, nomes carta variáveis individuais, removendo espaços em branco extra, etc
Personificação da Ignorância
11
Bem-vindo ao PPCG, seu código funciona apenas para não anos datas completas
Eduard Florinescu
isso é verdade. É mais difícil do que eu penso ...
MACboyet
removeu os espaços e encurte o var já. obrigado pela informação
MACboyet 19/04/19