tiramisu-cmdline-parser/examples/Hangman/example.py

178 lines
6 KiB
Python
Raw Normal View History

2018-11-29 22:10:08 +01:00
#!/usr/bin/env python3
"""Hangman example
"""
from random import choice
import unicodedata
import re
from os import unlink
from os.path import isfile
2019-04-09 07:18:05 +02:00
from tiramisu import RegexpOption, OptionDescription, Config, IntOption, UnicodeOption, BoolOption, ParamOption, Params, default_storage
from tiramisu_cmdline_parser import TiramisuCmdlineParser
2018-11-29 22:10:08 +01:00
LANG = 'fr_FR'
DICT_FILE = '/usr/share/myspell/{}.dic'.format(LANG)
WORD_REGEXP = re.compile(r'^[a-z]{7,12}$')
PROPOSALS_LEN = 27
NB_PROPOSALS = 6
def remove_accent(word):
"""remove all accent"""
word = unicodedata.normalize('NFD', word)
return word.encode('ascii', 'ignore').decode()
def get_random_word():
"""get line randomly in myspell file
"""
with open(DICT_FILE, 'r') as file_content:
word = choice(file_content.readlines()).strip()
if word.endswith('/S.'):
word = word[:-3]
if word.endswith('/X.'):
word = word[:-3]
if word.endswith('/F.'):
word = word[:-3]
if word.endswith('/a0p+') or word.endswith('/d0p+') or word.endswith('/a3p+'):
word = word[:-5]
if not WORD_REGEXP.search(remove_accent(word)):
return get_random_word()
return word
def display_uncomplete_word(word, *proposals):
"""display response with proposals
"""
if display_proposals_left(display_misses(word, *proposals)) == 0:
return word
display = ['-'] * len(word)
for idx, char in enumerate(remove_accent(word)):
if char in proposals:
display[idx] = word[idx]
return ''.join(display)
def display_misses(word, *proposals):
"""display all proposals
"""
ret = list(set(proposals) - set(list(remove_accent(word))))
if None in ret:
ret.remove(None)
ret.sort()
return ' '.join(ret)
def validate_misses(misses):
if display_proposals_left(misses) == 0:
raise ValueError('No more guest possible')
def display_proposals_left(misses):
if not misses:
return NB_PROPOSALS
return max(NB_PROPOSALS - len(misses.split(' ')), 0)
def display_proposal(word, *proposals):
if display_uncomplete_word(word, *proposals) == word:
return False
return display_proposals_left(display_misses(word, *proposals)) != 0
class ProposalOption(RegexpOption):
__slots__ = tuple()
_regexp = re.compile(r'^[a-z]$')
_display_name = 'proposal'
def main():
options = []
proposal = None
word = UnicodeOption('word',
'Word',
properties=('hidden', 'force_store_value'),
callback=get_random_word)
proposals = [ParamOption(word)]
for idx in range(PROPOSALS_LEN):
requires = [{'option': 'self',
'expected': None,
'action': 'hidden',
'inverse': True}]
if proposal is not None:
display = BoolOption('display{}'.format(idx),
'Display {}'.format(idx),
properties=('hidden',),
callback=display_proposal,
callback_params=Params(tuple(proposals)))
options.append(display)
requires.append({'option': proposal,
'expected': None,
'action': 'disabled'})
requires.append({'option': display,
'expected': False,
'action': 'disabled'})
proposal = ProposalOption('guess{}'.format(idx),
'Guess {}'.format(idx),
requires=requires,
2019-04-17 19:16:43 +02:00
properties=('positional', 'mandatory'))
2018-11-29 22:10:08 +01:00
#FIXME maximum recursion ...
#if proposals:
# proposal.impl_add_consistency('not_equal', proposals[0])
proposals.append(ParamOption(proposal, True))
options.append(proposal)
#
proposal_word = UnicodeOption('proposal_word',
'Word',
properties=('frozen',),
callback=display_uncomplete_word,
callback_params=Params(tuple(proposals)))
misses = UnicodeOption('misses',
'Misses',
properties=('frozen',),
callback=display_misses,
callback_params=Params(tuple(proposals)),
validator=validate_misses)
proposals_left = IntOption('proposals_left',
'Proposals left',
properties=('frozen',),
callback=display_proposals_left,
callback_params=Params(ParamOption(misses)))
#descr = OptionDescription('proposals',
# 'Suggesting letters',
# options)
2019-04-09 07:18:05 +02:00
default_storage.setting(engine='sqlite3')
2018-11-29 22:10:08 +01:00
config = Config(OptionDescription('root', 'root', [word, proposal_word, misses, proposals_left] + options), persistent=True, session_id='hangman')
2019-04-09 07:18:05 +02:00
config.property.read_write()
2018-11-29 22:10:08 +01:00
try:
2019-04-09 07:18:05 +02:00
parser = TiramisuCmdlineParser(config)
2019-04-17 19:16:43 +02:00
parser.parse_args(valid_mandatory=False)
2018-11-29 22:10:08 +01:00
except ValueError:
2019-04-09 07:18:05 +02:00
# if no more suggestion
2018-11-29 22:10:08 +01:00
pass
2019-04-09 07:18:05 +02:00
filename = '/tmp/tiramisu.db'
2018-11-29 22:10:08 +01:00
lost = False
for name in ['proposal_word', 'misses', 'proposals_left']:
option = config.option(name)
try:
value = option.value.get()
print('{}: {}'.format(option.option.doc(), value))
except ValueError as err:
lost = True
err.prefix = ''
print(option.option.doc(), str(err))
if isfile(filename):
unlink(filename)
if not lost and \
config.option('proposal_word').value.get() == config.forcepermissive.option('word').value.get():
print('You win')
if isfile(filename):
unlink(filename)
if __name__ == "__main__":
main()