-
Notifications
You must be signed in to change notification settings - Fork 12.5k
/
Copy pathmain.py
192 lines (159 loc) · 7.21 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import json
import random
import time
from enum import Enum
from pathlib import Path
from typing import Callable, List, Dict
import requests
from colorama import Fore, Style
DEBUG = False
success_code = 200
request_timeout = 1000
data_path = Path(__file__).parent.parent.parent / 'Data'
year = 4800566455
# Data structure to hold coverage information
coverage = {
"try_block": False,
"except_connection_error": False,
"status_code_check": False,
"return_statement": False,
"raise_runtime_error": False
}
class Source(Enum):
"""Enum that represents switch between local and web word parsing."""
FROM_FILE = 0 # noqa: WPS115
FROM_INTERNET = 1 # noqa: WPS115
def print_wrong(text: str, print_function: Callable[[str], None]) -> None:
"""
Print styled text(red).
:parameter text: text to print.
:parameter print_function: Function that will be used to print in game.
"""
text_to_print = Style.RESET_ALL + Fore.RED + text
print_function(text_to_print)
def print_right(text: str, print_function: Callable[[str], None]) -> None:
"""
Print styled text(red).
:parameter text: text to print.
:parameter print_function: Function that will be used to print in game.
"""
print_function(Style.RESET_ALL + Fore.GREEN + text)
def parse_word_from_local(choice_function: Callable[[List[str]], str] = random.choice) -> str:
# noqa: DAR201
"""
Parse word from local file.
:parameter choice_function: Function that will be used to choice a word from file.
:returns str: string that contains the word.
:raises FileNotFoundError: file to read words not found.
"""
try:
with open(data_path / 'local_words.txt', encoding='utf8') as words_file:
return choice_function(words_file.read().split('\n'))
except FileNotFoundError:
raise FileNotFoundError('File local_words.txt was not found')
def parse_word_from_site(url: str = 'https://random-word-api.herokuapp.com/word') -> str:
"""
Parse word from website.
:param url: URL that word will be parsed from.
:return: string that contains the word.
:raises requests.exceptions.ConnectionError: no connection to the internet.
:raises RuntimeError: something went wrong with getting the word from the site.
"""
try:
response: requests.Response = requests.get(url, timeout=request_timeout)
coverage["try_block"] = True # Added line: marking the try block as reached
except requests.exceptions.ConnectionError:
coverage["except_connection_error"] = True # Added line: marking the except block as reached
raise requests.exceptions.ConnectionError('There is no connection to the internet')
if response.status_code == success_code:
coverage["status_code_check"] = True # Added line: marking the status code check as reached
coverage["return_statement"] = True # Added line: marking the return statement as reached
return json.loads(response.content.decode())[0]
coverage["raise_runtime_error"] = True # Added line: marking the raise runtime error as reached
raise RuntimeError('Something went wrong with getting the word from site')
class MainProcess(object):
"""Manages game process."""
def __init__(self, source: Enum, pr_func: Callable, in_func: Callable, ch_func: Callable) -> None:
"""
Init MainProcess object.
:parameter in_func: Function that will be used to get input in game.
:parameter source: Represents source to get word.
:parameter pr_func: Function that will be used to print in game.
:parameter ch_func: Function that will be used to choice word.
"""
self._source = source
self._answer_word = ''
self._word_string_to_show = ''
self._guess_attempts_coefficient = 2
self._print_function = pr_func
self._input_function = in_func
self._choice_function = ch_func
def get_word(self) -> str:
# noqa: DAR201
"""
Parse word(wrapper for local and web parse).
:returns str: string that contains the word.
:raises AttributeError: Not existing enum
"""
if self._source == Source.FROM_INTERNET:
return parse_word_from_site()
elif self._source == Source.FROM_FILE:
return parse_word_from_local(self._choice_function)
raise AttributeError('Non existing enum')
def user_lose(self) -> None:
"""Print text for end of game and exits."""
print_wrong(f"YOU LOST(the word was '{self._answer_word}')", self._print_function) # noqa:WPS305
def user_win(self) -> None:
"""Print text for end of game and exits."""
print_wrong(f'{self._word_string_to_show} YOU WON', self._print_function) # noqa:WPS305
def game_process(self, user_character: str) -> bool:
# noqa: DAR201
"""
Process user input.
:parameter user_character: User character.
:returns bool: state of game.
"""
if user_character in self._answer_word:
word_list_to_show = list(self._word_string_to_show)
for index, character in enumerate(self._answer_word):
if character == user_character:
word_list_to_show[index] = user_character
self._word_string_to_show = ''.join(word_list_to_show)
else:
print_wrong('There is no such character in word', self._print_function)
if self._answer_word == self._word_string_to_show:
self.user_win()
return True
return False
def start_game(self) -> None:
"""Start main process of the game."""
if time.time() > year:
print_right('this program is more then 100years age', self._print_function)
with open(data_path / 'text_images.txt', encoding='utf8') as text_images_file:
print_wrong(text_images_file.read(), self._print_function)
print_wrong('Start guessing...', self._print_function)
self._answer_word = self.get_word()
self._word_string_to_show = '_' * len(self._answer_word)
attempts_amount = int(self._guess_attempts_coefficient * len(self._answer_word))
if DEBUG:
print_right(self._answer_word, self._print_function)
for attempts in range(attempts_amount):
user_remaining_attempts = attempts_amount - attempts
print_right(f'You have {user_remaining_attempts} more attempts', self._print_function) # noqa:WPS305
print_right(f'{self._word_string_to_show} enter character to guess: ', self._print_function) # noqa:WPS305
user_character = self._input_function().lower()
if self.game_process(user_character):
break
if '_' in self._word_string_to_show:
self.user_lose()
if __name__ == '__main__':
main_process = MainProcess(Source(1), print, input, random.choice)
main_process.start_game()
# Function to print and save coverage information
def print_coverage() -> None:
with open("output.txt", "w") as f:
for statement, reached in coverage.items():
output = f"{statement}: {'Reached' if reached else 'Not Reached'}"
print(output)
f.write(output + "\n")
print_coverage()