SHOW:
|
|
- or go back to the newest paste.
1 | # Ship Captain Crew | |
2 | # | |
3 | ||
4 | ||
5 | ||
6 | import sys | |
7 | import random | |
8 | ||
9 | - | use_unicode_dice = True |
9 | + | |
10 | # False: Print numbers instead of unicode dice. | |
11 | use_unicode_dice = False | |
12 | ||
13 | # compatible user input regardless of version. | |
14 | if sys.version_info[0] == 3: | |
15 | raw_input = input | |
16 | use_unicode_dice = True | |
17 | ||
18 | # These are unicode representations of dice given their side. | |
19 | # FACE: 1 2 3 4 5 6 | |
20 | unicode_faces = [None,"\u2680","\u2681","\u2682","\u2683","\u2684","\u2685"] | |
21 | ||
22 | #------------------------------------------------------------------------------- | |
23 | def get_unicode_dice(dice): | |
24 | """ | |
25 | dice = list of numbers [1-6] | |
26 | ||
27 | Expect: | |
28 | Given provided dice, return the values in unicode. | |
29 | ||
30 | Return: | |
31 | List of unicode characters representing dice values. | |
32 | """ | |
33 | faces = [int(die) for die in dice] | |
34 | return [unicode_faces[i] for i in faces] | |
35 | ||
36 | #------------------------------------------------------------------------------- | |
37 | def print_dice(dice): | |
38 | """ | |
39 | dice = list of numbers [1-6] | |
40 | ||
41 | Expect: | |
42 | prints each die out in single line separated by 2 spaces. | |
43 | If use_unicode = True, then prints the unicode. Otherwise, | |
44 | print the numerical values. | |
45 | ||
46 | Return: | |
47 | None | |
48 | """ | |
49 | faces = [str(die) for die in dice] | |
50 | ||
51 | if use_unicode_dice: | |
52 | faces = get_unicode_dice(dice) | |
53 | ||
54 | print(' '.join(faces)) | |
55 | ||
56 | #------------------------------------------------------------------------------- | |
57 | def print_scoreboard(players): | |
58 | """ | |
59 | players = list of player objects | |
60 | ||
61 | Expect: | |
62 | prints the score for all players received in alphabetical order by | |
63 | descending score. These results are padded with dots to allow for | |
64 | uniform output. | |
65 | ||
66 | Return: | |
67 | None | |
68 | """ | |
69 | names_sorted = sorted(players, key=lambda n: n.name) | |
70 | scores_sorted = sorted(names_sorted, key=lambda s: s.score, reverse=True) | |
71 | ||
72 | text = [] | |
73 | # " _____________________________________________________________ " | |
74 | text.append(" YE PLUNDERED BOOTY!") | |
75 | ||
76 | for i, s in enumerate(scores_sorted): | |
77 | text.append("%d. %s%d" % ((i+1), s.name.ljust(30, '.'), s.score)) | |
78 | ||
79 | print_scroll(text) | |
80 | ||
81 | #=============================================================================== | |
82 | # I honestly do not know why I'm keeping this around. Since python duck-typed, | |
83 | # it's not like I need it to group the states or anything. I suppose the biggest | |
84 | # strength it has right now is future extensions that *might* happen. | |
85 | class State(object): | |
86 | ||
87 | #--------------------------------------------------------------------------- | |
88 | def status(self): | |
89 | print("You see %s" % self.name) | |
90 | ||
91 | #=============================================================================== | |
92 | # This is our initial state of voyage. We roll 6 dice and attempt to transition | |
93 | # into other states based on the roll. The only direct transition available is | |
94 | # into Ship. No score here. | |
95 | class Deserted(State): | |
96 | def __init__(self, voyage): | |
97 | self.voyage = voyage | |
98 | self.total = 0 | |
99 | self.name = "deserted waters" | |
100 | ||
101 | #--------------------------------------------------------------------------- | |
102 | def roll_dice(self): | |
103 | dice = get_roll("5d6") | |
104 | return dice | |
105 | ||
106 | #--------------------------------------------------------------------------- | |
107 | def update(self, dice): | |
108 | print_dice(dice) | |
109 | if 6 in dice: | |
110 | print("6 found!") | |
111 | dice.remove(6) | |
112 | self.voyage.state = self.voyage.ship | |
113 | self.voyage.state.update(dice) | |
114 | ||
115 | #=============================================================================== | |
116 | # This state of voyage is achieved after we have been in Deserted state. In this | |
117 | # state, we roll 4 dice and can possibly modify state to Captain. No score here. | |
118 | class Ship(State): | |
119 | def __init__(self, voyage): | |
120 | self.voyage = voyage | |
121 | self.total = 0 | |
122 | self.name = "a ship" | |
123 | ||
124 | #--------------------------------------------------------------------------- | |
125 | def roll_dice(self): | |
126 | dice = get_roll("4d6") | |
127 | return dice | |
128 | ||
129 | #--------------------------------------------------------------------------- | |
130 | def update(self, dice): | |
131 | print_dice(dice) | |
132 | if 5 in dice: | |
133 | print("5 found!") | |
134 | dice.remove(5) | |
135 | self.voyage.state = self.voyage.captain | |
136 | self.voyage.state.update(dice) | |
137 | ||
138 | #=============================================================================== | |
139 | # This state of voyage is achieved after we have been in Ship state. In this | |
140 | # state, we roll 3 dice and can possibly modify state to Crew. No score here. | |
141 | class Captain(State): | |
142 | def __init__(self, voyage): | |
143 | self.voyage = voyage | |
144 | self.total = 0 | |
145 | self.name = "a ship, and a captain" | |
146 | ||
147 | #--------------------------------------------------------------------------- | |
148 | def roll_dice(self): | |
149 | dice = get_roll("3d6") | |
150 | return dice | |
151 | ||
152 | #--------------------------------------------------------------------------- | |
153 | def update(self, dice): | |
154 | print_dice(dice) | |
155 | if 4 in dice: | |
156 | print("4 found!") | |
157 | dice.remove(4) | |
158 | self.voyage.state = self.voyage.crew | |
159 | self.voyage.state.update(dice) | |
160 | ||
161 | #=============================================================================== | |
162 | # This state of voyage is achieved after we have been in Captain state. In this | |
163 | # state, we roll only 2 dice and we apply total from these dice. | |
164 | class Crew(State): | |
165 | def __init__(self, voyage): | |
166 | self.voyage = voyage | |
167 | self.total = 0 | |
168 | self.name = "a ship, and a captain, and a crew" | |
169 | ||
170 | #--------------------------------------------------------------------------- | |
171 | def roll_dice(self): | |
172 | dice = get_roll("2d6") | |
173 | return dice | |
174 | ||
175 | #--------------------------------------------------------------------------- | |
176 | def update(self, dice): | |
177 | print_dice(dice) | |
178 | self.total = sum(dice) | |
179 | print("Your score is: %d" % self.total) | |
180 | ||
181 | #=============================================================================== | |
182 | # This represents a full turn cycle for a player. This is the top level of our | |
183 | # state machine. The following states are entered: | |
184 | # - Deserted = Before Ship | |
185 | # - Ship = After Deserted -- Before Captain | |
186 | # - Captain = After Ship -- Before Crew | |
187 | # - Crew = After Captain -- End State (scoring mechanics) | |
188 | class Voyage(object): | |
189 | ||
190 | def __init__(self): | |
191 | self.deserted = Deserted(self) | |
192 | self.ship = Ship(self) | |
193 | self.captain = Captain(self) | |
194 | self.crew = Crew(self) | |
195 | ||
196 | self.state = self.deserted | |
197 | ||
198 | # The number of rolls permitted apparently is unchangable. | |
199 | # TODO: modify to list as words [First, Second, Third] | |
200 | self.turns = 3 | |
201 | ||
202 | #--------------------------------------------------------------------------- | |
203 | # It might make more sense to pass the player into this so we don't have | |
204 | # to return the total and instead increment it right here. | |
205 | # TODO: pass in player instead. | |
206 | def play2(self): | |
207 | print("="*40) | |
208 | for turn in range(self.turns): | |
209 | dice = self.state.roll_dice() | |
210 | self.state.update(dice) | |
211 | self.state.status() | |
212 | if self.state == self.crew: | |
213 | choice = raw_input("Keep score? [Y/N]: ") | |
214 | if choice.lower() in ['y','yes']: | |
215 | print("you keep %d points" % self.state.total) | |
216 | break | |
217 | print("That was turn %d" % turn) | |
218 | return self.state.total | |
219 | ||
220 | def play(self, player): | |
221 | print("="*40) | |
222 | print("%s is scouting" % player.name) | |
223 | for turn in range(self.turns): | |
224 | dice = self.state.roll_dice() | |
225 | self.state.update(dice) | |
226 | self.state.status() | |
227 | if self.state == self.crew: | |
228 | choice = raw_input("Keep score? [Y/N]: ") | |
229 | if choice.lower() in ['y','yes']: | |
230 | print("you keep %d points" % self.state.total) | |
231 | break | |
232 | print("That was turn %d" % turn) | |
233 | ||
234 | player.score += self.state.total | |
235 | ||
236 | #=============================================================================== | |
237 | # While thin, the player object does make sense because we keep track of a | |
238 | # score specific to a player. | |
239 | class Player(object): | |
240 | def __init__(self, name): | |
241 | self.name = name | |
242 | self.score = 0 | |
243 | ||
244 | #--------------------------------------------------------------------------- | |
245 | def set_sail(self): | |
246 | v = Voyage() | |
247 | v.play(self) | |
248 | #self.score += v.play() | |
249 | ||
250 | #--------------------------------------------------------------------------- | |
251 | def status(self): | |
252 | print("%s has %d points." % (self.name, self.score)) | |
253 | #=============================================================================== | |
254 | ||
255 | #------------------------------------------------------------------------------- | |
256 | def get_roll(asking): | |
257 | """ | |
258 | We receive a string formated as xdy | |
259 | x = quantity of dice | |
260 | y = sides of dice | |
261 | d = separator | |
262 | """ | |
263 | quantity, sides = asking.lower().split('d') | |
264 | dice = [random.randint(1, int(sides)) for i in range(int(quantity))] | |
265 | return dice | |
266 | ||
267 | #------------------------------------------------------------------------------- | |
268 | def get_roster(): | |
269 | names = raw_input("Enter players separated by comma: ") | |
270 | return tuple(names.strip().split(',')) | |
271 | ||
272 | #------------------------------------------------------------------------------- | |
273 | def print_scroll(text): | |
274 | print(" _____________________________________________________________ ") | |
275 | print("o=(_____________________________________________________________)=o") | |
276 | ||
277 | for line in text: | |
278 | print(" | %s|" % (line.ljust(58))) | |
279 | ||
280 | print(" |___________________________________________________________|") | |
281 | print("o=(_____________________________________________________________)=o") | |
282 | ||
283 | #------------------------------------------------------------------------------- | |
284 | def show_instructions(): | |
285 | instructions = [ | |
286 | " ----=== SHIP CAPTAIN CREW ===----", | |
287 | "The Voyage:", | |
288 | "A voyage consists of 3 rolls of the dice. Depending on ", | |
289 | "what you have acquired, you may be rolling 5, 4, 3, or ", | |
290 | "2 dice. To acquire your needed provisions, you must roll", | |
291 | "the numbers in correct order.", | |
292 | "", | |
293 | "Ship = 6 from 5 dice", | |
294 | "Captain = 5 from 4 dice but only with ship", | |
295 | "Crew = 4 from 3 dice but only with ship and captain", | |
296 | - | " %s" % (' '.join(get_unicode_dice([5,4,3,2,1]))), |
296 | + | |
297 | "A single roll may yield multiple provisions but they", | |
298 | "cannot be out of order. For example, if the roll is:", | |
299 | " 5 4 3 2 1", | |
300 | "you still do not have a ship because no six came up.", | |
301 | "Without a ship, there's no captain. Without a captain", | |
302 | "there's no crew. Without crew, there's no plunder!", | |
303 | "", | |
304 | "Scoring:", | |
305 | "Once you have a ship, a captain, and a crew, the other", | |
306 | "two dice are added together to give you your spoils. If", | |
307 | "you do not like what you've gathered, you may roll again", | |
308 | "if you have rolls to spare.", | |
309 | "", | |
310 | "Winning:", | |
311 | "The player with the highest score after all voyages have", | |
312 | "been played through is the winner.", | |
313 | "", | |
314 | "Savvy?", | |
315 | ] | |
316 | ||
317 | print_scroll(instructions) | |
318 | ||
319 | #------------------------------------------------------------------------------- | |
320 | def pre_game(): | |
321 | """ | |
322 | We find out whether or not the players need instruction on the game. | |
323 | If so, print the instructions. If not, return out. | |
324 | If a valid choice is entered, assume instruction is needed. | |
325 | """ | |
326 | print("Har mate! So, ye want to amass vast treasures? Might ye be") | |
327 | print("wanting to know how? Or are you salty enough?") | |
328 | print("1. Teach me!") | |
329 | print("2. Back off dog! I know what I'm doing!") | |
330 | choice = raw_input("Choose ye fate: ") | |
331 | ||
332 | if choice not in ['2']: | |
333 | show_instructions() | |
334 | raw_input("[press enter when ready to play]") | |
335 | ||
336 | voyages = raw_input("Ahoy! And how many trips ye be takin'?") | |
337 | try: | |
338 | return int(voyages) | |
339 | except: | |
340 | return 5 | |
341 | ||
342 | #------------------------------------------------------------------------------- | |
343 | def main(): | |
344 | voyages = pre_game() | |
345 | ||
346 | names = get_roster() | |
347 | players = [Player(name) for name in names] | |
348 | print_scoreboard(players) | |
349 | ||
350 | for voyage in range(voyages): | |
351 | print("............VOYAGE %d/%d................" % (voyage+1,voyages)) | |
352 | for player in players: | |
353 | player.set_sail() | |
354 | player.status() | |
355 | raw_input("waiting...") | |
356 | ||
357 | print_scoreboard(players) | |
358 | ||
359 | # Don't currently have a winner code. You just use your eyes when playing. | |
360 | # TODO: Add winner code... | |
361 | ||
362 | #------------------------------------------------------------------------------- | |
363 | if __name__ == '__main__': | |
364 | main() |