Skip to content

Commit 4fb28ee

Browse files
Add files via upload
1 parent f8a2634 commit 4fb28ee

File tree

5 files changed

+789
-0
lines changed

5 files changed

+789
-0
lines changed

PYTHON LUDO/ludo/__init__.py

Whitespace-only changes.

PYTHON LUDO/ludo/cli.py

+310
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
from .game import Player, Game
2+
from .painter import present_6_die_name
3+
from .recorder import RunRecord, MakeRecord
4+
from os import linesep
5+
6+
7+
class CLIGame():
8+
9+
def __init__(self):
10+
self.prompt_end = "> "
11+
self.game = Game()
12+
# used for nicer print
13+
self.prompted_for_pawn = False
14+
# saving game data
15+
self.record_maker = MakeRecord()
16+
# getting game data
17+
self.record_runner = None
18+
19+
def validate_input(self, prompt, desire_type, allawed_input=None,
20+
error_mess="Invalid Option!", str_len=None):
21+
'''
22+
loop while receive correct value
23+
param allowed_input can be list of allowed values
24+
param str_len is two sized tuple if min and max
25+
'''
26+
prompt += linesep + self.prompt_end
27+
while True:
28+
choice = input(prompt)
29+
if not choice:
30+
print(linesep + error_mess)
31+
continue
32+
try:
33+
choice = desire_type(choice)
34+
except ValueError:
35+
print(linesep + error_mess)
36+
continue
37+
if allawed_input:
38+
if choice in allawed_input:
39+
break
40+
else:
41+
print("Invalid Option!")
42+
continue
43+
elif str_len:
44+
min_len, max_len = str_len
45+
if min_len < len(choice) < max_len:
46+
break
47+
else:
48+
print(linesep + error_mess)
49+
else:
50+
break
51+
print()
52+
return choice
53+
54+
def get_user_initial_choice(self):
55+
text = linesep.join(["choose option",
56+
"0 - start new game",
57+
"1 - continue game",
58+
"2 - run (review) recorded game"])
59+
choice = self.validate_input(text, int, (0, 1, 2))
60+
return choice
61+
62+
def prompt_for_file(self, mode="rb"):
63+
'''return file descriptor'''
64+
text = "Enter filename (name of the record)"
65+
while True:
66+
filename = self.validate_input(text, str)
67+
try:
68+
file_descr = open(filename, mode=mode)
69+
return file_descr
70+
except IOError as e:
71+
print(e)
72+
print("Try again")
73+
74+
def does_user_want_save_game(self):
75+
'''return True if user want to save
76+
game or False
77+
'''
78+
text = linesep.join(["Save game?",
79+
"0 - No",
80+
"1 - Yes"])
81+
choice = self.validate_input(text, int, (0, 1))
82+
return choice == 1
83+
84+
def prompt_for_player(self):
85+
''' get player attributes from input,
86+
initial player instance and
87+
add player to the game
88+
'''
89+
available_colours = self.game.get_available_colours()
90+
text = linesep.join(["choose type of player",
91+
"0 - computer",
92+
"1 - human"])
93+
choice = self.validate_input(text, int, (0, 1))
94+
95+
if choice == 1:
96+
name = self.validate_input("Enter name for player",
97+
str, str_len=(1, 30))
98+
available_options = range(len(available_colours))
99+
if len(available_options) > 1:
100+
# show available colours
101+
options = ["{} - {}".format(index, colour)
102+
for index, colour in
103+
zip(available_options,
104+
available_colours)]
105+
text = "choose colour" + linesep
106+
text += linesep.join(options)
107+
choice = self.validate_input(text, int, available_options)
108+
colour = available_colours.pop(choice)
109+
else:
110+
# only one colour left
111+
colour = available_colours.pop()
112+
player = Player(colour, name, self.prompt_choose_pawn)
113+
elif choice == 0:
114+
# automatically assign colours
115+
colour = available_colours.pop()
116+
player = Player(colour)
117+
self.game.add_palyer(player)
118+
119+
def prompt_for_players(self):
120+
'''put all players in the game'''
121+
counts = ("first", "second", "third", "fourth last")
122+
text_add = "Add {} player"
123+
for i in range(2):
124+
print(text_add.format(counts[i]))
125+
self.prompt_for_player()
126+
print("Player added")
127+
128+
text = linesep.join(["Choose option:",
129+
"0 - add player",
130+
"1 - start game with {} players"])
131+
for i in range(2, 4):
132+
choice = self.validate_input(text.format(str(i)), int, (0, 1))
133+
if choice == 1:
134+
break
135+
elif choice == 0:
136+
print(text_add.format(counts[i]))
137+
self.prompt_for_player()
138+
print("Player added")
139+
140+
def prompt_choose_pawn(self):
141+
'''used when player (human) has more than
142+
one possible pawn to move.
143+
This method is pass as a callable during
144+
player instantiation
145+
'''
146+
text = present_6_die_name(self.game.rolled_value,
147+
str(self.game.curr_player))
148+
text += linesep + "has more than one possible pawns to move."
149+
text += " Choose pawn" + linesep
150+
pawn_options = ["{} - {}".format(index + 1, pawn.id)
151+
for index, pawn
152+
in enumerate(self.game.allowed_pawns)]
153+
text += linesep.join(pawn_options)
154+
index = self.validate_input(
155+
text, int, range(1, len(self.game.allowed_pawns) + 1))
156+
self.prompted_for_pawn = True
157+
return index - 1
158+
159+
def prompt_to_continue(self):
160+
text = "press Enter to continue" + linesep
161+
input(text)
162+
163+
def print_players_info(self):
164+
word = "start" if self.game.rolled_value is None else "continue"
165+
print("Game {} with {} players:".format(
166+
word,
167+
len(self.game.players)))
168+
for player in self.game.players:
169+
print(player)
170+
print()
171+
172+
def print_info_after_turn(self):
173+
'''it used game attributes to print info'''
174+
pawns_id = [pawn.id for pawn in self.game.allowed_pawns]
175+
# nicer print of dice
176+
message = present_6_die_name(self.game.rolled_value,
177+
str(self.game.curr_player))
178+
message += linesep
179+
if self.game.allowed_pawns:
180+
message_moved = "{} is moved. ".format(
181+
self.game.picked_pawn.id)
182+
if self.prompted_for_pawn:
183+
self.prompted_for_pawn = False
184+
print(message_moved)
185+
return
186+
message += "{} possible pawns to move.".format(
187+
" ".join(pawns_id))
188+
message += " " + message_moved
189+
if self.game.jog_pawns:
190+
message += "Jog pawn "
191+
message += " ".join([pawn.id for pawn in self.game.jog_pawns])
192+
else:
193+
message += "No possible pawns to move."
194+
print(message)
195+
196+
def print_standing(self):
197+
standing_list = ["{} - {}".format(index + 1, player)
198+
for index, player in enumerate(self.game.standing)]
199+
message = "Standing:" + linesep + linesep.join(standing_list)
200+
print(message)
201+
202+
def print_board(self):
203+
print(self.game.get_board_pic())
204+
205+
def run_recorded_game(self):
206+
'''get history of game (rolled_value
207+
and index's allowed pawn) from
208+
record_runner in order to replay game'''
209+
self.load_recorded_players()
210+
self.print_players_info()
211+
self.prompt_to_continue()
212+
for rolled_value, index in self.record_runner:
213+
self.game.play_turn(index, rolled_value)
214+
self.print_info_after_turn()
215+
self.print_board()
216+
self.prompt_to_continue()
217+
self.print_board()
218+
219+
def continue_recorded_game(self):
220+
'''move forward the game by calling
221+
play_turn method to the moment
222+
where game was interrupted.
223+
'''
224+
self.load_recorded_players()
225+
self.record_players()
226+
for rolled_value, index in self.record_runner:
227+
self.game.play_turn(index, rolled_value)
228+
self.record_maker.add_game_turn(
229+
self.game.rolled_value, self.game.index)
230+
self.print_players_info()
231+
self.print_info_after_turn()
232+
self.print_board()
233+
234+
def record_players(self):
235+
'''save players on recorder'''
236+
for player in self.game.players:
237+
self.record_maker.add_player(player)
238+
239+
def load_recorded_players(self):
240+
'''get recorded (save) players from
241+
recorder and put them in game
242+
'''
243+
if self.record_runner is None:
244+
file_descr = self.prompt_for_file()
245+
self.record_runner = RunRecord(file_descr)
246+
file_descr.close()
247+
for player in self.record_runner.get_players(
248+
self.prompt_choose_pawn):
249+
self.game.add_palyer(player)
250+
251+
def load_players_for_new_game(self):
252+
self.prompt_for_players()
253+
self.print_players_info()
254+
self.record_players()
255+
256+
def play_game(self):
257+
'''mainly calling play_turn
258+
Game's method while game finished
259+
'''
260+
try:
261+
while not self.game.finished:
262+
self.game.play_turn()
263+
self.print_info_after_turn()
264+
self.print_board()
265+
self.record_maker.add_game_turn(
266+
self.game.rolled_value, self.game.index)
267+
self.prompt_to_continue()
268+
print("Game finished")
269+
self.print_standing()
270+
self.offer_save_game()
271+
except (KeyboardInterrupt, EOFError):
272+
print(linesep +
273+
"Exiting game. " +
274+
"Save game and continue same game later?")
275+
self.offer_save_game()
276+
raise
277+
278+
def offer_save_game(self):
279+
'''offer user save game'''
280+
if self.does_user_want_save_game():
281+
file_descr = self.prompt_for_file(mode="wb")
282+
self.record_maker.save(file_descr)
283+
file_descr.close()
284+
print("Game is saved")
285+
286+
def start(self):
287+
'''main method, starting cli'''
288+
print()
289+
try:
290+
choice = self.get_user_initial_choice()
291+
if choice == 0: # start new game
292+
self.load_players_for_new_game()
293+
self.play_game()
294+
elif choice == 1: # continue game
295+
self.continue_recorded_game()
296+
if self.game.finished:
297+
print("Could not continue.",
298+
"Game is already finished",
299+
linesep + "Exit")
300+
else:
301+
self.prompt_to_continue()
302+
self.play_game()
303+
elif choice == 2: # review played game
304+
self.run_recorded_game()
305+
except (KeyboardInterrupt, EOFError):
306+
print(linesep + "Exit Game")
307+
308+
309+
if __name__ == '__main__':
310+
CLIGame().start()

0 commit comments

Comments
 (0)