Calcular el signo del zodiaco chino

10

Dado que se acerca el Año Nuevo chino, aquí hay un desafío para calcular el zodiaco chino, el elemento y el Taijitu para una fecha determinada.

La entrada debe ser una fecha:

1/31/2014

La fecha utilizada aquí es el estilo de EE. UU. mm/dd/yyyy, Pero también puede ser el estilo ISO-8601: yyyy-mm-ddpor lo tanto, el estilo de entrada de fecha no es estricto.

La salida debe ser el signo animal en el zodiaco chino, incluido el elemento que corresponde a la fecha, y su contraparte Taijitu :

Horse - Wood - Yang

Una tabla que muestra el zodiaco - elemento - relación Taijitu se puede ver aquí: Zodiaco chino - Años

El formato de salida no es estricto, pero debe contener animal, elemento y componente Taijitu, y debe estar delimitado de alguna manera.

Los ejemplos de resultados válidos para la fecha anterior pueden incluir:

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

Su programa debe devolver resultados válidos para un rango de al menos 100 años, incluida la fecha de hoy. Esto significa que tendrá que tener en cuenta al menos dos ciclos de 60 años ( sexagenario ).

Eduard Florinescu
fuente
3
¿Tiene un enlace conveniente para calcular el comienzo de un año zodiacal?
Hand-E-Food
3
No tienes idea de cómo calcular el año zodaico, pero "parece bastante simple". ¿Quizás deberíamos cerrar esta pregunta por ahora y volver a abrirla cuando tenga esos pequeños detalles resueltos?
1
Otra cosa a tener en cuenta es que siempre es entre el 21 de enero y el 21 de febrero inclusive.
Justin
3
La tabla que enlace no sirve de nada a menos que agregue una restricción de que no es necesario dar la salida correcta para fechas fuera de ese rango.
Peter Taylor
2
Eduard Florinescu, dos cosas que debe aclarar en la pregunta: 1) rango de fechas de entrada como señala @PeterTaylor, y 2) ¿el formato de salida tiene que ser exactamente como se especifica en su ejemplo? Cada personaje cuenta, así que haz este objetivo. Gracias.
Darren Stone

Respuestas:

4

Mathematica 63

De acuerdo, esto puede estar envejeciendo, pero funciona (la entrada de fecha es ambigua en muchos casos):

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

Ejemplo:

z@"1/31/2014"

"Caballo (Madera Yang)"

Yves Klett
fuente
La amplitud de Mathematica me sorprende. Su formato de salida es incorrecto, pero estoy seguro de que es fácil de solucionar.
Darren Stone
1
@DarrenStone es un tanto glorioso porque Mathematica simplemente llama W | A. ¿Crees que la salida debe ajustarse exactamente al formato del OP?
Yves Klett
Parece que otras respuestas están formateadas exactamente como el resultado de ejemplo de la pregunta y ciertamente requiere un código adicional para hacerlo en cualquier idioma. Pero esa es realmente una pregunta para @EduardFlorinescu
Darren Stone
@DarrenStone cierto. Esto sin duda agregará un poco 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");}

Formateado:

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
fuente
+1 Además, puede guardar más de 20 caracteres evitando string.Format.
Hand-E-Food
Sí, claro, gracias. Intenté jugar al golf s% 2 == 0 etc. y olvidé el grande. :-) Y, en realidad, eran exactamente 20 caracteres, IIANM.
Mormegil
4

Python 2: 360 * 387 586 594 - Personajes

Reducido aún más

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]

El código anterior funciona para el siguiente intervalo: 5 de febrero de 1924 - 31 de diciembre de 2043

Ejemplo: después de pegar el código anterior en el cursor del intérprete de 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]

y luego presione Enter, ingrese una fecha como esta

6/13/2018

y luego presione Enternuevamente, la salida será

Dog Earth Yang


* reducido 27 bytes más con la ayuda de Brian ver comentarios.

Eduard Florinescu
fuente
2
¿Notó que su número base 36 contiene "matemáticas" dos veces? :)
Timwi
1
@Timwi: D No, no lo hice, ¡y eso es agradable y espeluznante!
Eduard Florinescu
Eduard, ¿podrías explicar la parte d = int (número base 36)? Encontré su respuesta investigando en stackoverflow para un problema similar. Necesito ampliar los cálculos del año al rango de años 1500 - 2043. Gracias de antemano por cualquier ayuda.
Luis Miguel
1
Puede guardar otros 23 caracteres con algunas microoptimizaciones. Ver reddit.com/r/Python/comments/2oqobw/…
Brian
1
@Timwi 1math6y 2math6. Incluso el precedente 5 y los siguientes 3 se reflejan con diferentes caracteres intermedios. Eso es 3spooky5me.
Urna de pulpo mágico
3

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

Esto funcionará para las fechas entre el 5 de febrero de 1924 y el 29 de enero de 2044.

Piedra de Darren
fuente
¿Qué demonios es ese número "mágico"?
tomsmeding
1
@tomsmeding, es un número entero de 600 bits codificado en Base 36 para compacidad. Dividido en campos de bits, es una tabla del primer día del calendario lunar de cada año entre 1924 y 1944.
Darren Stone
3

GolfScript (212 caracteres)

Esto utiliza caracteres no imprimibles, así que aquí está la salida de 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/=

Un programa equivalente que usa escapes de cadena y, por lo tanto, es un poco más largo es:

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

La parte interesante es la computación, dada la fecha, si es antes o después del Año Nuevo chino que cae en ese año gregoriano. Inspirándome en el algoritmo de cálculo de Pascua que he usado en una pregunta anterior, busqué un cálculo razonablemente simple de la fecha de Año Nuevo. Al final, elegí una fórmula simple que me lleva a la mayor parte del camino, más una tabla de búsqueda para el término de error.

El cálculo simple es day_of_year = 21 + (19 * year % 30). Los rangos de término de error de 0a 8lo largo del intervalo de interés (1924-2044), y nunca cambia de año en año por más de uno, por lo que la tabla de búsqueda se codifica en ternario equilibrado y se calcula el error sumando los términos de error de una prefijo de la tabla.

Peter Taylor
fuente
Agradable, el más corto hasta ahora, a excepción de Mathematica, uno está usando un recurso externo. +1
Eduard Florinescu
2

C #, 630 611 604 572 570 bytes, 120 años

(agregue ~ 2⅔ bytes por año adicional si conoce el desplazamiento)

Esto es bueno para las personas nacidas del 31 de enero de 1900 al 24 de enero de 2020 y es probable que se estrelle fuera de ese rango. ¿Hay puntos de bonificación por la cantidad de años cubiertos?

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

O condensado (con saltos de línea añadidos):

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

Uno de los trucos fue tener el origen de la tabla de compensación al 28 de enero. Esto demostró tener el recuento de caracteres más bajo.

Si por casualidad se insiste en que la entrada es una cadena, agregue 22 caracteres para cambiar la firma del método a:

string Z(string i){

y agrega la línea:

var d=DateTime.Parse(i);

EDICIONES:

  • Coloque todas las cadenas en una matriz y agregue compensaciones a los selectores de salida.
  • Cambió el día de compensación al 28 de enero.
  • string.Split()Inspiración tomada de la respuesta de Eduard Florinescu .
  • En línea todas las matrices. Solo me salvó 2 personajes. : - /
Hand-E-Food
fuente
Ahorre 5 caracteres cambiando " - "+new[]{"Yang","Yin"}[x%2]a " - Y"+(x%2<1?"ang":"in"):)
Timwi
-1

Bastante sencillo con PHP usando la instrucción Switch .

  • El cálculo es tan lejos como quieras ...

    <?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
fuente
1
Bienvenido a PPCG! Requerimos que todas las respuestas sean competidores serios , por lo que en el caso del código golf, requerimos respuestas para hacer un esfuerzo en acortar el código. Por ejemplo, nombres de variables de una sola letra, eliminación de espacios en blanco adicionales, etc.
Realización de la ignorancia
1
Bienvenido a PPCG, su código funciona solo por años sin fechas completas
Eduard Florinescu
eso es verdad. Es más difícil de lo que creo ...
MACboyet
eliminado los espacios y acortar la var ya. gracias por la información
MACboyet