-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.py
203 lines (159 loc) · 7.22 KB
/
game.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
193
194
195
196
197
198
199
200
201
202
203
from ui import UI
from cpu_ia import CPU
from board import TicTacToeBoard
from input import CustomInput, number_to_grid
from os import system
from time import sleep
class TicTacToeGame():
def __init__(self, board:type[TicTacToeBoard], user_interface:type[UI], cpu:type[CPU]) -> None:
self.board = board
self.ui = user_interface
self.cpu = cpu
self.ci = CustomInput()
self.player1 = {'player': 'player_1', 'symbol': 'x'}
self.player2 = {'player': 'undefined', 'symbol': 'o'}
self.score = None
self.cpu.board = board
def main_menu(self) -> None:
"""Initiates game configs."""
while True:
# chosse main menu options
system("cls")
menu_option = self.ci.pick_option(self.ui.main_menu_options(), self.ui.main_menu_command())
if menu_option == 1: # Play option
# Choose opponent
system("cls")
opponent_option = self.ci.pick_option(self.ui.opponent_options(), self.ui.opponent_command())
self.set_players(opponent_option)
if opponent_option == 2: # CPU opponent
# choose difficulty
system("cls")
difficulty_option = self.ci.pick_option(self.ui.difficulty_options(), self.ui.difficulty_command())
self.set_difficulty(difficulty_option)
# choose pre_game options
system("cls")
print(self.ui.new_game_alert())
pre_game = self.ci.pick_option(self.ui.pre_game_options(), self.ui.pre_game_command())
if pre_game == 1: # Start new game
self.score = {f'{self.player1["player"]}': 0, f'{self.player2["player"]}': 0} # Start score for new game
return
elif pre_game == 2: # continue game option
if self.board.board is None: # no game was initiated yet
system("cls")
print(self.ui.no_game_in_progress_error())
sleep(2)
continue
return
elif pre_game == 3: # return option. (user decided not start a game for now)
continue
elif menu_option == 2: # select language option
# choose language
system("cls")
language_option = self.ci.pick_option(self.ui.language_options(), self.ui.language_command(), 'value')
self.set_language(language_option)
continue
elif menu_option == 3: # show rules option
system("cls")
print(self.ui.how_to_play())
input(self.ui.continue_input()) # Show the rules until any input
continue
elif menu_option == 4: # exit game
exit()
def set_players(self, opponent:int) -> int:
"""set players info"""
# set players name
self.player1['player'] = 'player_1' if opponent == 1 else 'you'
self.player2['player'] = 'player_2' if opponent == 1 else 'cpu'
# set players symbols on cpu instance
self.cpu.cpu_symbol = self.player2['symbol']
self.cpu.player1_symbol = self.player1['symbol']
def set_language(self, language:str) -> None:
"""set user interface language"""
self.ui.language = language.title()
def set_difficulty(self, difficulty):
"""set CPU IA difficulty"""
self.cpu.difficulty = difficulty
def play(self, starter:dict) -> None:
"""The loop for a game in progress. Ends on a win or draw"""
turn = starter
while True:
system("cls")
self.board.print_formated_board()
print(self.ui.show_turn(**turn))
self.player_turn(turn)
if self.check_end(turn):
return
turn = self.change_turn(turn)
if turn['player'] == 'cpu':
self.cpu_turn(turn)
if self.check_end(turn):
return
turn = self.change_turn(turn)
def player_turn(self, turn:str) -> None:
"""Play in a valid place on the board with player input"""
while True:
user_input = self.ci.pick_in_range(self.ui.get_user_input_play(), 1, self.board.size**2)
line, column = number_to_grid(self.board.size, self.board.size, user_input)
if self.board.place_mark(line, column, turn['symbol']):
return
print(self.ui.not_empty_space_error())
def cpu_turn(self, turn) -> None:
"""Play in a valid place on the board with cpu choice"""
while True:
line, column = self.cpu.play()
if self.board.place_mark(line, column, turn['symbol']):
return
def change_turn(self, actual_turn:str) -> dict:
"""Change the turn on the game
Returns:
dict: the dict of the new player turn"""
return self.player1 if actual_turn == self.player2 else self.player2
def check_end(self, turn:dict) -> bool:
"""checks if the game has ended and run the due events
Args:
turn (dict): The player turn when the game was over
Returns:
bool: False if the game has not ended. True if the game has ended
"""
if self.board.check_win():
self.win_event(self.board.win_info(), turn)
return True
if self.board.is_filled():
self.draw_event()
return True
return False
def win_event(self, win_info:dict, turn:dict) -> None:
"""Events after a win
Args:
win_info (dict): board.win_info return type
turn (dict): info of the player that won
"""
system("cls")
self.board.print_formated_board()
positions = [key for key, value in win_info.items() if value not in [0, 'x', 'o']]
print(self.ui.win_message(turn, positions))
self.score[turn['player']] += 1
# print the score
for key, value in self.score.items():
print(f'{key}: {value}')
def draw_event(self) -> None:
"""Events after a draw"""
system("cls")
self.board.print_formated_board()
print(self.ui.draw_message())
# print the score
for key, value in self.score.items():
print(f'{key}: {value}')
def main(self) -> None:
"""The main game loop to effectively starts playing"""
while True:
self.main_menu()
self.board.create_board()
while True:
self.play(self.player1)
print('\n' + self.ui.main_menu_alert())
end = self.ci.pick_option(self.ui.end_options(), self.ui.end_command())
if end != 1: # not the "play again" choice
break
self.board.create_board()
continue