158 lines
4.5 KiB
Python
158 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()
|