159 lines
4.5 KiB
Python
159 lines
4.5 KiB
Python
|
|
'''Chinese zodiac'''
|
|||
|
|
|
|||
|
|
from functools import (reduce)
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
|
|||
|
|
# TRADITIONAL STRINGS -------------------------------------
|
|||
|
|
|
|||
|
|
# zodiacNames :: Dict
|
|||
|
|
def zodiacNames():
|
|||
|
|
'''天干 tiangan – 10 heavenly stems
|
|||
|
|
地支 dizhi – 12 terrestrial branches
|
|||
|
|
五行 wuxing – 5 elements
|
|||
|
|
生肖 shengxiao – 12 symbolic animals
|
|||
|
|
阴阳 yinyang - dark and light
|
|||
|
|
'''
|
|||
|
|
return dict(
|
|||
|
|
zip(
|
|||
|
|
['tian', 'di', 'wu', 'sx', 'yy'],
|
|||
|
|
map(
|
|||
|
|
lambda tpl: list(
|
|||
|
|
zip(* [tpl[0]] + list(
|
|||
|
|
map(
|
|||
|
|
lambda x: x.split(),
|
|||
|
|
tpl[1:])
|
|||
|
|
))
|
|||
|
|
),
|
|||
|
|
[
|
|||
|
|
# 天干 tiangan – 10 heavenly stems
|
|||
|
|
('甲乙丙丁戊己庚辛壬癸',
|
|||
|
|
'jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi'),
|
|||
|
|
|
|||
|
|
# 地支 dizhi – 12 terrestrial branches
|
|||
|
|
('子丑寅卯辰巳午未申酉戌亥',
|
|||
|
|
'zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài'),
|
|||
|
|
|
|||
|
|
# 五行 wuxing – 5 elements
|
|||
|
|
('木火土金水',
|
|||
|
|
'mù huǒ tǔ jīn shuǐ',
|
|||
|
|
'wood fire earth metal water'),
|
|||
|
|
|
|||
|
|
# 十二生肖 shengxiao – 12 symbolic animals
|
|||
|
|
('鼠牛虎兔龍蛇馬羊猴鸡狗豬',
|
|||
|
|
'shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū',
|
|||
|
|
'rat ox tiger rabbit dragon snake horse goat ' +
|
|||
|
|
'monkey rooster dog pig'
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# 阴阳 yinyang
|
|||
|
|
('阳阴', 'yáng yīn')
|
|||
|
|
]
|
|||
|
|
)))
|
|||
|
|
|
|||
|
|
|
|||
|
|
# zodiacYear :: Dict -> [[String]]
|
|||
|
|
def zodiacYear(dct):
|
|||
|
|
'''A string of strings containing the
|
|||
|
|
Chinese zodiac tokens for a given year.
|
|||
|
|
'''
|
|||
|
|
def tokens(y):
|
|||
|
|
iYear = y - 4
|
|||
|
|
iStem = iYear % 10
|
|||
|
|
iBranch = iYear % 12
|
|||
|
|
(hStem, pStem) = dct['tian'][iStem]
|
|||
|
|
(hBranch, pBranch) = dct['di'][iBranch]
|
|||
|
|
yy = iYear % 2
|
|||
|
|
return [
|
|||
|
|
[str(y), '', ''],
|
|||
|
|
[
|
|||
|
|
hStem + hBranch,
|
|||
|
|
pStem + pBranch,
|
|||
|
|
str((iYear % 60) + 1) + '/60'
|
|||
|
|
],
|
|||
|
|
list(dct['wu'][iStem // 2]),
|
|||
|
|
list(dct['sx'][iBranch]),
|
|||
|
|
list(dct['yy'][int(yy)]) + ['dark' if yy else 'light']
|
|||
|
|
]
|
|||
|
|
return lambda year: tokens(year)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# TEST ----------------------------------------------------
|
|||
|
|
# main :: IO ()
|
|||
|
|
def main():
|
|||
|
|
'''Writing out wiki tables displaying Chinese zodiac
|
|||
|
|
details for a given list of years.
|
|||
|
|
'''
|
|||
|
|
print('\n'.join(
|
|||
|
|
list(map(
|
|||
|
|
zodiacTable(zodiacNames()),
|
|||
|
|
[
|
|||
|
|
1935, 1938, 1949,
|
|||
|
|
1968, 1972, 1976,
|
|||
|
|
datetime.now().year
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
|
|||
|
|
# WIKI TABLES --------------------------------------------
|
|||
|
|
|
|||
|
|
# zodiacTable :: Dict -> Int -> String
|
|||
|
|
def zodiacTable(tokens):
|
|||
|
|
'''A wiki table displaying Chinese zodiac
|
|||
|
|
details for a a given year.
|
|||
|
|
'''
|
|||
|
|
return lambda y: wikiTable({
|
|||
|
|
'class': 'wikitable',
|
|||
|
|
'colwidth': '70px'
|
|||
|
|
})(transpose(zodiacYear(tokens)(y)))
|
|||
|
|
|
|||
|
|
|
|||
|
|
# wikiTable :: Dict -> [[a]] -> String
|
|||
|
|
def wikiTable(opts):
|
|||
|
|
'''List of lists rendered as a wiki table string.'''
|
|||
|
|
def colWidth():
|
|||
|
|
return 'width:' + opts['colwidth'] + '; ' if (
|
|||
|
|
'colwidth' in opts
|
|||
|
|
) else ''
|
|||
|
|
|
|||
|
|
def cellStyle():
|
|||
|
|
return opts['cell'] if 'cell' in opts else ''
|
|||
|
|
|
|||
|
|
return lambda rows: '{| ' + reduce(
|
|||
|
|
lambda a, k: (
|
|||
|
|
a + k + '="' + opts[k] + '" ' if k in opts else a
|
|||
|
|
),
|
|||
|
|
['class', 'style'],
|
|||
|
|
''
|
|||
|
|
) + '\n' + '\n|-\n'.join(
|
|||
|
|
'\n'.join(
|
|||
|
|
('|' if (0 != i and ('cell' not in opts)) else (
|
|||
|
|
'|style="' + colWidth() + cellStyle() + '"|'
|
|||
|
|
)) + (
|
|||
|
|
str(x) or ' '
|
|||
|
|
) for x in row
|
|||
|
|
) for i, row in enumerate(rows)
|
|||
|
|
) + '\n|}\n\n'
|
|||
|
|
|
|||
|
|
|
|||
|
|
# GENERIC -------------------------------------------------
|
|||
|
|
|
|||
|
|
# transpose :: Matrix a -> Matrix a
|
|||
|
|
def transpose(m):
|
|||
|
|
'''The rows and columns of the argument transposed.
|
|||
|
|
(The matrix containers and rows can be lists or tuples).'''
|
|||
|
|
if m:
|
|||
|
|
inner = type(m[0])
|
|||
|
|
z = zip(*m)
|
|||
|
|
return (type(m))(
|
|||
|
|
map(inner, z) if tuple != inner else z
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
return m
|
|||
|
|
|
|||
|
|
|
|||
|
|
# MAIN ---
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
main()
|