RosettaCodeData/Task/Chinese-zodiac/Python/chinese-zodiac-2.py

159 lines
4.5 KiB
Python
Raw Permalink Normal View History

2023-07-01 11:58:00 -04:00
'''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()