View difference between Paste ID: nnvpA54S and 24kjgv4i
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()