Oblicz chiński znak zodiaku

10

Biorąc pod uwagę, że nadchodzi Chiński Nowy Rok, oto wyzwanie, aby obliczyć chińskiego zodiaku, żywioł i Taijitu na określoną datę.

Dane wejściowe powinny być datą:

1/31/2014

Data użyta tutaj jest stylem amerykańskim mm/dd/yyyy, ale alternatywnie może być stylem ISO-8601: yyyy-mm-ddwięc styl wprowadzania daty nie jest ścisły.

Wyjściem powinien być znak zwierzęcy w chińskim zodiaku zawierający element odpowiadający dacie i jego odpowiednik w Taijitu :

Horse - Wood - Yang

Tabelę pokazującą związek Zodiak - element - Taijitu można zobaczyć tutaj: Zodiak Chiński - Lata

Format wyjściowy nie jest ścisły, ale powinien zawierać zwierzę, element i komponent Taijitu i powinien być określony w pewien sposób.

Przykłady prawidłowych danych wyjściowych dla powyższej daty mogą obejmować:

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

Twój program powinien zwracać prawidłowe dane wyjściowe przez okres co najmniej 100 lat, w tym dzisiejszą datę. Oznacza to, że konieczne będzie uwzględnienie co najmniej dwóch 60-letnich ( płciowych ) cykli.

Eduard Florinescu
źródło
3
Czy masz wygodny link do obliczania początku roku zodiaku?
Hand-E-Food
3
Nie masz pojęcia, jak obliczyć rok zodaic, ale „wydaje się to dość proste”. Być może powinniśmy na razie zamknąć to pytanie i otworzyć je ponownie, kiedy masz już te drobne szczegóły?
1
Należy również zauważyć, że zawsze jest to od 21 stycznia do 21 lutego włącznie.
Justin
3
Tabela, do której linkujesz, jest bezużyteczna, chyba że dodasz ograniczenie, że nie trzeba podawać poprawnych danych wyjściowych dla dat spoza tego zakresu.
Peter Taylor
2
Eduard Florinescu, dwie rzeczy, które powinieneś wyjaśnić w pytaniu: 1) wprowadź zakres dat, jak wskazuje @PeterTaylor, i 2) czy format wyjściowy musi być dokładnie taki, jak podałeś w swoim przykładzie? Każda postać się liczy, więc zrób ten cel. Dzięki.
Darren Stone

Odpowiedzi:

4

Mathematica 63

OK, może się to starzeć, ale działa (w wielu przypadkach wprowadzanie daty jest niejednoznaczne):

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

Przykład:

z@"1/31/2014"

„Koń (Yang Wood)”

Yves Klett
źródło
Zadziwia mnie szerokość Mathematiki. Twój format wyjściowy jest nieprawidłowy, ale jestem pewien, że łatwo to naprawić.
Darren Stone
1
@DarrenStone jest to trochę niechlubne, ponieważ Mathematica po prostu wywołuje W | A. Czy uważasz, że dane wyjściowe muszą dokładnie pasować do formatu OP?
Yves Klett,
Wygląda na to, że inne odpowiedzi są sformatowane dokładnie tak, jak przykładowe dane wyjściowe pytania i na pewno wymaga to dodatkowego kodu w dowolnym języku. Ale to naprawdę pytanie dla @EduardFlorinescu
Darren Stone
@DarrenStone true. To z pewnością doda sporo kosztów ogólnych. W&C ...
Yves Klett
4

C # - 357 337 339 bajtów

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

Sformatowany:

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
źródło
+1 Możesz także zapisać ponad 20 znaków, unikając string.Format.
Hand-E-Food
Tak, prawda, dziękuję. Próbowałem grać w różne s% 2 == 0 itd. I zapomniałem dużego. :-) I właściwie to było dokładnie 20 znaków, IIANM.
Mormegil
4

Python 2: 360 * 387 586 594 - Znaki

Zredukowane dalej

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]

Powyższy kod działa w następującym przedziale: 5 lutego 1924 r. - 31 grudnia 2043 r

Przykład: po wklejeniu powyższego kodu do kursora interpretera 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]

a następnie naciśnij Enter, wprowadź taką datę

6/13/2018

a następnie naciśnij Enterponownie, wyjście będzie

Dog Earth Yang


* zmniejszono dalsze 27 bajtów dzięki pomocy Briana w wyświetlaniu komentarzy.

Eduard Florinescu
źródło
2
Czy zauważyłeś, że twoja podstawowa liczba 36 zawiera „matematykę” dwa razy? :)
Timwi
1
@Timwi: D Nie, nie zrobiłem tego, i to jest zarówno miłe, jak i straszne!
Eduard Florinescu,
Eduard, czy mógłbyś wyjaśnić część d = int (liczba podstawowa 36)? Natknąłem się na twoją odpowiedź podczas badań nad przepełnieniem stosu dla podobnego problemu. Muszę rozszerzyć obliczenia na lata 1500–2043. Z góry dziękuję za wszelką pomoc.
Luis Miguel,
1
Możesz zapisać kolejne 23 znaki za pomocą mikrooptymalizacji. Zobacz reddit.com/r/Python/comments/2oqobw/…
Brian
1
@Timwi 1math6i 2math6. Nawet poprzednie 5 i następne 3 są odzwierciedlone między różnymi znakami. To 3spooky5me.
Magic Octopus Urn
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]]*' - '

Będzie to działać w dniach od 5 lutego 1924 r. Do 29 stycznia 2044 r.

Darren Stone
źródło
Co to do cholery jest ta „magiczna” liczba?
Tomsmeding
1
@tomsmeding, jest to 600-bitowa liczba całkowita zakodowana w bazie 36 dla zwięzłości. Podzielony na pola bitów, jest to tabela pierwszego dnia kalendarza księżycowego na każdy rok między 1924 a 1944 rokiem.
Darren Stone
3

GolfScript (212 znaków)

Używa znaków niedrukowalnych, więc oto wynik z 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/=

Równoważny program, który używa znaków zmiany znaczenia, a zatem jest nieco dłuższy, to:

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

Interesującą częścią jest obliczanie, biorąc pod uwagę datę, czy to przed, czy po chińskim Nowym Roku, który przypada w tym roku gregoriańskim. Czerpiąc inspirację z wielkanocnego algorytmu obliczeniowego, którego użyłem w poprzednim pytaniu, szukałem dość prostego obliczenia daty nowego roku. W końcu poszedłem z prostą formułą, która prowadzi mnie przez większość drogi, a także tabelą odnośników dla terminu błędu.

Proste obliczenie to day_of_year = 21 + (19 * year % 30). Termin błędu mieści się w przedziale od 0do 8ponad zakresu zainteresowania (1924–2044) i nigdy nie zmienia się z roku na rok o więcej niż jeden, więc tabela przeglądowa jest zakodowana w zbalansowanym trójskładniku, a błąd jest obliczany poprzez zsumowanie terminów błędu prefiks tabeli.

Peter Taylor
źródło
Fajne, najkrótsze jak dotąd, z wyjątkiem Mathematica, który korzysta z zewnętrznego źródła. +1
Eduard Florinescu,
2

C #, 630 611 604 572 570 bajtów, 120 lat

(dodaj ~ 2⅔ bajtów na dodatkowy rok, jeśli znasz przesunięcie)

Jest to dobre dla osób urodzonych od 31 stycznia 1900 r. Do 24 stycznia 2020 r. I prawdopodobnie ulegnie awarii poza tym zakresem. Czy są punkty bonusowe za liczbę lat objętych ubezpieczeniem?

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

Lub skondensowane (z dodanymi podziałami linii):

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

Jednym z trików było ustalenie pochodzenia tabeli offsetów 28 stycznia. Okazało się, że ma najmniejszą liczbę znaków.

Jeśli przypadkiem nalega, aby dane wejściowe były ciągiem, dodaj 22 znaki, aby zmienić podpis metody na:

string Z(string i){

i dodaj wiersz:

var d=DateTime.Parse(i);

EDYCJE:

  • Umieść wszystkie ciągi w jednej tablicy i dodaj przesunięcia do selektorów wyjściowych.
  • Zmieniono przesunięcie dnia na 28 stycznia.
  • string.Split()Inspiracja zaczerpnięta z odpowiedzi Eduarda Florinescu .
  • Inline wszystkie tablice. Uratowało mi to tylko 2 postacie. : - /
Hand-E-Food
źródło
Zapisz 5 znaków, zmieniając " - "+new[]{"Yang","Yin"}[x%2]na " - Y"+(x%2<1?"ang":"in"):)
Timwi
-1

Całkiem prosto z PHP za pomocą instrukcji Switch .

  • Obliczenia są tak daleko, jak chcesz ...

    <?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
źródło
1
Witamy w PPCG! Wymagamy, aby wszystkie odpowiedzi były poważnymi konkurentami , dlatego w przypadku gry w golfa wymagamy odpowiedzi, aby starać się skrócić kod. Na przykład, nazwy zmiennych jednoliterowych, usuwanie dodatkowych białych znaków itp.
Embodiment of Ignorance
1
Witamy w PPCG, Twój kod działa tylko przez lata, które nie uzupełniają dat
Eduard Florinescu 18.04.19
to prawda. To trudniejsze niż myślę…
MACboyet
usunąłem spacje i już skróciłem var. dzięki za informację
MACboyet