Last active
December 14, 2021 20:33
-
-
Save TheArcherST/84eca0ac91a889fb3d3c86dc2eb1faa5 to your computer and use it in GitHub Desktop.
Code to estimate your test results
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This program helps you to evaluate you test results | |
```input.md | |
1. . | |
2. ? | |
3. | |
4. | |
5. ? | |
``` | |
Here i said that i totally know answer on first question, | |
don't know answers on 2 and 5, and know possible answer | |
on 3 and 4. | |
You can change constatnts in following vars and classes | |
Without script, you can approximately estimate it: | |
`Count of unknown` / `Answers in question` / `Total questions` | |
""" | |
import abc | |
import typing | |
from dataclasses import dataclass | |
from tabulate import tabulate | |
# ====== CONSTATNTS ======== | |
FILE_NAME = 'input.md' | |
ANSWERS_IN_QUESTION = 4 | |
class StatusEstimates: | |
MAYBE = 0.6 | |
RIGHT = 0.9 | |
RANDOM = 1 / ANSWERS_IN_QUESTION | |
class TokenType: | |
NUMBER = 'NUMBER' | |
DOT = 'DOT' | |
EOF = 'EOF' | |
STATUS = 'STATUS' | |
# ========================== | |
@dataclass | |
class Token: | |
type: str | |
value: str | |
class Lexer: | |
def __init__(self, text: str): | |
self.text = text | |
def iterator(self): | |
text = self.normalize_text(self.text) | |
for i in text.split(' '): | |
yield self._token_factory(i) | |
@staticmethod | |
def normalize_text(text: str): | |
def unplug(literals: list[str], text_: str): | |
for literal in literals: | |
text_ = text_.replace(literal, f' {literal} ') | |
return text_ | |
# if operators concatenated to id, will be unplugged | |
# but can be generated double spaces | |
text = unplug(['.', '?'], text) | |
# rm all double spaces | |
while text.find(' ') != -1: | |
text = text.replace(' ', ' ') | |
return text | |
@staticmethod | |
def _token_factory(literal: str): | |
if literal == '.': | |
type_ = TokenType.DOT | |
elif literal.isnumeric(): | |
type_ = TokenType.NUMBER | |
elif literal in ('?',): | |
type_ = TokenType.STATUS | |
elif literal == '': | |
type_ = TokenType.EOF | |
else: | |
raise KeyError(f"Unknown token: `{literal}`") | |
return Token(type_, literal) | |
class BaseInterpreter: | |
def __init__(self, text: str): | |
self.tokens_iterator = Lexer(text).iterator() | |
self.current_token = Token(TokenType.EOF, '') | |
self.previous_token = Token(TokenType.EOF, '') | |
self._next_token() | |
def _next_token(self): | |
self.previous_token = self.current_token | |
try: | |
self.current_token = self.tokens_iterator.__next__() | |
except StopIteration: | |
self.current_token = Token(TokenType.EOF, '') | |
return self.current_token | |
def eat(self, *token_types: str): | |
if self.check(*token_types): | |
self._next_token() | |
return self.previous_token | |
else: | |
raise SyntaxError(f'excepted token(-s): {token_types}, but `{self.current_token}` got') | |
def check(self, *token_types: str) -> bool: | |
return self.current_token.type in token_types | |
@abc.abstractmethod | |
def expr(self): | |
pass | |
@dataclass | |
class ExprResult: | |
question_number: int | |
literal: str | |
value: float | |
class Interpreter(BaseInterpreter): | |
def expr(self) -> ExprResult: | |
if self.current_token.type == TokenType.NUMBER: | |
question_number = int(self.eat(TokenType.NUMBER).value) | |
self.eat(TokenType.DOT) | |
status = self.current_token.value | |
self.eat(TokenType.EOF, TokenType.DOT, TokenType.STATUS) | |
lib = { | |
'': StatusEstimates.MAYBE, | |
'.': StatusEstimates.RIGHT, | |
'?': StatusEstimates.RANDOM | |
} | |
try: | |
result = lib[status] | |
except KeyError: | |
raise RuntimeError('Interpreter: unknown status, please, check lexer.') | |
return ExprResult(question_number, status, result) | |
def run(text: str) -> list[ExprResult]: | |
results = [] | |
lines = text.split('\n') | |
for i in lines: | |
interpreter = Interpreter(i) | |
res = interpreter.expr() | |
results.append(res) | |
return results | |
def get_comment(assumed_value: float): | |
if assumed_value < 40: | |
result = "You will don't pass it. Try to resolve most bad-answered questions" | |
elif assumed_value < 50: | |
result = 'Bad. Try to resolve most bad-answered questions' | |
elif assumed_value < 60: | |
result = 'I think you pass it, but try resolve more questions' | |
elif assumed_value < 70: | |
result = 'Good! But not great. Try resolve more questions' | |
elif assumed_value < 90: | |
result = 'Great! You can finish work. Really good.' | |
elif assumed_value < 96: | |
result = 'Just awesome!' | |
else: | |
raise ValueError(f"Can't estimate assumed_value `{assumed_value}`") | |
return result | |
def main(): | |
with open(FILE_NAME) as fs: | |
text = fs.read() | |
results = run(text) | |
percentage = sum([i.value for i in results]) / len(results) * 100 | |
random_answers = filter(lambda x: x.literal == '?', results) | |
maybe_answers = filter(lambda x: x.literal == '', results) | |
def to_q_numbers(results__: typing.Iterable[ExprResult]) -> list[int]: | |
result = [] | |
for i in results__: | |
result.append(i.question_number) | |
return result | |
random_answers = to_q_numbers(random_answers) | |
maybe_answers = to_q_numbers(maybe_answers) | |
print(f'Assumed value: {round(percentage, 2)}%\n') | |
print(get_comment(percentage)) | |
print() | |
print(tabulate(zip(random_answers, maybe_answers), | |
('random', 'maybe'))) | |
print() | |
print('That answers on what you can think') | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment