Chinese zodiac: Difference between revisions
(→{{header|AppleScript}}: Fixed header) |
|||
Line 27: | Line 27: | ||
=={{header| |
=={{header|AppleScript}}== |
||
{{Trans|JavaScript}} |
{{Trans|JavaScript}} |
||
{{Trans|Haskell}} |
{{Trans|Haskell}} |
Revision as of 13:47, 19 February 2017
You are encouraged to solve this task according to the task description, using any language you may know.
Determine the Chinese zodiac sign and related associations for a given year.
Traditionally, the Chinese have counted years using two simultaneous cycles, one of length 10 (the "celestial stems") and one of length 12 (the "terrestrial branches"); the combination results in a repeating 60-year pattern. Mapping the branches to twelve traditional animal deities results in the well-known "Chinese zodiac", assigning each year to a given animal. For example, Saturday, January 28, 2017 CE (in the common Gregorian calendar) begins the lunisolar year of the Rooster.
The celestial stems have no one-to-one mapping like that of the branches to animals; however, the five pairs of consecutive stems each belong to one of the five traditional Chinese elements (Wood, Fire, Earth, Metal, and Water). Further, one of the two years within each element's governance is associated with yin, the other with yang.
Thus, 2017 is also the yin year of Fire. Note that since 12 is an even number, the association between animals and yin/yang doesn't change. Consecutive Years of the Rooster will cycle through the five elements, but will always be yin, despite the apparent conceptual mismatch between the male animals and the female aspect.
- Task
- Create a subroutine or program that will return or output the animal, yin/yang association, and element for the lunisolar year that begins in a given CE year.
You may optionally provide more information in the form of the year's numerical position within the 60-year cycle and/or its actual Chinese stem-branch name (in Han characters or Pinyin transliteration).
- Requisite information
- The animal cycle runs in this order: Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, Monkey, Rooster, Dog, Pig.
- The element cycle runs in this order: Wood, Fire, Earth, Metal, Water.
- The yang year precedes the yin year within each element.
- The current 60-year cycle began in 1984 CE; the first cycle of the Common Era began in 4 CE.
Thus, 1984 was the year of the Wood Rat (yang), 1985 was the year of the Wood Ox (yin), and 1986 the year of the Fire Tiger (yang); 2017 - which, as already noted, is the year of the Fire Rooster (yin) - is the 34th year of the current cycle.
- Information for optional task
- The ten celestial stems are 甲 jiă, 乙 yĭ, 丙 bĭng, 丁 dīng, 戊 wù, 己 jĭ, 庚 gēng, 辛 xīn, 壬 rén, and 癸 gŭi. With the ASCII version of Pinyin tones, the names are written "jia3", "yi3", "bing3", "ding1", "wu4", "ji3", "geng1", "xin1", "ren2", and "gui3".
- The twelve terrestrial branches are 子 zĭ, 丑 chŏu, 寅 yín, 卯 măo, 辰 chén, 巳 sì, 午 wŭ, 未 wèi, 申 shēn, 酉 yŏu, 戌 xū, 亥 hài. In ASCII Pinyin, those are "zi3", "chou3", "yin2", "mao3", "chen2", "si4", "wu3", "wei4", "shen1", "you3", "xu1", and "hai4".
Therefore 1984 was 甲子 (jiă-zĭ, or jia3-zi3). 2017 is the 34th year of the current cycle, 丁酉 (dīng-yŏu or ding1-you3).
AppleScript
<lang AppleScript>on run
-- TRADITIONAL STRINGS --------------------------------------------------- -- ts :: Array Int (String, String) -- 天干 tiangan – 10 heavenly stems set ts to zip(chars("甲乙丙丁戊己庚辛壬癸"), ¬ |words|("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")) -- ds :: Array Int (String, String) -- 地支 dizhi – 12 terrestrial branches set ds to zip(chars("子丑寅卯辰巳午未申酉戌亥"), ¬ |words|("zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài")) -- ws :: Array Int (String, String, String) -- 五行 wuxing – 5 elements set ws to zip3(chars("木火土金水"), ¬ |words|("mù huǒ tǔ jīn shuǐ"), ¬ |words|("wood fire earth metal water")) -- xs :: Array Int (String, String, String) -- 十二生肖 shengxiao – 12 symbolic animals set xs to zip3(chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬"), ¬ |words|("shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū"), ¬ |words|("rat ox tiger rabbit dragon snake horse goat monkey rooster dog pig")) -- ys :: Array Int (String, String) -- 阴阳 yinyang set ys to zip(chars("阳阴"), |words|("yáng yīn")) -- TRADITIONAL CYCLES ---------------------------------------------------- script cycle on lambda(y) set iYear to y - 4 set iStem to iYear mod 10 set iBranch to iYear mod 12 set {hStem, pStem} to item (iStem + 1) of ts set {hBranch, pBranch} to item (iBranch + 1) of ds set {hElem, pElem, eElem} to item ((iStem div 2) + 1) of ws set {hAnimal, pAnimal, eAnimal} to item (iBranch + 1) of xs set {hYinyang, pYinyang} to item ((iYear mod 2) + 1) of ys {{show(y), hStem & hBranch, hElem, hAnimal, hYinyang}, ¬ {"", pStem & pBranch, pElem, pAnimal, pYinyang}, ¬ {"", show((iYear mod 60) + 1) & "/60", eElem, eAnimal, ""}} end lambda end script -- FORMATTING ------------------------------------------------------------ -- fieldWidths :: Int set fieldWidths to {{6, 10, 7, 8, 3}, {6, 11, 8, 8, 4}, {6, 11, 8, 8, 4}} script showYear property cz : cycle script widthStringPairs on lambda(nscs) set {ns, cs} to nscs zip(ns, cs) end lambda end script script justifiedRow on lambda(row) script leftJustify on lambda(ns) set {n, s} to ns justifyLeft(n, space, s) end lambda end script concat(map(leftJustify, row)) end lambda end script on lambda(y) set cy to cycle's lambda(y) unlines(map(justifiedRow, ¬ map(widthStringPairs, ¬ zip(fieldWidths, cy)))) end lambda end script -- TEST OUTPUT ----------------------------------------------------------- intercalate("\n\n", map(showYear, {1935, 1938, 1968, 1972, 1976, 1984, 2017}))
end run
-- GENERIC FUNCTIONS
-- show :: a -> String on show(a)
a as string
end show
-- concat :: a -> [a] | [String] -> String on concat(xs)
script append on lambda(a, b) a & b end lambda end script if length of xs > 0 and class of (item 1 of xs) is string then set unit to "" else set unit to {} end if foldl(append, unit, xs)
end concat
-- foldl :: (a -> b -> a) -> a -> [b] -> a on foldl(f, startValue, xs)
tell mReturn(f) set v to startValue set lng to length of xs repeat with i from 1 to lng set v to lambda(v, item i of xs, i, xs) end repeat return v end tell
end foldl
-- intercalate :: Text -> [Text] -> Text on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText} set strJoined to lstText as text set my text item delimiters to dlm return strJoined
end intercalate
-- justifyLeft :: Int -> Char -> Text -> Text on justifyLeft(n, cFiller, strText)
if n > length of strText then text 1 thru n of (strText & replicate(n, cFiller)) else strText end if
end justifyLeft
-- map :: (a -> b) -> [a] -> [b] on map(f, xs)
tell mReturn(f) set lng to length of xs set lst to {} repeat with i from 1 to lng set end of lst to lambda(item i of xs, i, xs) end repeat return lst end tell
end map
-- minimum :: [a] -> a on minimum(xs)
script min on lambda(a, x) if x < a or a is missing value then x else a end if end lambda end script foldl(min, missing value, xs)
end minimum
-- Lift 2nd class handler function into 1st class script wrapper -- mReturn :: Handler -> Script on mReturn(f)
if class of f is script then f else script property lambda : f end script end if
end mReturn
-- replicate :: Int -> a -> [a] on replicate(n, a)
set out to {} if n < 1 then return out set dbl to {a} repeat while (n > 1) if (n mod 2) > 0 then set out to out & dbl set n to (n div 2) set dbl to (dbl & dbl) end repeat return out & dbl
end replicate
-- unlines :: [String] -> String on unlines(xs)
intercalate(linefeed, xs)
end unlines
-- words :: String -> [String] on |words|(s)
words of s
end |words|
-- chars :: String -> [String] on chars(s)
characters of s
end chars
-- zip :: [a] -> [b] -> [(a, b)] on zip(xs, ys)
script pair on lambda(x, i) [x, item i of ys] end lambda end script set intMin to minimum([length of xs, length of ys]) if intMin > 0 then map(pair, items 1 thru intMin of xs) else {} end if
end zip
-- zip3 :: [a] -> [b] -> [c] -> [(a, b, c)] on zip3(xs, ys, zs)
script on lambda(x, i) [x, item i of ys, item i of zs] end lambda end script map(result, items 1 thru ¬ minimum({length of xs, length of ys, length of zs}) of xs)
end zip3</lang>
- Output:
1935 乙亥 木 豬 阴 yĭhài mù zhū yīn 12/60 wood pig 1938 戊寅 土 虎 阳 wùyín tǔ hǔ yáng 15/60 earth tiger 1968 戊申 土 猴 阳 wùshēn tǔ hóu yáng 45/60 earth monkey 1972 壬子 水 鼠 阳 rénzĭ shuǐ shǔ yáng 49/60 water rat 1976 丙辰 火 龍 阳 bĭngchén huǒ lóng yáng 53/60 fire dragon 1984 甲子 木 鼠 阳 jiăzĭ mù shǔ yáng 1/60 wood rat 2017 丁酉 火 鸡 阴 dīngyŏu huǒ jī yīn 34/60 fire rooster
Common Lisp
<lang lisp>; Any CE Year that was the first of a 60-year cycle (defconstant base-year 1984)
(defconstant celestial-stems
'("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))
(defconstant terrestrial-branches
'("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))
(defconstant zodiac-animals
'("Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"))
(defconstant elements '("Wood" "Fire" "Earth" "Metal" "Water"))
(defconstant aspects '("yang" "yin"))
(defconstant pinyin
(pairlis (append celestial-stems terrestrial-branches) '("jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi" "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))
(defun this-year () (nth 5 (multiple-value-list (get-decoded-time))))
(defun pinyin-for (han) (cdr (assoc han pinyin :test #'string=)))
(defun chinese-zodiac (&rest years)
(loop for ce-year in (if (null years) (list (this-year)) years) collecting (let* ((cycle-year (- ce-year base-year)) (stem-number (mod cycle-year 10)) (stem-han (nth stem-number celestial-stems)) (stem-pinyin (pinyin-for stem-han))
(element-number (floor stem-number 2)) (element (nth element-number elements))
(branch-number (mod cycle-year 12)) (branch-han (nth branch-number terrestrial-branches)) (branch-pinyin (pinyin-for branch-han)) (zodiac-animal (nth branch-number zodiac-animals))
(aspect-number (mod cycle-year 2)) (aspect (nth aspect-number aspects))) (cons ce-year (list stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect)))))
(defun get-args ()
(or #+CLISP *args* #+SBCL (cdr *posix-argv*) #+LISPWORKS system:*line-arguments-list* #+CMU extensions:*command-line-words* nil))
(loop for cz in (apply #'chinese-zodiac (mapcar #'read-from-string (get-args)))
doing (format t "~{~a: ~a~a (~a-~a, ~a ~a; ~a)~%~}" cz))</lang>
- Output:
$ sbcl --script cz.cl 2017: 丁酉 (dīng-yŏu, Fire Rooster; yin) $ clisp cz.cl 193{5,8} 194{1,7} 1968 197{2,6} 1935: 乙亥 (yĭ-hài, Wood Pig; yin) 1938: 戊寅 (wù-yín, Earth Tiger; yang) 1941: 辛巳 (xīn-sì, Metal Snake; yin) 1947: 丁亥 (dīng-hài, Fire Pig; yin) 1968: 戊申 (wù-shēn, Earth Monkey; yang) 1972: 壬子 (rén-zĭ, Water Rat; yang) 1976: 丙辰 (bĭng-chén, Fire Dragon; yang)
Haskell
(We can use Chinese characters in Haskell names, as long as the first character is lower-case alphabetic) <lang haskell>import Data.Array (Array, listArray, (!))
-- TRADITIONAL STRINGS ------------------------------------------------------ ats :: Array Int (Char, String) ats =
listArray (0, 9) $ zip "甲乙丙丁戊己庚辛壬癸" -- 天干 tiangan – 10 heavenly stems (words "jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")
ads :: Array Int (String, String) ads =
listArray (0, 11) $ zip (chars "子丑寅卯辰巳午未申酉戌亥") -- 地支 dizhi – 12 terrestrial branches (words "zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài")
aws :: Array Int (String, String, String) aws =
listArray (0, 4) $ zip3 (chars "木火土金水") -- 五行 wuxing – 5 elements (words "mù huǒ tǔ jīn shuǐ") (words "wood fire earth metal water")
axs :: Array Int (String, String, String) axs =
listArray (0, 11) $ zip3 (chars "鼠牛虎兔龍蛇馬羊猴鸡狗豬") -- 十二生肖 shengxiao – 12 symbolic animals (words "shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū") (words "rat ox tiger rabbit dragon snake horse goat monkey rooster dog pig")
ays :: Array Int (String, String) ays = listArray (0, 1) $ zip (chars "阳阴") (words "yáng yīn") -- 阴阳 yinyang
chars :: String -> [String] chars = (flip (:) [] <$>)
-- TRADITIONAL CYCLES -------------------------------------------------------- f生肖五行年份 y =
let i年份 = y - 4 i天干 = rem i年份 10 i地支 = rem i年份 12 (h天干, p天干) = ats ! i天干 (h地支, p地支) = ads ! i地支 (h五行, p五行, e五行) = aws ! quot i天干 2 (h生肖, p生肖, e生肖) = axs ! i地支 (h阴阳, p阴阳) = ays ! rem i年份 2 in [ [show y, h天干 : h地支, h五行, h生肖, h阴阳] -- 汉子 Chinese characters , [[], p天干 ++ p地支, p五行, p生肖, p阴阳] -- Pinyin roman transcription , [[], show (rem i年份 60 + 1) ++ "/60", e五行, e生肖, []] -- English ]
-- FORMATTING ---------------------------------------------------------------- fieldWidths :: Int fieldWidths = [[6, 10, 7, 8, 3], [6, 11, 8, 8, 4], [6, 11, 8, 8, 4]]
showYear :: Int -> String showYear y =
unlines $ (\(ns, xs) -> concat $ uncurry (`justifyLeft` ' ') <$> zip ns xs) <$> zip fieldWidths (f生肖五行年份 y) where justifyLeft n c s = take n (s ++ replicate n c)
-- TEST OUTPUT --------------------------------------------------------------- main :: IO () main = mapM_ putStrLn $ showYear <$> [1935, 1938, 1968, 1972, 1976, 1984, 2017]</lang>
- Output:
1935 乙亥 木 豬 阴 yĭhài mù zhū yīn 12/60 wood pig 1938 戊寅 土 虎 阳 wùyín tǔ hǔ yáng 15/60 earth tiger 1968 戊申 土 猴 阳 wùshēn tǔ hóu yáng 45/60 earth monkey 1972 壬子 水 鼠 阳 rénzĭ shuǐ shǔ yáng 49/60 water rat 1976 丙辰 火 龍 阳 bĭngchén huǒ lóng yáng 53/60 fire dragon 1984 甲子 木 鼠 阳 jiăzĭ mù shǔ yáng 1/60 wood rat 2017 丁酉 火 鸡 阴 dīngyŏu huǒ jī yīn 34/60 fire rooster
JavaScript
ES6
<lang JavaScript>(() => {
'use strict';
// GENERIC FUNCTIONS -----------------------------------------------------
// zip :: [a] -> [b] -> [(a,b)] const zip = (xs, ys) => xs.slice(0, Math.min(xs.length, ys.length)) .map((x, i) => [x, ys[i]]);
// zip3 :: [a] -> [b] -> [c] -> [(a,b,c)] const zip3 = (xs, ys, zs) => xs.slice(0, Math.min(xs.length, ys.length, zs.length)) .map((x, i) => [x, ys[i], zs[i]]);
// words, chars :: String -> [String] const words = s => s.split(/\s+/); const chars = s => s.split();
// quot Num a => a -> a -> Int const quot = (m, n) => Math.floor(m / n);
// show :: // (a -> String) f, Num n => // a -> maybe f -> maybe n -> String const show = JSON.stringify;
// concat :: a -> [a] | [String] -> String const concat = xs => { if (xs.length > 0) { const unit = typeof xs[0] === 'string' ? : []; return unit.concat.apply(unit, xs); } else return []; };
// justifyLeft :: Int -> Char -> Text -> Text const justifyLeft = (n, cFiller, strText) => n > strText.length ? ( (strText + cFiller.repeat(n)) .substr(0, n) ) : strText;
// unlines :: [String] -> String const unlines = xs => xs.join('\n');
// intercalate :: String -> [a] -> String const intercalate = (s, xs) => xs.join(s);
// map :: (a -> b) -> [a] -> [b] const map = (f, xs) => xs.map(f);
// TRADITIONAL STRINGS --------------------------------------------------- // ats :: Array Int (String, String) const ats = zip( chars("甲乙丙丁戊己庚辛壬癸"), // 天干 tiangan – 10 heavenly stems words("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi") );
// ads :: Array Int (String, String) const ads = zip( chars("子丑寅卯辰巳午未申酉戌亥"), // 地支 dizhi – 12 terrestrial branches words("zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài") );
// aws :: Array Int (String, String, String) const aws = zip3( chars("木火土金水"), // 五行 wuxing – 5 elements words("mù huǒ tǔ jīn shuǐ"), words("wood fire earth metal water") );
// axs :: Array Int (String, String, String) const axs = zip3( chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬"), // 十二生肖 shengxiao – 12 symbolic animals words("shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū"), words("rat ox tiger rabbit dragon snake horse goat monkey rooster dog pig") );
// ays :: Array Int (String, String) const ays = zip( chars("阳阴"), // 阴阳 yinyang words("yáng yīn") );
// TRADITIONAL CYCLES ---------------------------------------------------- const zodiac = y => { const iYear = y - 4, iStem = iYear % 10, iBranch = iYear % 12, [hStem, pStem] = ats[iStem], [hBranch, pBranch] = ads[iBranch], [hElem, pElem, eElem] = aws[quot(iStem, 2)], [hAnimal, pAnimal, eAnimal] = axs[iBranch], [hYinyang, pYinyang] = ays[iYear % 2]; return [ [show(y), hStem + hBranch, hElem, hAnimal, hYinyang], [, pStem + pBranch, pElem, pAnimal, pYinyang], [, show((iYear % 60) + 1) + '/60', eElem, eAnimal, ] ]; };
// FORMATTING ------------------------------------------------------------ // fieldWidths :: Int const fieldWidths = [ [6, 10, 7, 8, 3], [6, 11, 8, 8, 4], [6, 11, 8, 8, 4] ];
// showYear :: Int -> String const showYear = y => unlines(map( row => concat(map(([n, s]) => justifyLeft(n, ' ', s), row)), map( ([ns, xs]) => zip(ns, xs), zip(fieldWidths, zodiac(y)) ) ));
// TEST OUTPUT ----------------------------------------------------------- return intercalate( '\n\n', map(showYear, [1935, 1938, 1968, 1972, 1976, 1984, 2017]) );
})();</lang>
- Output:
1935 乙亥 木 豬 阴 yĭhài mù zhū yīn 12/60 wood pig 1938 戊寅 土 虎 阳 wùyín tǔ hǔ yáng 15/60 earth tiger 1968 戊申 土 猴 阳 wùshēn tǔ hóu yáng 45/60 earth monkey 1972 壬子 水 鼠 阳 rénzĭ shuǐ shǔ yáng 49/60 water rat 1976 丙辰 火 龍 阳 bĭngchén huǒ lóng yáng 53/60 fire dragon 1984 甲子 木 鼠 阳 jiăzĭ mù shǔ yáng 1/60 wood rat 2017 丁酉 火 鸡 阴 dīngyŏu huǒ jī yīn 34/60 fire rooster
Perl 6
<lang perl6>sub Chinese-zodiac ( Int $year ) {
my @heaven = <甲 jiă 乙 yĭ 丙 bĭng 丁 dīng 戊 wù 己 jĭ 庚 gēng 辛 xīn 壬 rén 癸 gŭi>.pairup; my @earth = <子 zĭ 丑 chŏu 寅 yín 卯 măo 辰 chén 巳 sì 午 wŭ 未 wèi 申 shēn 酉 yŏu 戌 xū 亥 hài>.pairup; my @animal = <Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig>; my @element = <Wood Fire Earth Metal Water>; my @aspect = <yang yin>;
my $cycle_year = ($year - 4) % 60; my $i2 = $cycle_year % 2; my $i10 = $cycle_year % 10; my $i12 = $cycle_year % 12;
%( 'Han' => @heaven[$i10].key ~ @earth[$i12].key, 'pinyin' => @heaven[$i10].value ~ @earth[$i12].value, 'heaven' => @heaven[$i10], 'earth' => @earth[$i12], 'element' => @element[$i10 div 2], 'animal' => @animal[$i12], 'aspect' => @aspect[$i2], 'cycle' => $cycle_year + 1 )
}
- TESTING
printf "%d: %s (%s, %s %s; %s - year %d in the cycle)\n",
$_, .&Chinese-zodiac<Han pinyin element animal aspect cycle> for 1935, 1938, 1968, 1972, 1976, 1984, Date.today.year;</lang>
- Output:
1935: 乙亥 (yĭhài, Wood Pig; yin - year 12 in the cycle) 1938: 戊寅 (wùyín, Earth Tiger; yang - year 15 in the cycle) 1968: 戊申 (wùshēn, Earth Monkey; yang - year 45 in the cycle) 1972: 壬子 (rénzĭ, Water Rat; yang - year 49 in the cycle) 1976: 丙辰 (bĭngchén, Fire Dragon; yang - year 53 in the cycle) 1984: 甲子 (jiăzĭ, Wood Rat; yang - year 1 in the cycle) 2017: 丁酉 (dīngyŏu, Fire Rooster; yin - year 34 in the cycle)
PowerShell
<lang PowerShell> function Get-ChineseZodiac {
[CmdletBinding()] [OutputType([PSCustomObject])] Param ( [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateRange(1,9999)] [int] $Year = (Get-Date).Year )
Begin { $pinyin = @{ '甲' = 'jiă' '乙' = 'yĭ' '丙' = 'bĭng' '丁' = 'dīng' '戊' = 'wù' '己' = 'jĭ' '庚' = 'gēng' '辛' = 'xīn' '壬' = 'rén' '癸' = 'gŭi' '子' = 'zĭ' '丑' = 'chŏu' '寅' = 'yín' '卯' = 'măo' '辰' = 'chén' '巳' = 'sì' '午' = 'wŭ' '未' = 'wèi' '申' = 'shēn' '酉' = 'yŏu' '戌' = 'xū' '亥' = 'hài' }
$celestial = '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸' $terrestrial = '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥' $animals = 'Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig' $elements = 'Wood', 'Fire', 'Earth', 'Metal', 'Water' $aspects = 'yang', 'yin'
$base = 4 } Process { foreach ($ce_year in $Year) { $cycle_year = $ce_year - $base
$stem_number = $cycle_year % 10 $stem_han = $celestial[$stem_number] $stem_pinyin = $pinyin[$stem_han]
$element_number = [Math]::Floor($stem_number / 2) $element = $elements[$element_number]
$branch_number = $cycle_year % 12 $branch_han = $terrestrial[$branch_number] $branch_pinyin = $pinyin[$branch_han] $animal = $animals[$branch_number]
$aspect_number = $cycle_year % 2 $aspect = $aspects[$aspect_number]
$index = $cycle_year % 60 + 1
[PSCustomObject]@{ Year = $Year Element = $element Animal = $animal Aspect = $aspect YearOfCycle = $index ASCII = "$stem_pinyin-$branch_pinyin" Chinese = "$stem_han$branch_han" } } }
} </lang> <lang PowerShell> 1935, 1938, 1968, 1972, 1976 | Get-ChineseZodiac | Format-Table </lang>
- Output:
Year Element Animal Aspect YearOfCycle ASCII Chinese ---- ------- ------ ------ ----------- ----- ------- 1935 Wood Pig yin 12 yĭ-hài 乙亥 1938 Earth Tiger yang 15 wù-yín 戊寅 1968 Earth Monkey yang 45 wù-shēn 戊申 1972 Water Rat yang 49 rén-zĭ 壬子 1976 Fire Dragon yang 53 bĭng-chén 丙辰
Defaults to the current year: <lang PowerShell> Get-ChineseZodiac </lang>
- Output:
Year : 2017 Element : Fire Animal : Rooster Aspect : yin YearOfCycle : 34 ASCII : dīng-yŏu Chinese : 丁酉
Using the Year property of a [DateTime]
object:
<lang PowerShell>
Get-Date "11/8/2016" | Get-ChineseZodiac
</lang>
- Output:
Year : 2016 Element : Fire Animal : Monkey Aspect : yang YearOfCycle : 33 ASCII : bĭng-shēn Chinese : 丙申
Emulate the Ruby script's output: <lang PowerShell> $zodiacs = 1935, 1938, 1968, 1972, 1976 | Get-ChineseZodiac
foreach ($zodiac in $zodiacs) {
"{0}: {1} ({2}, {3} {4}; {5} - year {6} of the cycle)" -f $zodiac.Year, $zodiac.Chinese, $zodiac.ASCII, $zodiac.Element, $zodiac.Animal, $zodiac.Aspect, $zodiac.YearOfCycle
} </lang>
- Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin - year 12 of the cycle) 1938: 戊寅 (wù-yín, Earth Tiger; yang - year 15 of the cycle) 1968: 戊申 (wù-shēn, Earth Monkey; yang - year 45 of the cycle) 1972: 壬子 (rén-zĭ, Water Rat; yang - year 49 of the cycle) 1976: 丙辰 (bĭng-chén, Fire Dragon; yang - year 53 of the cycle)
Python
<lang Python>
- coding: utf-8
from __future__ import print_function from datetime import datetime
pinyin = {
'甲': 'jiă', '乙': 'yĭ', '丙': 'bĭng', '丁': 'dīng', '戊': 'wù', '己': 'jĭ', '庚': 'gēng', '辛': 'xīn', '壬': 'rén', '癸': 'gŭi',
'子': 'zĭ', '丑': 'chŏu', '寅': 'yín', '卯': 'măo', '辰': 'chén', '巳': 'sì', '午': 'wŭ', '未': 'wèi', '申': 'shēn', '酉': 'yŏu', '戌': 'xū', '亥': 'hài'
}
animals = ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake',
'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig']
elements = ['Wood', 'Fire', 'Earth', 'Metal', 'Water']
celestial = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'] terrestrial = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'] aspects = ['yang', 'yin']
def calculate(year):
BASE = 4 year = int(year) cycle_year = year - BASE stem_number = cycle_year % 10 stem_han = celestial[stem_number] stem_pinyin = pinyin[stem_han] element_number = stem_number // 2 element = elements[element_number] branch_number = cycle_year % 12 branch_han = terrestrial[branch_number] branch_pinyin = pinyin[branch_han] animal = animals[branch_number] aspect_number = cycle_year % 2 aspect = aspects[aspect_number] index = cycle_year % 60 + 1 print("{}: {}{} ({}-{}, {} {}; {} - year {} of the cycle)" .format(year, stem_han, branch_han, stem_pinyin, branch_pinyin, element, animal, aspect, index))
current_year = datetime.now().year
years = [1935, 1938, 1968, 1972, 1976, current_year]
for year in years:
calculate(year)
</lang>
Racket
<lang racket>#lang racket
(require racket/date)
- Any CE Year that was the first of a 60-year cycle
(define base-year 1984)
(define celestial-stems '("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))
(define terrestrial-branches '("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))
(define zodiac-animals
'("Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"))
(define elements '("Wood" "Fire" "Earth" "Metal" "Water"))
(define aspects '("yang" "yin"))
(define pinyin
(map cons (append celestial-stems terrestrial-branches) (list "jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi" "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))
(define (this-year) (date-year (current-date)))
(define (pinyin-for han) (cdr (assoc han pinyin)))
(define (han/pinyin-nth n hans) (let ((han (list-ref hans n))) (values han (pinyin-for han))))
(define (chinese-zodiac ce-year)
(let* ((cycle-year (- ce-year base-year)) (stem-number (modulo cycle-year (length celestial-stems))) (element-number (quotient stem-number 2)) (aspect-number (modulo cycle-year (length aspects))) (branch-number (modulo cycle-year (length terrestrial-branches))) (element (list-ref elements element-number)) (zodiac-animal (list-ref zodiac-animals branch-number)) (aspect (list-ref aspects aspect-number))) (let-values (([stem-han stem-pinyin] (han/pinyin-nth stem-number celestial-stems)) ([branch-han branch-pinyin] (han/pinyin-nth branch-number terrestrial-branches))) (list ce-year stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect))))
(module+ test
(for ((ce-year (in-list '(1935 1938 1941 1947 1968 1972 1976)))) (apply printf "~a: ~a~a (~a-~a, ~a ~a; ~a)~%" (chinese-zodiac ce-year))))</lang>
- Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin) 1938: 戊寅 (wù-yín, Earth Tiger; yang) 1941: 辛巳 (xīn-sì, Metal Snake; yin) 1947: 丁亥 (dīng-hài, Fire Pig; yin) 1968: 戊申 (wù-shēn, Earth Monkey; yang) 1972: 壬子 (rén-zĭ, Water Rat; yang) 1976: 丙辰 (bĭng-chén, Fire Dragon; yang)
Ruby
This is written as a command-line tool that takes a list of CE year numbers as arguments and outputs their information; if no arguments are supplied, it displays the information for the current year.
<lang ruby># encoding: utf-8 pinyin = {
'甲' => 'jiă', '乙' => 'yĭ', '丙' => 'bĭng', '丁' => 'dīng', '戊' => 'wù', '己' => 'jĭ', '庚' => 'gēng', '辛' => 'xīn', '壬' => 'rén', '癸' => 'gŭi',
'子' => 'zĭ', '丑' => 'chŏu', '寅' => 'yín', '卯' => 'măo', '辰' => 'chén', '巳' => 'sì', '午' => 'wŭ', '未' => 'wèi', '申' => 'shēn', '酉' => 'yŏu', '戌' => 'xū', '亥' => 'hài'
} celestial = %w(甲 乙 丙 丁 戊 己 庚 辛 壬 癸) terrestrial = %w(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥) animals = %w(Rat Ox Tiger Rabbit Dragon Snake
Horse Goat Monkey Rooster Dog Pig)
elements = %w(Wood Fire Earth Metal Water) aspects = %w(yang yin)
BASE = 4
args = if !ARGV.empty?
ARGV else [Time.new.year] end
args.each do |arg|
ce_year = Integer(arg) print "#{ce_year}: " if ARGV.length > 1 cycle_year = ce_year - BASE
stem_number = cycle_year % 10 stem_han = celestial[stem_number] stem_pinyin = pinyin[stem_han]
element_number = stem_number / 2 element = elements[element_number]
branch_number = cycle_year % 12 branch_han = terrestrial[branch_number] branch_pinyin = pinyin[branch_han] animal = animals[branch_number]
aspect_number = cycle_year % 2 aspect = aspects[aspect_number]
index = cycle_year % 60 + 1
print stem_han, branch_han puts " (#{stem_pinyin}-#{branch_pinyin}, #{element} #{animal}; #{aspect} - year #{index} of the cycle)"
end</lang>
- Output:
Given arguments 1935 1938 1968 1972 1976:
1935: 乙亥 (yĭ-hài, Wood Pig; yin - year 12 of the cycle) 1938: 戊寅 (wù-yín, Earth Tiger; yang - year 15 of the cycle) 1968: 戊申 (wù-shēn, Earth Monkey; yang - year 45 of the cycle) 1972: 壬子 (rén-zĭ, Water Rat; yang - year 49 of the cycle) 1976: 丙辰 (bĭng-chén, Fire Dragon; yang - year 53 of the cycle)
Given no arguments and run during the year 2017:
丁酉 (dīng-yŏu, Fire Rooster; yin - year 34 of the cycle)
zkl
<lang zkl>fcn ceToChineseZodiac(ce_year){ // --> list of strings
# encoding: utf-8 var [const] pinyin=SD( // create some static variables, SD is small fixed dictionary "甲","jiă", "乙","yĭ", "丙","bĭng", "丁","dīng", "戊","wù", "己","jĭ", "庚","gēng", "辛","xīn", "壬","rén", "癸","gŭi",
"子","zĭ", "丑","chŏu", "寅","yín", "卯","măo", "辰","chén", "巳","sì", "午","wŭ", "未","wèi", "申","shén","酉","yŏu", "戌","xū", "亥","hài" ),
celestial =T("甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"), terrestrial=T("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"), animals =T("Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
"Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"),
elements =T("Wood", "Fire", "Earth", "Metal", "Water"), aspects =T("yang","yin"), ;
const BASE=4; cycle_year:=ce_year - BASE;
cycle_year,aspect := ce_year - BASE, aspects[cycle_year%2]; stem_number,element := cycle_year%10, elements[stem_number/2]; stem_han,stem_pinyin := celestial[stem_number], pinyin[stem_han];
branch_number,animal := cycle_year%12, animals[branch_number]; branch_han,branch_pinyin := terrestrial[branch_number], pinyin[branch_han];
return(stem_han,branch_han,
stem_pinyin,branch_pinyin, element,animal,aspect) }</lang> <lang zkl>foreach ce_year in (T(1935,1938,1968,1972,1976,Time.Clock.UTC[0])){
println("%d: %s%s (%s-%s, %s %s; %s)" .fmt(ce_year,ceToChineseZodiac(ce_year).xplode()));
}</lang>
- Output:
1935: 乙亥 (yĭ-hài, Wood Pig; yin) 1938: 戊寅 (wù-yín, Earth Tiger; yang) 1968: 戊申 (wù-shén, Earth Monkey; yang) 1972: 壬子 (rén-zĭ, Water Rat; yang) 1976: 丙辰 (bĭng-chén, Fire Dragon; yang) 2017: 丁酉 (dīng-yŏu, Fire Rooster; yin)