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() |