def use_robber(player, robber, hexes, boardSurface, playerKey, menuSurface, titleFont, infoFont): # Get the current hex of the Robber to use as a metric to know when the player has successfully picked a new hex destinationHex = robber.currentHex print("Choose a new hex for the Robber.") # Ask the player to which hex they want to move the Robber destinationHex = ui.get_hex_from_player(player, hexes, playerKey) if destinationHex is None: return (1, "{} did not choose a hex.".format(player.name)) # A list to hold the players from whom the player can steal playersAvailableToRob = [] # Loop through the vertices that surround the Robber's new hex for vertex in destinationHex.vertices: # Check whether each vertex has a settlement built on it if vertex.settlement is not None: # If so, check that the owner of that settlement is not the player if vertex.settlement.owner != player and vertex.settlement.owner not in playersAvailableToRob: # If that's the case, the owner of that vertex is a player from whom the player can steal playersAvailableToRob.append(vertex.settlement.owner) # The default value for the player from whom the player will steal playerToRob = None # If the player has multiple players from whom they can steal, ask them to choose their target if len(playersAvailableToRob) > 0: print("Choose the player from whom you wish to steal.") playerMenu = {"Cancel and return to main menu": None} for plyr in playersAvailableToRob: playerMenu["{} ({} cards)".format(plyr.name, sum(plyr.cardsInHand.values()))] = plyr playerToRob = ui.present_menu(player, playerMenu, "Steal from", menuSurface, titleFont, infoFont) if playerToRob is None: return (2, "{} did not choose a player.".format(player.name)) robberResult = robber.play(boardSurface, destinationHex, player, playerToRob) return (0, robberResult)
def halve_player_hand(player, playerList, resourceDecks, handSurface, menuSurface, enemySurface, titleFont, infoFont): handSurface.fill(c.white) ui.present_menu(player, {"Yes": 1}, "Ready?", menuSurface, titleFont, infoFont) draw_player_hand(player, handSurface, titleFont, infoFont) draw_enemy_info(player, playerList, enemySurface, infoFont) pygame.display.update(handSurface.get_rect()) numToDiscard = int(sum(player.cardsInHand.values()) / 2.0) while numToDiscard > 0: resourcesInHand = sorted([resource for resource in player.cardsInHand.keys() if player.cardsInHand[resource] > 0]) resourceMenu = OrderedDict(zip(resourcesInHand, resourcesInHand)) cardToDiscard = ui.present_menu(player, resourceMenu, "Discard {}".format(numToDiscard), menuSurface, titleFont, infoFont) player.discard_resources({cardToDiscard: 1}, resourceDecks) draw_player_hand(player, handSurface, titleFont, infoFont) pygame.display.update(handSurface.get_rect()) numToDiscard -= 1 return (0, "{} successfully discarded cards.".format(player.name))
def play_yop_card(player, resourceDecks, surface, titleFont, infoFont): if not player.has_dev_card("Year of Plenty"): if player.has_new_dev_card("Year of Plenty"): return (1, "Cannot play a Development Card on the turn it's bought.") return (1, "{} does not have a Year of Plenty to play.".format(player.name)) availableResources = [resource for resource in resourceDecks.keys() if resourceDecks[resource] > 0] resourceMenu = OrderedDict(zip(availableResources, availableResources)) resourceMenu["Cancel and return to main menu"] = None print("{}, choose the first resource to draw.".format(player.name)) resource1 = ui.present_menu(player, resourceMenu, "Draw Which? (1)", surface, titleFont, infoFont) if resource1 is None: return (2, "{} chose to not play a Year of Plenty.".format(player.name)) player.draw_resources({resource1: 1}, resourceDecks) player.consume_dev_card("Year of Plenty") availableResources = [resource for resource in resourceDecks.keys() if resourceDecks[resource] > 0] resourceMenu = OrderedDict(zip(availableResources, availableResources)) resourceMenu["Don't draw a 2nd card"] = None print("{}, choose the second resource to draw.".format(player.name)) resource2 = ui.present_menu(player, resourceMenu, "Draw Which? (2)", surface, titleFont, infoFont) if resource2 is None: return (0, "{} used Year of Plenty to draw {}".format(player.name, resource1)) player.draw_resources({resource2: 1}, resourceDecks) return (0, "{} used Year of Plenty to draw {} and {}".format(player.name, resource1, resource2))
def maritime_trade(player, resourceDecks, surface, titleFont, infoFont): tradeAwayList = [] for resource in c.resourceTypes: ratio = player.tradeRatios[resource] if player.cardsInHand[resource] >= ratio: tradeAwayList.append(("{} at {} to 1".format(resource, ratio), resource)) tradeAwayList.append(("Cancel and return to main menu", None)) tradeAwayMenu = OrderedDict(tradeAwayList) print("Please select the resource you would like to maritime trade: ") resourceTrading = ui.present_menu(player, tradeAwayMenu, "Trade Away", surface, titleFont, infoFont) if resourceTrading is None: return (1, "{} chose not to trade.".format(player.name)) tradeRatio = player.tradeRatios[resourceTrading] tradeForList = [] for resource in c.resourceTypes: if resource is not resourceTrading and resourceDecks[resource] > 0: tradeForList.append((resource, resource)) tradeForList.append(("Cancel and return to main menu", None)) tradeForMenu = OrderedDict(tradeForList) resourceGetting = ui.present_menu(player, tradeForMenu, "Trade For", surface, titleFont, infoFont) if resourceGetting is None: return (1, "{} chose not to trade.".format(player.name)) tradeAmountList = [] counter = 1 while counter * tradeRatio <= player.cardsInHand[resourceTrading] and counter <= resourceDecks[resourceGetting]: tradeAmountList.append(("{} {} for {} {}".format(counter * tradeRatio, resourceTrading, counter, resourceGetting), counter)) counter += 1 tradeAmountList.append(("Cancel and return to main menu", None)) tradeAmountMenu = OrderedDict(tradeAmountList) tradeQuantity = ui.present_menu(player, tradeAmountMenu, "Trade", surface, titleFont, infoFont) if tradeQuantity is None: return (1, "{} chose not to trade.".format(player.name)) player.discard_resources({resourceTrading: tradeQuantity * tradeRatio}, resourceDecks) player.draw_resources({resourceGetting: tradeQuantity}, resourceDecks) return (0, "{} traded {} {} for {} {}".format(player.name, tradeQuantity * tradeRatio, resourceTrading, tradeQuantity, resourceGetting))
def play_monopoly_card(player, resourceDecks, playerList, surface, titleFont, infoFont): if not player.has_dev_card("Monopoly"): if player.has_new_dev_card("Monopoly"): return (1, "Cannot play a Development Card on the turn it's bought.") return (1, "{} does not have a Monopoly card to play.".format(player.name)) print("{}, which resource do you want to monopolize?".format(player.name)) resourceMenu = OrderedDict(zip(c.resourceTypes, c.resourceTypes)) resourceMenu["Cancel and return to main menu"] = None choice = ui.present_menu(player, OrderedDict(zip(c.resourceTypes, c.resourceTypes)), "Take Which?", surface, titleFont, infoFont) if choice is None: return (2, "{} cancelled the play. Returning.") startCount = player.cardsInHand[choice] enemyList = [person for person in playerList if person != player] for enemy in enemyList: enemyResourceCount = enemy.cardsInHand[choice] enemy.discard_resources({choice: enemyResourceCount}, resourceDecks) player.draw_resources({choice: enemyResourceCount}) gain = player.cardsInHand[choice] - startCount return (0, "{} drew {} {} from the other players.".format(player.name, gain, choice))
def main(): # A dictionary to hold the decks of resources, keyed to their resource name resourceDecks = {c.lumber: 19, c.grain: 19, c.wool: 19, c.clay: 19, c.ore: 19} developmentDeck = deque(c.developmentDeckList) # A list of the hexes, assigned a resource and a numbered tile using the lists above hexes = [p.Hex(c.resourcesForHexes[x], c.oddsOrdered[x], c.resourceToColor[c.resourcesForHexes[x]], c.hexCenters[x]) for x in range(19)] # Iterate over the hexes and create Vertex objects using the coordinates of their vertices vertices = [] vertexCoordsSeen = [] # Loop over the top 3 rows of hexes for hexTile in hexes[:12]: # Loop over the coordinates of the upper 3 vertices for index, coord in enumerate(hexTile.vertexCoordinates[:3]): # Check that this is a new vertex coordinate if coord not in vertexCoordsSeen: # Record this vertex position vertexCoordsSeen.append(coord) # Create a new Vertex object at these coordinates newVertex = p.Vertex(coord) # Check that the vertex is not the upper-left vertex of the hex # If not, record that this vertex is adjacent to the previous vertex if index != 0: vertices[-1].adjacentVertices.append(newVertex) newVertex.adjacentVertices.append(vertices[-1]) # Add the vertex to the list of vertices vertices.append(newVertex) # Repeat the loop above for the bottom three rows of hexes for hexTile in hexes[7:]: # Use the lower 3 coordinates here for index, coord in enumerate(hexTile.vertexCoordinates[3:][::-1]): if coord not in vertexCoordsSeen: vertexCoordsSeen.append(coord) newVertex = p.Vertex(coord) if index != 0: vertices[-1].adjacentVertices.append(newVertex) newVertex.adjacentVertices.append(vertices[-1]) vertices.append(newVertex) # Loop through the vertices and relate them to the hexes they touch for vertex in vertices: # For each vertex, look at hex for hexTile in hexes: # Check that the vertex and hex aren't already related but the coordinates match if vertex not in hexTile.vertices and vertex.coordinates in hexTile.vertexCoordinates: # Record the position of the vertex according to the hex's coordinate list verIndex = hexTile.vertexCoordinates.index(vertex.coordinates) # Place the vertex into the hex's vertex list at the same position hexTile.vertices[verIndex] = vertex # Add the hex to the vertex's hex list vertex.hexes.append(hexTile) # If the vertex has 3 hexes in its hex list, no more hexes need to be examined if len(vertex.hexes) == 3: break # Loop through the hexes and relate vertices that are vertically adjacent for hexTile in hexes: if hexTile.vertices[0] not in hexTile.vertices[5].adjacentVertices: hexTile.vertices[0].adjacentVertices.append(hexTile.vertices[5]) hexTile.vertices[5].adjacentVertices.append(hexTile.vertices[0]) if hexTile.vertices[2] not in hexTile.vertices[3].adjacentVertices: hexTile.vertices[2].adjacentVertices.append(hexTile.vertices[3]) hexTile.vertices[3].adjacentVertices.append(hexTile.vertices[2]) # A list of the ports on the map ports = [p.Port([resource], 2) for resource in c.resourceTypes] ports += [p.Port(list(c.resourceTypes), 3) for i in range(4)] # Assign the ports to the appropriate vertices vertices[0].port = ports[5] vertices[1].port = ports[5] ports[5].vertices = [vertices[0], vertices[1]] vertices[3].port = ports[2] vertices[4].port = ports[2] ports[2].vertices = [vertices[3], vertices[4]] vertices[7].port = ports[4] vertices[14].port = ports[6] vertices[15].port = ports[6] ports[6].vertices = [vertices[14], vertices[15]] vertices[17].port = ports[4] ports[4].vertices = [vertices[7], vertices[17]] vertices[26].port = ports[7] vertices[28].port = ports[1] vertices[37].port = ports[7] vertices[38].port = ports[1] ports[7].vertices = [vertices[26], vertices[37]] ports[1].vertices = [vertices[28], vertices[38]] vertices[45].port = ports[3] vertices[46].port = ports[3] ports[3].vertices = [vertices[45], vertices[46]] vertices[47].port = ports[8] vertices[48].port = ports[8] ports[8].vertices = [vertices[47], vertices[48]] vertices[50].port = ports[0] vertices[51].port = ports[0] ports[0].vertices = [vertices[50], vertices[51]] # Create the Robber robber = p.Robber(hexes[c.desertIndex]) # Instantiate a player with their name, color, AI status, and the sizes of their pieces playerList = ui.create_players() # Give the players enough cards to build their first settlements and roads # TODO EDITED THIS TO TEST MARITIME TRADING & BUILDING startingHand = {c.grain: 4, c.wool: 2, c.clay: 4, c.lumber: 4, c.ore: 3} for player in playerList: player.draw_resources(startingHand, resourceDecks) # Shuffle the players to set the turn order random.shuffle(playerList) # Set up the award placards largestArmy = p.LargestArmy(playerList) longestRoad = p.LongestRoad(playerList) # Pygame initialization pygame.init() # opens the window with the size specifications given screen = pygame.display.set_mode(c.screenSize) # sets the font and size comicsansLargeFont = pygame.font.SysFont("comicsansms", 25) # set the font and size for the player key arialSmallFont = pygame.font.SysFont("Arial", 15) pygame.event.set_allowed(None) pygame.event.set_allowed([pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN, pygame.QUIT]) # Create the Player Key playerKey = p.PlayerKey(arialSmallFont, playerList) boardSurface = screen.subsurface((0, 0), c.oceanSize) playerHandSurface = screen.subsurface((c.oceanWidth, 0), (c.gameMenuWidth, 225)) playerHandSurface.fill(c.white) menuSurface = screen.subsurface((c.oceanWidth, 226), (c.gameMenuWidth, c.oceanHeight-226)) menuSurface.fill(c.white) enemyInfoSurface = screen.subsurface((c.oceanWidth + c.gameMenuWidth + 1, 0), (c.gameEventLogWidth - 1, 225)) enemyInfoSurface.fill(c.white) logSurface = screen.subsurface((c.oceanWidth + c.gameMenuWidth + 1, 226), (c.gameEventLogWidth - 1, c.oceanHeight - 226)) logSurface.fill(c.white) # The pygame loop # A flag to track if the board has been drawn boardDrawn = False # A flag to track if the players have built their starting settlements and roads initialSettlementsBuilt = False # A flag to track if a player has won the game gameOver = False while 1: # Draw the key, hexes, odds tiles, and Robber if not boardDrawn: # Set the background color boardSurface.fill(c.oceanBlue) # Draw the player key playerKey.draw(boardSurface) # Loop through the hexes, so that they can be drawn for hexTile in hexes: # Draw the hex pygame.draw.polygon(boardSurface, hexTile.color, hexTile.vertexCoordinates, 0) # Check that the hex is not the desert hex if hexTile.resource != c.desert: # Record the hex's odds tile resourceOdds = str(hexTile.odds) # Set the color of the odds number's text based on the value if resourceOdds == "6" or resourceOdds == "8": label = comicsansLargeFont.render(resourceOdds, 1, c.red) else: label = comicsansLargeFont.render(resourceOdds, 1, c.black) # Place the number on the screen boardSurface.blit(label, hexTile.coordinates) # Draw the Robber robber.draw_robber(boardSurface) # Draw the ports, colored according to their resource for port in ports: portColor = (0, 0, 0) if port.resources != c.resourceTypes: portColor = c.resourceToColor[port.resources[0]] port.draw_port(boardSurface, portColor) # Draw any existing player objects for player in playerList: if player.builtRoads: for road in player.builtRoads: road.draw_road(boardSurface) if player.builtSettlements: for settlement in player.builtSettlements: settlement.draw_settlement(boardSurface) # Update the whole screen in order to show the newly drawn board pygame.display.flip() # Record that the board has been drawn boardDrawn = True # Set up the initial settlements and roads for each player if not initialSettlementsBuilt: print("Each player must build their first settlements and roads.") # Loop through the shuffled player list forwards once and then backwards once # playerList[::-1]: TODO NEED TO CHANGE BACK!!! for player in playerList: # A flag to track whether the player has completed a valid action validAction = False # Give a line break print("") while not validAction: print("For the settlement:") buildResult = build_settlement(player, vertices, resourceDecks, boardSurface, playerKey) if buildResult[0] == 0: validAction = True pygame.display.update() validAction = False # Repeat until the player successfully builds a road while not validAction: print("For the road from that settlement:") buildResult = build_road(player, vertices, longestRoad, resourceDecks, boardSurface, playerKey) if buildResult[0] == 0: validAction = True pygame.display.update() # Record that the players have built the initial 2 settlements and roads initialSettlementsBuilt = True if not gameOver: # Loop through the players to let each take their game turns for player in playerList: print("\n{}, it is now your turn.".format(player.name)) startTurn = None while startTurn is None: startTurn = ui.present_menu(player, c.startMenu, "Ready?", menuSurface, comicsansLargeFont, arialSmallFont) if not startTurn: sys.exit(0) player.count_points() draw_player_hand(player, playerHandSurface, comicsansLargeFont, arialSmallFont) pygame.display.update(playerHandSurface.get_rect()) draw_enemy_info(player, playerList, enemyInfoSurface, arialSmallFont) pygame.display.update(enemyInfoSurface.get_rect()) # Initiate the pre-harvest menu actionChoice = ui.present_menu(player, c.preHarvestMenu, "Pre-Harvest", menuSurface, comicsansLargeFont, arialSmallFont) result = eval(actionChoice) if not isinstance(result, int): player.count_points() draw_player_hand(player, playerHandSurface, comicsansLargeFont, arialSmallFont) draw_enemy_info(player, playerList, enemyInfoSurface, arialSmallFont) result = roll_dice(player) diceResult = result # Check if the roll was a 7, and have the players discards cards and play the Robber if so if diceResult == 7: # Discard cards for players with more than 7 for playerToCheck in playerList: if sum(playerToCheck.cardsInHand.values()) > 7: halve_player_hand(playerToCheck, playerList, resourceDecks, playerHandSurface, menuSurface, enemyInfoSurface, comicsansLargeFont, arialSmallFont) draw_enemy_info(player, playerList, enemyInfoSurface, arialSmallFont) playMade = False while not playMade: # Have the player make a play with the Robber robberPlay = use_robber(player, robber, hexes, boardSurface, playerKey, menuSurface, comicsansLargeFont, arialSmallFont) if robberPlay[0] == 0: playMade = True # Update the screen to show the new location of the Robber pygame.display.update() # Print the result of the player stealing from someone print(robberPlay[1]) else: # Have the players draw their resource cards for playerDrawing in playerList: for settlement in playerDrawing.builtSettlements: playerDrawing.draw_resources(settlement.find_yield(diceResult), resourceDecks) print("{} has {}".format(playerDrawing.name, playerDrawing.cardsInHand)) print("The decks have {}".format(resourceDecks)) turnOver = False while not turnOver: draw_player_hand(player, playerHandSurface, comicsansLargeFont, arialSmallFont) draw_enemy_info(player, playerList, enemyInfoSurface, arialSmallFont) pygame.display.update(playerHandSurface.get_rect()) actionChoice2 = ui.present_menu(player, c.postHarvestMenu, "Post-Harvest", menuSurface, comicsansLargeFont, arialSmallFont) result = eval(actionChoice2) player.count_points() print(result[1]) if result[1] == "Turn is over.": turnOver = True if result[2] >= 10: print("\n{} has won the game with {} points!!".format(player.name, result[3])) gameOver = True if gameOver: break for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit()