ccpq/standalone_tui.py

240 lines
7.0 KiB
Python
Executable File

#!/usr/bin/python3
import pathlib
import argparse
import os
import random
import time
from rich.console import Console
from rich.markdown import Markdown
from rich.table import Table
from ccpq.lib_ccpq import Question, Database, Game
MSG = {
True: [
"Yes!",
"Good one!",
"Super!",
"Excellent job!"
],
False: [
"Sorry, that's wrong",
"No, that's not right",
"Damn it! That's not the right answer",
]
}
DIFFICULTY = {
"easy": "010-160",
"medium": "101-500",
"hard": "102-500",
}
LEVELS = [
"010-160",
"101-400",
"101-500",
"102-400",
"102-500",
]
class Tui(object):
def __init__(self):
self._console = Console()
self._stats = []
def ask_question(self, question):
os.system("clear")
md = Markdown("# {}".format(question.get_question()))
self._console.print(md)
md = Markdown("level: {}".format(question.get_level()))
self._console.print(md)
md = ""
for possibility in question.get_possibilities():
md += "1. {}\n".format(possibility)
md = Markdown(md)
self._console.print(md)
def prompt_for_answer(self, name):
#md = Markdown("What's your answer?")
#self._console.print(md)
answer = self._parse_input(name)
return answer
def _parse_input(self, name):
"""
"""
answers = []
results = input("\n {}, what's your answer? (only numbers, separated by a SPACE) ".format(name))
results = results.split()
for result in results:
if result.isdigit():
answers.append(result)
else:
md = Markdown("**only digits please**")
self._console.print(md)
return answers
def signal_player(self, player):
os.system("clear")
md = "# {}".format(player.name)
md = Markdown(md)
self._console.print(md)
time.sleep(2)
os.system("clear")
def show_response(self, question):
answers = question.get_right_answers()
if len(answers) == 1:
answer = answers[0]
md = Markdown("### The right answer is: {}".format(answer))
else:
md = "### The right answers are:\n"
for answer in answers:
md += "* {}\n".format(answer)
md = Markdown(md)
self._console.print(md)
def show_explanation(self, question):
md = "--- \n {} \n \n ---".format(question.get_explication())
md = Markdown(md)
self._console.print(md)
def show_success(self, success):
md = "# {}".format(random.choice(MSG[success]))
md = Markdown(md)
self._console.print(md)
def show_stats(self, stats):
md = "{}, you have {} out of {} right!\n".format(stats[0], stats[1], stats[1] + stats[2])
md = Markdown(md)
self._console.print(md)
md = "### press **enter** to get a new question, s for stats and **CTRL-C** to quit"
md = Markdown(md)
self._console.print(md)
result = input()
return result
def show_game_stats(self, players):
os.system("clear")
table = Table("Player")
table.add_column("Right")
table.add_column("Wrong")
table.add_column("Total")
for player in players:
name, right, wrong = player.get_stats()
table.add_row(str(name), str(right), str(wrong), str(right + wrong))
self._console.print(table)
md = "### press **enter** to continue"
md = Markdown(md)
self._console.print(md)
input()
def goodbye(self):
md = Markdown("# Goodbye!")
self._console.print(md)
class Application(object):
def __init__(self, filepath_csv, filepath_players, interface, number, level):
self._db = Database(filepath_csv, level)
self._session = Game(filepath_players)
self._number = number * len(self._session.get_all_players())
self._interface = interface
def start(self):
pass
def run(self):
while self._number > 0:
player = self._session.get_random_player()
if len(self._session.get_all_players()) > 1:
self._interface.signal_player(player)
question = self._db.get_question()
self._interface.ask_question(question)
answer = self._interface.prompt_for_answer(player)
stat = question.verify(answer)
player.stats.update_stats(stat)
self._interface.show_success(stat)
self._interface.show_response(question)
self._interface.show_explanation(question)
result = self._interface.show_stats(player.get_stats())
if result.startswith("s"):
players = self._session.get_all_players()
self._interface.show_game_stats(players)
self._number -= 1
self.quit()
def quit(self):
players = self._session.get_all_players()
self._interface.show_game_stats(players)
self._interface.goodbye()
def level_logic(level, difficulty):
if level is None and difficulty is None:
level = "lpic1_part1"
elif level is not None:
# level = LEVELS[0:LEVELS.index(DIFFICULTY[level]) + 1]
level = (level)
elif difficulty is not None:
level = LEVELS[0:LEVELS.index(DIFFICULTY[difficulty]) + 1]
return level
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-f",
"--file",
required=False,
default="data",
help="path to specific CSV file or directory",
action="store"
)
parser.add_argument(
"-p",
"--players",
required=False,
default="",
help="file with list of players",
action="store"
)
parser.add_argument(
"-n",
"--number",
default=20,
help="number of questions to ask",
type=int,
action="store"
)
group_level = parser.add_mutually_exclusive_group()
group_level.add_argument(
"-d",
"--difficulty",
choices=DIFFICULTY.keys(),
help="easy, medium or hard"
)
group_level.add_argument(
"-l",
"--level",
choices=LEVELS,
help="LPI level to test"
)
args = parser.parse_args()
filepath_csv = pathlib.Path(args.file)
filepath_players = pathlib.Path(args.players)
if not filepath_csv.exists():
print("no such file or directory!")
exit(1)
level = level_logic(args.level, args.difficulty)
interface = Tui()
app = Application(filepath_csv, filepath_players, interface, args.number, level)
try:
app.run()
except KeyboardInterrupt:
app.quit()