-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
360 lines (303 loc) · 18.8 KB
/
main.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
import random
class Cards: # The card object is defined here
def __init__(self):
self.market = [] # Container for all cards
self.marketClone = [] # Constant
self.CommitCard = '' # Last Played card
self.CommitList = [] # All played cards are stored here
def create_deck(self):
self.deck = []
for _ in range(5):
self.shape_list = []
self.exception = [0, 6, 9, 15, 16, 17, 18, 19]
for j in range(21):
if j in self.exception:
pass
else:
self.shape_list.append(j) # Adds the list of valid numbers for a whot game to the shapes list
self.deck.append(self.shape_list) # Appending all five to a parent list called deck
return self.deck # return deck upon call
def print_deck(self):
print(self.deck)
def generate_market(self):
self.shape_name = ["Circle", "Cross", "Triangle", "Square", "Star"] # An initialization of all the shape names
for y in range(len(self.deck)):
for z in self.deck[y]:
self.market.append(self.shape_name[y] + str(z)) # This creates the list of all the cards with thee shape name appended to the beginning e.g Circle10
self.marketClone.append(self.shape_name[y] + str(z)) # Stores a duplicate of the above step in another list
return self.market, self.marketClone
def shuffle_market(self):
random.shuffle(self.market) # Shuffles Market... Market is the list containing all the card deck
return self.market
def assign_firstCard(self): # This method assigns the initial card that decides what the first player is to play
randomInt = random.randint(0, (len(self.market) - 1)) # Generate a random int between O and the number of cards in the market
self.CommitCard = self.market[randomInt] # Picks the card at the randompositionn deduced earlier and stores it in the commit variacble
self.market.pop(randomInt) # This card cannot exist twice so since it is already in commit, it is removed from market.
self.CommitList.append(self.CommitCard) # This list stores all the commits i.e all played cards but it is initially empty and now we add commit into it
return self.CommitCard
def print_market(self):
for i in self.market:
print(i)
def tender(self, gameObj):
lenOfCards = []
add = 0
for i in range(gameObj.numOfPlayers): # Loop through the list of players and select theindex of each player
for j in gameObj.newPlayerList[i].playerCards: # For each player access the list containing their unplayed cards
testSum = gameObj.newPlayerList[i].check_for_digit(j) # Pick the numeric values from all the cards
add += testSum # sum those numeric values
lenOfCards.append(add) # store the numeric sums of cards for all players in List called lenOfCards
add = 0
smallest = lenOfCards[0] # Set the first element of the list as the smallest
j = len(lenOfCards)
for l in range(1, j): # loop through the rest of the other players
if smallest > lenOfCards[l]: # Compare the smallest element with the present element
smallest = lenOfCards[l] # store the new smallest value in smallest
smallestIndex = lenOfCards.index(smallest) # Select the index of the overall smallest element and store in smallestIndex
print("Ran out of market, Winner upon tender is", gameObj.newPlayerList[smallestIndex].alias) # Declare the winner upon tender
print(">>> ", gameObj.newPlayerList[smallestIndex].alias, "won because It has the smallest sum of cards")
raise SystemExit("The End... Quiting game!!!") # quit the game
def goto_market(self, playerObj): # An option for player to pick a card if non of its cards matches commit.
if len(self.market) > 0: # This can only be done when market is not empty
playerObj.playerCards.append(self.market[0]) # Append the first card in market to the players card list
playerObj.playerCardsIndex = playerObj.stack_index(self) # Go to the PlayerClass and execute stack_index which refreshes list of indices of all player cards and store it in this variable
self.market.pop(0) # Remove the card selected away from market
else: # This means market is empty
self.tender(gameloop) # We choose to tender our cards then... call tender method.
return playerObj.playerCards, playerObj.playerCardsIndex
class Player: # Defines the Players behaviors and characteristics
def __init__(self): # Initializing the different characteristics of the player object
self.playerCards = [] # this contains the players cards
self.playerCardsIndex = [] # this contains the list of the indicecs of this cards in the MarketClone(Constant market)
self.name = '' # The name of the Player Obj
self.alias = '' # The alias of the player obj
self.cardIndex = 0 # Used to store the index of a card
self.chosenIndex = 0 # Stores the index of the card the player wish to commit
self.chosenCard = '' # the card identifier that the player wants to commit
self.cardDigit = 0 # The digit of the card that the player wants to commit
self.commitDigit = 0 # The digit of the card that is in commit
self.cardShape = '' # The shape of the card that the player wants to commit
self.commitShape = '' # The shape of the card that is in commit
self.cardEffectPeriod = 1
def create_profile(self): # creates a profile for the player
self.name = input("Enter your alias(Avatar_name)>>> ") # Asks input for Human players choice name
self.alias = self.name[0].upper() # Picks the first letter converts it to Uppercase and sets it as the alias
return self.alias
def create_stack(self, cardObj): # create players cards
print(self.alias)
for _ in range(5): # Create 5 cards for the player
randomNum = random.randint(0, (len(cardObj.market) - 1)) # pick randomly from market
self.playerCards.append(cardObj.market[randomNum]) # adds it to player cards list
cardObj.market.pop(randomNum) # removes the cards from market
return self.playerCards # return the list of all of the current players cards
def stack_index(self, cardObj):
self.playerCardsIndex.clear() # Clears Player Cards Indices list
for item in self.playerCards: # loop through all player cards
for obj in cardObj.marketClone: # Check through the constant clone of market
if obj == item: # confirm if the players cards are in market clone
self.cardIndex = cardObj.marketClone.index(obj) # Then select the index of each card from market clone
self.playerCardsIndex.append(self.cardIndex) # Put those indices in a list
return self.playerCardsIndex
def player_stack(self, cardObj): # Work on distribution of cards to players
self.create_stack(cardObj) # calls the method that creates card
self.stack_index(cardObj) # calls the method that store the indices the cards created above
def print_playerDetails(self): # Prints player details
print(self.alias)
print(self.playerCards)
def check_for_digit(self, cardName): # Finds numeric value is a Card identifier/name
num = '' # an empty string to capture the digits
for item in cardName: # in card name, loop through all characters
if item.isdigit(): # if item is a digit
num += item # append to num e.g Star21 => '2' + '1' = '21'
cardNum = int(num) # convert num to an integer and store it cardNum
return cardNum # return that integer
def check_for_shape(self, cardName): # checks for the name of the shape in the card name
shape = ''
for item in cardName: # in card name, loop through all characters
if item.isalpha() == True: # if item is a string
shape += item # add item to shape e.g Star21 => 'S' + 't' + 'a' + 'r' = 'Star'
return shape # return shape
def card_selection(self, cardObj): # Prompts player to play its card
self.print_playerDetails() #Prints the details of the one to play
print("\nThe presently committed card is", cardObj.CommitCard, "\n") # Informs player about the last played card(commit)
self.chosenIndex = int(input("Enter the order of the card you want to play, e.g if 1st enter 1 | Press 0 to go to Market>>> ")) # prompt to enter an input or go to market
def commit_card(self, cardObj): # Handles card validation
self.card_selection(cardObj) # calls the prompt for player to play a card
self.chosenCard = self.playerCards[self.chosenIndex - 1] # stores the chosen card in a container for validation
self.cardShape = self.check_for_shape(self.chosenCard) # Check for the shape of the card player played and store the shape for validattion
self.cardDigit = self.check_for_digit(self.chosenCard) # Check for the digit of the card player played and store the digit for validattion
self.commitShape = self.check_for_shape(cardObj.CommitCard) # Check for the shape of last played card
self.commitDigit = self.check_for_digit(cardObj.CommitCard) # Check for the digit of last played card
conditions = (self.commitShape == self.cardShape) or (self.commitDigit == 20) or (self.cardDigit == self.commitDigit) or (self.cardDigit == 20) # conditions for validation
if conditions and self.chosenIndex != 0: # If condition is met and player did not decide to pick a card from market
cardObj.CommitCard = self.chosenCard # Accept the card and make it the new last played card
print(self.alias, "played", self.chosenCard) # Inform all players about current players card choice
self.playerCards.pop(self.chosenIndex - 1) # Upon accepting the card from the user, remove it from the list of cards the player can play
self.playerCardsIndex.pop(self.chosenIndex - 1) # remove its index from the list of player card indices
cardObj.CommitList.append(cardObj.CommitCard) # add the card to list of previously played cards
if self.cardDigit == 1 or self.cardDigit == 2 or self.cardDigit == 5 or self.cardDigit == 8 or self.cardDigit == 14 :
self.cardEffectPeriod = 1
elif self.chosenIndex == 0: # If player decided to go to market to pick a card
self.cardEffectPeriod = 0
cardObj.goto_market(self) # call the method that does that in the card Object class
print(self.alias, "went to Market") # Tell the players that current player decided to visit the market
else: # if none of the conditions are met,
print("Your card is not acceptable. Commit a valid card | Press 0 to Go to Market") # Reject the card and prompt the user for another input
self.commit_card(cardObj) # rerun current method
return cardObj.CommitCard # return Commited Card
class AIPlayer(Player): # AI players special behavior and characteristics are defined here, it inherits frfom Player class
def __init__(self):
super().__init__() # Inheritance in Python
self.name = 'AI'
self.alias = 'AI'
self.playerCards = []
self.playerCardsIndex = []
self.cardEffectPeriod = 1
def ai_stack(self, cardObj): # distributes cards to the ai players
self.playerCards = self.create_stack(cardObj)
self.playerCardsIndex = self.stack_index(cardObj)
def ai_decision(self, cardObj): # The ai's logic for selecting the best card... No future prediction, just a simple thought process
random.shuffle(self.playerCards) # Shuffle ai's cards
for j in self.playerCards: # Run a test on all cards
self.chosenCard = j # The current chosen card
self.cardShape = self.check_for_shape(self.chosenCard) # Check for the shape of the ai's card
self.commitShape = self.check_for_shape(cardObj.CommitCard) # Check for the shape of the last played card
self.cardDigit = self.check_for_digit(self.chosenCard) # Check for the digit of the ai's card
self.commitDigit = self.check_for_digit(cardObj.CommitCard) # Check for the digit of the last played card
conditions = (self.commitShape == self.cardShape) or (self.commitDigit == 20) or (self.cardDigit == self.commitDigit) or (self.cardDigit == 20) # conditions for validation
if conditions: # if condition is met
cardObj.CommitCard = self.chosenCard # Accept card
cardObj.CommitList.append(cardObj.CommitCard) # Add card to list of last played cards
if self.cardDigit == 1 or self.cardDigit == 2 or self.cardDigit == 5 or self.cardDigit == 8 or self.cardDigit == 14 :
self.cardEffectPeriod = 1
print(self.alias, "played", self.chosenCard) # Inform players about ai's choice
self.playerCardsIndex.pop(self.playerCards.index(self.chosenCard)) # Remove card index from list of ai cards indices
self.playerCards.remove(self.chosenCard) # remove card from list of cards ai can play
break # stop looking for other acceptable cards
else: # If condition is not met
self.cardEffectPeriod = 0
cardObj.goto_market(self) # ai should pick a card from market
print(self.alias, "went to Market") # Inform all about ai's decision to visit the market
return cardObj.CommitCard
class Gameplay: # Game Manager
def __init__(self):
self.testcase = 0
self.playerList = []
self.numOfaiPlayers = 0
self.numOfPlayers = 0
self.newPlayerList = []
self.firstPlayerIndex = 0
self.winner = ''
self.runGame = True
self.k = 0
def num_ai(self):
self.numOfaiPlayers = int(input("Choose Number of AI opponents >>> "))
self.numOfPlayers = 1 + self.numOfaiPlayers
for i in range(self.numOfaiPlayers):
ai = AIPlayer()
self.playerList.append(ai)
j = i + 1
ai.alias = f"AI_{j}"
def select_first_player(self, cardObj):
print("The Default commited card is", cardObj.CommitCard)
for i in range(self.numOfPlayers):
self.newPlayerList.append(self.playerList[i])
randomDieOutput = random.randint(0, (self.numOfaiPlayers))
self.firstPlayerIndex = randomDieOutput
print("First player is", self.newPlayerList[self.firstPlayerIndex].alias)
return self.firstPlayerIndex
def play(self, runIndex, cardObj):
if runIndex == 0:
self.newPlayerList[runIndex].commit_card(cardObj)
else:
self.newPlayerList[runIndex].ai_decision(cardObj)
def hold_on(self, runIndex, playerObj, cardObj):
print("Hold on Fella's...", playerObj.alias, "has another chance to play")
self.play(runIndex, cardObj)
self.card_test(runIndex, playerObj, cardObj)
def pick(self, playerObj, cardObj, num):
if self.k == self.numOfaiPlayers:
playerObj = self.newPlayerList[0]
else:
playerObj = self.newPlayerList[self.k + 1]
print(playerObj.alias, "is gifted", num, "cards")
for _ in range(num):
cardObj.goto_market(playerObj)
self.skip()
def pick_two(self, playerObj, cardObj, num):
self.pick(playerObj, cardObj, num)
def pick_three(self, playerObj, cardObj, num):
self.pick(playerObj, cardObj, num)
def skip(self):
if self.k == self.numOfaiPlayers:
self.k = 0
else:
self.k += 1
print("---Skipped One Player---")
def general_market(self, runIndex, playerObj, cardObj):
print("...General Market... | All players are gifted a card except for current player")
counter = 0
while counter < self.numOfaiPlayers:
if (runIndex == self.numOfaiPlayers):
runIndex = 0
elif (runIndex < self.numOfaiPlayers):
runIndex += 1
if runIndex != self.k:
playerObj = self.newPlayerList[runIndex]
cardObj.goto_market(playerObj)
else:
break
counter += 1
runIndex = self.k
self.play(runIndex, cardObj)
self.card_test(runIndex, playerObj, cardObj)
def card_test(self, runIndex, playerObj, cardObj):
self.testcase = playerObj.check_for_digit(cardObj.CommitCard)
if playerObj.cardEffectPeriod != 0:
playerObj.cardEffectPeriod = 0
if self.testcase == 1:
self.hold_on(runIndex, playerObj, cardObj)
elif self.testcase == 2:
self.pick_two(playerObj, cardObj, 2)
elif self.testcase == 5:
self.pick_three(playerObj, cardObj, 3)
elif self.testcase == 8:
self.skip()
elif self.testcase == 14:
self.general_market(runIndex, playerObj, cardObj)
else:
pass
def winner_test(self, playerObj):
if len(playerObj.playerCards) == 0:
self.winner = playerObj.alias
self.runGame = False
print(self.winner, "is the Champion!!!")
elif len(playerObj.playerCards) == 1:
print("Alert!!! =>",playerObj.alias, "has one more card left")
return self.winner, self.runGame
def run(self):
c = Cards()
c.create_deck()
c.generate_market()
p1 = Player()
self.playerList.append(p1)
p1.create_profile()
self.playerList[0].player_stack(c)
self.num_ai()
for i in range(self.numOfaiPlayers):
self.playerList[i + 1].ai_stack(c)
c.shuffle_market()
c.assign_firstCard()
self.select_first_player(c)
self.k = self.firstPlayerIndex
while (self.winner == '') and (self.runGame == True):
self.play(self.k, c)
self.card_test(self.k, self.newPlayerList[self.k], c)
self.winner_test(self.newPlayerList[self.k])
if self.k == self.numOfaiPlayers:
self.k = 0
else:
self.k += 1
print(f"There is a winner already!: {self.winner}")
if __name__ == '__main__':
gameloop = Gameplay()
gameloop.run()