def setUp(self): self.player = SillyPlayer(1, [], 0) self.strat = strategy.Strategy() self.carnivore = species.Species(0, 1, 1, []) self.carnivore.setTraits([trait.Trait.carnivore]) self.fat_carnivore = species.Species(0, 1, 1, []) self.fat_carnivore.setTraits([trait.Trait.carnivore]) self.fat_carnivore.setBodySize(5) self.herbavore = species.Species(0, 1, 1, []) self.fat_herbavore = species.Species(0, 1, 1, []) self.fat_herbavore.setBodySize(4) self.fat_tissue = species.Species(0, 1, 1, []) self.fat_tissue.setBodySize(3) self.fat_tissue.setTraits([trait.Trait.fat_tissue]) self.fat_fat_tissue = species.Species(0, 1, 1, []) self.fat_fat_tissue.setBodySize(6) self.fat_fat_tissue.setTraits([trait.Trait.fat_tissue]) self.opherb = species.Species(0, 1, 1, []) self.opfatherb = species.Species(0, 1, 1, []) self.opfatherb.setBodySize(4) self.opponent1 = SillyPlayer(1, [], 0) self.opponent1.setSpeciesBoards([self.opherb, self.opfatherb]) self.opponents = [[self.opherb, self.opfatherb]] self.dealer = dealer.Dealer(4, [self.player, self.opponent1])
def __init__(self, id, bag, speciesList, cards, player=None, info=""): self.num = id self.foodbag = bag self.species = speciesList self.hand = cards self.player = player or SillyPlayer() self.info = info
def parse_playerEx(player_json): """ converts the json representation of a player into a player representation :param player_json: Player+ :return: Player """ try: if len(player_json) == 4: [[i, given_id], [l, los], [b, bag], [c, loc]] = player_json if (i == "id" and l == "species" and b == "bag" and c == "cards"): player = SillyPlayer(given_id, parse_los(los), bag) if loc: player.setHand(parse_loc(loc)) return player else: return player else: [[i, given_id], [l, los], [b, bag]] = player_json if (i == "id" and l == "species" and b == "bag"): return SillyPlayer(given_id, parse_los(los), bag) except ValueError: raise ValueError("invalid player")
def __init__(self, ident, loSpeciesBoard, bag, externalPlayer = None, info = None): """ Initializes a player with a given id, list of species boards, and food bag :param ident: int :param loSpeciesBoard: list of Species :param bag: int greater than 0 :param externalPlayer: a an extenal player (SillyPlayer or ProxyPlayer) :param info: String """ self.species_boards = loSpeciesBoard self.food_bag = bag self.hand = [] self.player_id = ident if externalPlayer: self.externalPlayer = externalPlayer else: self.externalPlayer = SillyPlayer(1, [], 0) if info: self.info = info else: self.info = ""
class PlayerState: num = 0 foodbag = 0 species = [] hand = [] """ Internal representation of a json player @param num: Nat+ representing this player's unique ID number @param foodbag: Nat representing this player's foodbag @param species: A List of this player's Species boards @param hand: A List of TraitCards in this player's hand (not on boards/haven't been traded in) @param player: the external player with strategic functionality Nat, Nat, ListOf(Species), ListOf(TraitCard), Player -> PlayerState """ def __init__(self, id, bag, speciesList, cards, player=None): self.num = id self.foodbag = bag self.species = speciesList self.hand = cards self.player = SillyPlayer() """ override equality Any -> Boolean """ def __eq__(self, other): if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ else: return False """ override inequality Any -> Boolean """ def __ne__(self, other): return not self.__eq__(other) """ start a game (step 1) -- if given a new species, add it, and inform external player of current state @param spec: an OptSpecies (given if this player didn't already have a species; otherwise False) OptSpecies -> Void """ def start(self, spec): if spec is not False: self.species.append(spec) self.player.start(self) """ Do post-turn cleanup: - square up species' populations with what they ate - remove starving species - move food from species boards to player foodbags @return the number of species we removed for being extinct (so that dealer can give us cards) Void -> Nat """ def endOfTurn(self): numExtinct = 0 speciesToRemove = [] for specIdx in range(len(self.species)): self.foodbag += self.species[specIdx].cullStarving() if self.isExtinct(specIdx): speciesToRemove.append(specIdx) numExtinct += 1 self.species = [ self.species[i] for i in range(len(self.species)) if i not in speciesToRemove ] return numExtinct """ Check if an action from our external player would be a cheating move Following conditions must pass: - All card indexes acted on must exist in our hand and be unique - The highest species index referenced should exist after addition of new species boards - Should only be able to replace trait cards that already exist (ie no adding of new trait cards) @param action: the action the external player wishes to take @return the action or, if it was cheating, False Action4 -> Action4 or False """ def checkCheatAction(self, action): if (self.checkLegalCards(action.getAllCardIdcs()) and self.checkLegalSpecies(action.getAllSpecIdcs(), len(action.BT)) and self.checkTraitReplacement(action.RT, action.BT)): return action else: return False """ Check that all species indexes passed correspond to species that the player will own by the end of the action Used to check for cheating in Action4 @param specIdcs: indexes of the species the external player asked to modify @param numBT: the number of BuyTrait actions being requested @return True if moves are legal, False otherwise ListOf(Nat) -> Boolean """ def checkLegalSpecies(self, specIdcs, numBT): return not ((max(specIdcs) > (numBT + len(self.species) - 1)) or (min(specIdcs) < 0)) """ Check that trait replacement uses legal cards and tries to replace existing traits Used to check for cheating in Action4 @param RTs: the ReplaceTrait actions to check @param BTs: the BuySpeciesBoards @return True if moves are legal, False otherwise ListOf(ReplaceTrait) -> Boolean """ def checkTraitReplacement(self, RTs, BTs): for rt in RTs: if (rt.oldTraitIdx < 0) or (rt.specIdx > (len(self.species) + len(BTs) - 1)): return False traitLen = False if rt.specIdx < len(self.species): traitLen = len(self.species[rt.specIdx].traits) elif rt.specIdx < (len(self.species) + len(BTs)): traitLen = len(BTs[rt.specIdx - len(self.species) - 1].traitList) if traitLen is False or rt.oldTraitIdx >= traitLen: return False return True """ Check that the card indexes passed all correspond to cards we own and that each index is unique Used to check for cheating in an Action4 @param cardIdcs: the indexes of the cards the external player asked to use @return True if the moves are legal, False otherwise ListOf(Nat) -> Boolean """ def checkLegalCards(self, cardIdcs): if len(cardIdcs) != len(set(cardIdcs)): # no duplicates return False if (max(cardIdcs) > (len(self.hand) - 1)) or min(cardIdcs) < 0: # only use cards we have return False return True """ Choose actions for watering hole tributes and trading and check for cheating assumption: list of players is ordered such that players before this one in the list play before us, and those after this one in the list play after us @param allPlayers: the states of all players currently in the game @return an Action4 from the external player or, if that move was cheating, False ListOf(PlayerState) -> Action4 or False """ def choose(self, allPlayers): for i in range(len(allPlayers)): if allPlayers[i] is self: splitIdx = i befores = [play.species for play in allPlayers[:splitIdx]] afters = [play.species for play in allPlayers[splitIdx + 1:]] return self.checkCheatAction(self.player.choose(befores, afters)) """ create dictionary None -> Dict """ def toDict(self): return { "num": self.num, "species": [species.toDict() for species in self.species], "hand": [card.toDict() for card in self.hand], "foodbag": self.foodbag } """ Display the essence of a player Void -> Void """ def display(self): Drawing(player=self.toDict()) """ creates a json array of a PlayerState object Void -> JsonArray """ def playerStateToJson(self): species = [Species.speciesToJson(animal) for animal in self.species] cards = [TraitCard.traitCardToJson(card) for card in self.hand] result = [["id", self.num], ["species", species], ["bag", self.foodbag]] if cards: result.append(["cards", cards]) return result """ creates a PlayerState from a json array JsonArray -> PlayerState """ @staticmethod def playerStateFromJson(state): try: cards = [] if state[0][0] == "id": num = state[0][1] if state[1][0] == "species": speciesList = [ Species.speciesFromJson(species) for species in state[1][1] ] if state[2][0] == "bag": bag = state[2][1] if len(state) == 4 and state[3][0] == "cards": cards = [ TraitCard.traitCardFromJson(card) for card in state[3][1] ] if num > 0 and bag >= 0: return PlayerState(num, bag, speciesList, cards) except Exception as e: print state raise e #quit() """ Proxy to call the feed method in the external player @param wateringHole: the amount of food that can be eaten @param players: all the players in this round @return FeedingAction -One of: False - no feeding at this time Nat - index of Species fed [Nat, Nat] - index of fat-tissue Species fed, amount of fatFood [Nat, Nat, Nat] - index of carnivore, index of player to attack, index of species to attack Nat, ListOf(PlayerState) -> FeedingAction """ def feed(self, wateringHole, player): return self.player.feed(self, wateringHole, player) """ Get this player's score -- a combo of their foodbag, total population for all species, and total trait cards placed on species @return the player's score based on the above Void -> Nat """ def getScore(self): score = self.foodbag for spec in self.species: score += spec.population score += len(spec.traits) return score """ Number of cards this player needs dealt at the beginning of a turn Based on their number of species If they have no species, then they should ask for 1 card, as they'll be receiving a new species at the beginning of the round @return num cards needed Void -> Nat """ def numCardsNeeded(self): return 3 + max(1, len(self.species)) """ Filter out all fed species to get a list of species that can be fed @return a list of (Species' index, Species) for hungry species this player has Void -> ListOf((Nat, Species)) """ def getHungrySpecies(self): hungry = [] for i in range(len(self.species)): if self.species[i].isHungry(): hungry.append((i, self.species[i])) return hungry """ Gets the indexes of the species neighboring the given species @param speciesIdx: index of the species to get neighbors for Nat -> [OptSpecies, OptSpecies] where an OptSpecies is Species or False """ def getNeighbors(self, speciesIdx): if speciesIdx > 0: lNeighbor = self.species[speciesIdx - 1] else: lNeighbor = False if speciesIdx < len(self.species) - 1: rNeighbor = self.species[speciesIdx + 1] else: rNeighbor = False return [lNeighbor, rNeighbor] """ Verify that this player can use their own chosen species to attack the other given species @param defPlayer: PlayerState of the defending player @param defIdx: index of the defending species @param attIdx: index of the attacking species: should be one of our own PlayerState, Nat, Nat -> Boolean """ def verifyAttack(self, defPlayer, attIdx, defIdx): left, right = defPlayer.getNeighbors(defIdx) return Species.isAttackable(defPlayer.species[defIdx], self.species[attIdx], left, right) """ Tell whether or not the given species is extinct (i.e. that its population <= 0) @param specIdx: index of the species to check Nat -> Boolean """ def isExtinct(self, specIdx): return self.species[specIdx].isExtinct() """ Add one population to a species at the given index @param specIdx: index of the species to modify Nat -> Void """ def addPopulation(self, specIdx): self.species[specIdx].addPopulation() """ Add one body size to a species at the given index @param specIdx: index of the species to modify Nat -> Void """ def addBody(self, specIdx): self.species[specIdx].addBody() """ Give this player a new species with the given traits @param traitIdcs: indices of the trait cards this new species will have, up to 3 ListOf(Nat) -> Void """ def addSpecies(self, traitIdcs): self.species.append( Species(0, 0, 1, [self.hand[i] for i in traitIdcs], 0)) """ Remove the given species from this player's list of species @param specIdx: index of the species to remove Nat -> Void """ def removeSpecies(self, specIdx): del self.species[specIdx] """ Tell whether or not this player has any species Void -> Boolean """ def hasNoSpecies(self): return not (len(self.species) > 0) """ Deletes the cards at the given indices from this player's hand @param cardIdcs: the indexes of the cards to remove ListOf(Nat) -> Void """ def discardFromHand(self, cardIdcs): self.hand = [ self.hand[i] for i in range(len(self.hand)) if i not in cardIdcs ] """ Adds the given TraitCards to the end of this player's hand @param cards: the cards to add ListOf(TraitCard) -> Void """ def addCards(self, cards): self.hand = cards + self.hand """ Tell whether the species at the given index has the given trait @param specIdx: the index of the species to check @param traitName: the name of the trait to check for Nat, String -> Boolean """ def speciesHasTrait(self, specIdx, traitName): return self.species[specIdx].hasTrait(traitName) """ Drop the population of the given species as in a carnivore attack If the species' food > its population, drop the food as well @param specIdx: the index of the species to have its population decremented Nat -> Void """ def executeAttack(self, specIdx): self.species[specIdx].executeAttack() """ Feed the given species the given amount of fat food that it requested @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @return the amount of food this species was given Nat, Nat -> Nat """ def feedFatFood(self, specIdx, foodCount): spec = self.species[specIdx] if spec.hasTrait("fat-tissue"): foodCount = min(foodCount, spec.body - spec.fatFood) spec.eatFatFood(foodCount) return foodCount else: raise ValueError( "Tried to feed fat food to a species without fat tissue") """ Feed a given species the amount of food that it requested @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @param wateringHole: the amount of food in the dealer's watering hole @return the total amount of food eaten during this feeding Nat, Nat, Nat -> Nat """ def feedSpecies(self, specIdx, foodCount, wateringHole): spec = self.species[specIdx] foodCount = min(wateringHole, foodCount, spec.population - spec.food) spec.eatFood(foodCount) wateringHole -= foodCount forageAmount = self.forage(specIdx, wateringHole) wateringHole -= forageAmount foodCount += forageAmount foodCount += self.cooperate(specIdx, foodCount, wateringHole) return foodCount # TODO: abstract everything. all of it """ If the given species has the foraging trait, give it one more food @param specIdx: index of the species to feed @param wateringHole: the amount of food in the dealer's watering hole @return the amount of food this species ate """ def forage(self, specIdx, wateringHole): spec = self.species[specIdx] amountFed = 0 if wateringHole > 0 and spec.hasTrait( "foraging") and spec.population > spec.food: spec.eatFood(1) amountFed += 1 return amountFed """ Cooperate @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @param wateringHole: the amount of food in the dealer's watering hole @return the amount of food all species in the cooperation chain ate Nat, Nat, Nat -> Nat """ def cooperate(self, specIdx, foodCount, wateringHole): spec = self.species[specIdx] amountFed = 0 left, right = self.getNeighbors(specIdx) if spec.hasTrait("cooperation") and right is not False: for i in range(foodCount): if wateringHole > 0: fedThisSpecies = self.feedSpecies(specIdx + 1, 1, wateringHole) amountFed += fedThisSpecies wateringHole -= fedThisSpecies return amountFed """ After a carnivore attack, have all species with the scavenge trait eat from left to right @param wateringHole: the amount of food that can be handed out amongst the scavengers @return the amount of food eaten amongst our scavengers Nat -> Nat """ def scavenge(self, wateringHole): amountFed = 0 scavengers = self.getSpeciesWithTrait("scavenger") for scav in scavengers: if wateringHole > 0: fedThisSpecies = self.feedSpecies(scav, 1, wateringHole) amountFed += fedThisSpecies wateringHole -= fedThisSpecies return amountFed """ Get all species this player owns that has the given trait @param trait: the name of the trait to be checked String -> ListOf(SpecIdx) """ def getSpeciesWithTrait(self, trait): return [ i for i in range(len(self.species)) if self.speciesHasTrait(i, trait) ] """ Give all fertile species this player owns one population Void -> Void """ def fertile(self): fertile = self.getSpeciesWithTrait("fertile") for spec in fertile: self.species[spec].addPopulation() """ Give all long-necked species this player owns one food, as long as the watering hole is large enough to feed them @param wateringHole: the dealer's watering hole @return the amount of food eaten by the longnecks Nat -> Nat """ def longNeck(self, wateringHole): amountFed = 0 longNeck = self.getSpeciesWithTrait("long-neck") for ln in longNeck: if wateringHole > 0: fedThisSpecies = self.feedSpecies(ln, 1, wateringHole) amountFed += fedThisSpecies wateringHole -= fedThisSpecies return amountFed """ Transfer fat food that a species stored last turn to its actual food Void -> Void """ def transferFatFood(self): fatTissue = self.getSpeciesWithTrait("fat-tissue") for ft in fatTissue: self.species[ft].transferFatFood() """ Replace a TraitCard on the given species @param specIdx: the index of the species whose traits need switched out @param oldTraitIdx: the index of the old trait card @param newTraitIdx: the index of the trait card replacing the old one Nat, Nat, Nat -> Void """ def replaceTrait(self, specIdx, oldTraitIdx, newTraitIdx): self.species[specIdx].replaceTrait(oldTraitIdx, self.hand[newTraitIdx])
def __init__(self, id, bag, speciesList, cards, player=None): self.num = id self.foodbag = bag self.species = speciesList self.hand = cards self.player = SillyPlayer()
class Player: species_boards = [] food_bag = 0 hand = [] player_id = 0 externalPlayer = None def __init__(self, ident, loSpeciesBoard, bag, externalPlayer = None, info = None): """ Initializes a player with a given id, list of species boards, and food bag :param ident: int :param loSpeciesBoard: list of Species :param bag: int greater than 0 :param externalPlayer: a an extenal player (SillyPlayer or ProxyPlayer) :param info: String """ self.species_boards = loSpeciesBoard self.food_bag = bag self.hand = [] self.player_id = ident if externalPlayer: self.externalPlayer = externalPlayer else: self.externalPlayer = SillyPlayer(1, [], 0) if info: self.info = info else: self.info = "" def getInfo(self): """ gets the info field in this player :return: String """ return self.info def setSpeciesBoards(self, loSpeciesBoard): """ sets the list of species of this player to the given list of species :param loSpeciesBoard: [Species, ...] """ self.species_boards = loSpeciesBoard def getSpeciesBoards(self): """ gets the list of species of this player :return: [Species, ...] """ return self.species_boards def addSpeciesBoard(self, board): """ adds the species board to the player list of species :board: Species """ self.species_boards.append(board) def setFoodBag(self, fb): """ sets the food bag of the player to the given value :param fb: int """ self.food_bag = fb def getFoodBag(self): """ gets the food bag of this player :return: int """ return self.food_bag def addToFoodBag(self, tokens): """ adds points (tokens) to the food bag :param tokens: int """ self.food_bag += tokens def setHand(self, cards): """ sets the hand of the player to the given cards :param cards: [TraitCard, ...] """ self.hand = cards def getHand(self): """ gets the hand of the player :return: [TraitCard, ...] """ return self.hand def getExternalPlayer(self): """ get the external player of this internal player :return: SillyPlayer or ProxyPlayer """ return self.externalPlayer def addToHand(self, cards): """ adds the given cards to this player's hand :param cards: [TraitCard, ...] """ self.hand.extend(cards) def giveCard(self, i): """ returns the card at the given index & deletes the card :param i: int that represents an index of a card in the players hand :return: TraitCard """ if i in range(len(self.getHand())): card = self.getHand()[i] else: card = self.getHand()[len(self.getHand())-1] return card def removeCardsFromHand(self, loc): """ removes a the cards from this player's hand :param loc: [TraitCard, ...] :effect: modifies this player's hand """ for card in loc: if card in self.getHand(): self.getHand().remove(card) def setPlayerId(self, ident): """ sets the id of this player to the given ident """ self.player_id = ident def getPlayerId(self): """ gets the player's id :return: int """ return self.player_id def getSpeciesByIndex(self, i): """ gets the species from the players list of species by index :param i: int :return: Species """ return self.species_boards[i] def moveFatToFood(self): """ Moves the fat from the fat food species to food """ for animal in self.getSpeciesBoards(): if animal.hasTrait(trait.Trait.fat_tissue): animal.moveFatFood() def removeSpeciesInLOS(self, species_index): """ removes the species from the list of species in this player :param species: int which is the index of the species in the player species """ species = self.getSpeciesByIndex(species_index) self.species_boards.remove(species) def getHungrySpeciesIndexes(self): """ gets the hungry species of this player :return: [int, ...] which represents the indexes of the hungry species """ player_species = self.getSpeciesBoards() hungry_species_indexes = [] for i in range(len(player_species)): if player_species[i].isHungry(): hungry_species_indexes.append(i) return hungry_species_indexes def increaseSpeciesPopulation(self, species_index, amount): """ increased the population of the species at the given index :param species_index: int """ species = self.getSpeciesByIndex(species_index) species.addToPopulation(amount) def increaseSpeciesBody(self, species_index, amount): """ increased the population of the species at the given index :param species_index: int """ species = self.getSpeciesByIndex(species_index) species.addToBody(amount) def reduceSpeciesPopulation(self, species_index, amount): """ reduces the population of the species at the given index by the given ammount :param species_index: an int representing the index of one of this player's species :param amount: an int less then the population of the given species :return: Boolean """ species = self.getSpeciesByIndex(species_index) return species.reducePopulation(amount) def starveSpecies(self): """ makes the player's species have the population equal to the amount of food the species consumed :return: int """ deletedSpecies = 0 for sp in self.getSpeciesBoards(): if not sp.starve(): self.getSpeciesBoards().remove(sp) deletedSpecies += 1 return deletedSpecies def moveFoodToBag(self): """ moves the food from the species to the player's food bag """ food = 0 for sp in self.getSpeciesBoards(): food += sp.getFood() sp.setFood(0) self.setFoodBag(food) def addSpecies(self, species, bt): """ Adds the traits to the given species and appends that species to the end of the species list :param species: a species board :param bt: a list of indexes corresponding to trait cards in this player's hand :return: [TraitCard, ...] """ cards_to_discard = [] card = self.giveCard(bt[0]) cards_to_discard.append(card) for index_card in bt[1:]: card2 = self.giveCard(index_card) trait_to_add = card2.getTrait() species.addTrait(trait_to_add) cards_to_discard.append(card2) self.addSpeciesBoard(species) return cards_to_discard def replaceTrait(self, species_index, trait_index, card_index): """ replaces the trait of the species with the given :param species_index: int :param trait_index: int :param card_index: int :return: TraitCard """ species = self.getSpeciesByIndex(species_index) card = self.giveCard(card_index) trait_changed = card.getTrait() species.replaceTrait(trait_index, trait_changed) return card def grow(self, species_index, card_index, funct): """ applies the given function on the species index :param species_index: int :param card_index: int :param funct: a function that takes in 2 numbers :return: TraitCard """ card = self.giveCard(card_index) funct(species_index, 1) return card def apply_list(self, applylist, funct2): """ adds the _ of the given species and discards the appropraite card :param applylist: [[String, int, int], ...] where the first is the index of species the second the index of the card :param funct2: a function that takes in 2 numbers :return: [TraitCard, ...] """ cards_to_discard = [] for g in applylist: [index_species, index_card] = g card = self.grow(index_species, index_card, funct2) cards_to_discard.append(card) return cards_to_discard def apply_rt_list(self, rt_list): """ replaces the traits for the given species :param rt_list: [RT, ...] :return: [TraitCard, ...] """ cards_to_discard = [] for rt in rt_list: [species_index, trait_index, card_index] = rt card = self.replaceTrait(species_index, trait_index, card_index) cards_to_discard.append(card) return cards_to_discard def apply_action(self, player_action): """ applies the appropriate actions :player_action: PlayerAction :return: [TraitCard, ...] """ gp_list, gb_list, rt_list = player_action cards_to_discard = self.apply_rt_list(rt_list) cards_to_discard.extend(self.apply_list(gp_list, self.increaseSpeciesPopulation)) cards_to_discard.extend(self.apply_list(gb_list, self.increaseSpeciesBody)) return cards_to_discard def canFeed(self): """ Checks if the call to feed follows the sequencing constraints throws an error if it doesn't match specs Returns: A boolean regarding if this player can feed a species or not """ #checks if there are not enough species boards if (len(self.species_boards) != 0): #checks if there are an appropraite number of hungry animals hunger = False for animal in self.species_boards: if animal.getPopulation() > animal.getFood(): hunger = True elif (animal.hasTrait(trait.Trait.fat_tissue) and (animal.getBodySize() > animal.getFatFood())): hunger = True return hunger return False def start(self, w, b, c): """ add the given cards and the species board to the player and then tells the external player about the change :param w: int :param b: Species :param c: [TraitCard, ...] """ if b: self.addSpeciesBoard(b) self.addToHand(c) t = [w, self.getFoodBag(), self.getSpeciesBoards(), self.getHand()] self.externalPlayer.start(t) def choose(self, s): """ queries the external player for its choice of using it's cards :param s: [[[Species, ...], ...], [[Species, ...], ...]] :return: Action4 """ action = self.externalPlayer.choose(s[0], s[1]) if validate.validateAction4(action, self): return action else: return "delete" def feedNext(self, wateringHole, lolos): """ queries the external player for its choice of which species to feed next :param wateringHole: int :param lop: [Player, ...] not containing this player :return: one of -False (if a player can't feed any species) -the index of a species in self.species_boards, -[the index of a species in self.species_boards with the trait fat_tissue, Nat] -[the index of a species in self.species_boards with the trait carnivore, the index of the player in the given list of players, and the index of an attackable species owned by the prior player] """ if (not self.canFeed()): return None feedingChoice = self.externalPlayer.feedNext(wateringHole, lolos, [self.getFoodBag(), self.getSpeciesBoards(), self.getHand()]) if validate.validateFeedingChoice(feedingChoice, self, lolos, wateringHole): return feedingChoice else: return "delete" def calculateScore(self): """ calculates the score of this player :return: int """ score = self.getFoodBag() for sp in self.getSpeciesBoards(): score += sp.getPopulation() score += len(sp.getTraits()) return score def player_strings(self): """ returns the strings reperesentations of the fields in this player :return: [String, [String, ...], [String, ...]] """ this_id = self.getPlayerId() this_food_bag = self.getFoodBag() this_hand = self.getHand() this_species = self.getSpeciesBoards() id_food_bag_string = "Player: " + "id: " + str(this_id) + ", food bag: " + str(this_food_bag) species_strings = [] for species in this_species: species_strings.append(species.display_species()) hand_strings = [] if this_hand: for card in this_hand: hand_strings.append(card.display_card()) return [id_food_bag_string, species_strings, hand_strings] def sortCards(self): sortedHand = sorted(self.getHand(), cmp = deck.compareTraitCard, reverse = True) return sortedHand
class PlayerState: num = 0 foodbag = 0 species = [] hand = [] """ Internal representation of a json player @param num: ID number @param foodbag: yep @param species: this player's species boards @param hand: traitcards in this player's hand (not on boards/haven't been traded in) @param player: the external player with strategic functionality Nat, Nat, ListOf(Species), ListOf(TraitCard), Player -> PlayerState """ def __init__(self, id, bag, speciesList, cards, player=None): self.num = id self.foodbag = bag self.species = speciesList self.hand = cards self.player = SillyPlayer() """ override equality Any -> Boolean """ def __eq__(self, other): if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ else: return False """ override inequality Any -> Boolean """ def __ne__(self, other): return not self.__eq__(other) """ create dictionary None -> Dict """ def toDict(self): return { "num": self.num, "species": [species.toDict() for species in self.species], "hand": [card.toDict() for card in self.hand], "foodbag": self.foodbag } """ Display the essence of a player Void -> Void """ def display(self): Drawing(player=self.toDict()) """ creates a json array of a PlayerState object Void -> JsonArray """ def playerStateToJson(self): species = [Species.speciesToJson(animal) for animal in self.species] cards = [TraitCard.traitCardToJson(card) for card in self.hand] result = [["id", self.num], ["species", species], ["bag", self.foodbag]] if cards: result.append(["cards", cards]) return result """ creates a PlayerState from a json array JsonArray -> PlayerState """ @staticmethod def playerStateFromJson(state): try: cards = [] if state[0][0] == "id": num = state[0][1] if state[1][0] == "species": speciesList = [ Species.speciesFromJson(species) for species in state[1][1] ] if state[2][0] == "bag": bag = state[2][1] if len(state) == 4 and state[3][0] == "cards": cards = [ TraitCard.traitCardFromJson(card) for card in state[3][1] ] if num > 0 and bag >= 0: return PlayerState(num, bag, speciesList, cards) except: quit() """ Proxy to call the feed method in the external player @param wateringHole: the amount of food that can be eaten @param players: all the players in this round @return FeedingAction -One of: False - no feeding at this time Nat - index of Species fed [Nat, Nat] - index of fat-tissue Species fed, amount of fatFood [Nat, Nat, Nat] - index of carnivore, index of player to attack, index of species to attack Nat, ListOf(PlayerState) -> FeedingAction """ def feed(self, wateringHole, player): return self.player.feed(self, wateringHole, player) """ Filter out all fed species to get a list of species that can be fed @return a list of (Species' index, Species) for hungry species this player has Void -> ListOf((Nat, Species)) """ def getHungrySpecies(self): hungry = [] for i in range(len(self.species)): if self.species[i].isHungry(): hungry.append((i, self.species[i])) return hungry """ Gets the indexes of the species neighboring the given species @param speciesIdx: index of the species to get neighbors for Nat -> [OptSpecies, OptSpecies] where an OptSpecies is Species or False """ def getNeighbors(self, speciesIdx): if speciesIdx > 0: lNeighbor = self.species[speciesIdx - 1] else: lNeighbor = False if speciesIdx < len(self.species) - 1: rNeighbor = self.species[speciesIdx + 1] else: rNeighbor = False return [lNeighbor, rNeighbor] """ Verify that this player can use their own chosen species to attack the other given species @param defPlayer: PlayerState of the defending player @param defIdx: index of the defending species @param attIdx: index of the attacking species: should be one of our own PlayerState, Nat, Nat -> Boolean """ def verifyAttack(self, defPlayer, attIdx, defIdx): left, right = defPlayer.getNeighbors(defIdx) return Species.isAttackable(defPlayer.species[defIdx], self.species[attIdx], left, right) """ Tell whether or not the given species is extinct (i.e. that its population <= 0) @param specIdx: index of the species to check Nat -> Boolean """ def isExtinct(self, specIdx): return self.species[specIdx].isExtinct() """ Remove the given species from this player's list of species @param specIdx: index of the species to remove Nat -> Void """ def removeSpecies(self, specIdx): del self.species[specIdx] """ Tell whether or not this player has any species Void -> Boolean """ def hasNoSpecies(self): return not (len(self.species) > 0) """ Tell whether the species at the given index has the given trait @param specIdx: the index of the species to check @param traitName: the name of the trait to check for Nat, String -> Boolean """ def speciesHasTrait(self, specIdx, traitName): return self.species[specIdx].hasTrait(traitName) """ Drop the population of the given species as in a carnivore attack If the species' food > its population, drop the food as well @param specIdx: the index of the species to have its population decremented Nat -> Void """ def executeAttack(self, specIdx): self.species[specIdx].executeAttack() """ Feed the given species the given amount of fat food that it requested @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @return the amount of food this species was given Nat, Nat -> Nat """ def feedFatFood(self, specIdx, foodCount): spec = self.species[specIdx] if spec.hasTrait("fat-tissue"): foodCount = min(foodCount, spec.body - spec.fatFood) spec.eatFatFood(foodCount) return foodCount else: raise ValueError( "Tried to feed fat food to a species without fat tissue") """ Feed a given species the amount of food that it requested @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @param wateringHole: the amount of food in the dealer's watering hole @return the total amount of food eaten during this feeding Nat, Nat, Nat -> Nat """ def feedSpecies(self, specIdx, foodCount, wateringHole): spec = self.species[specIdx] foodCount = min(wateringHole, foodCount, spec.population - spec.food) spec.eatFood(foodCount) wateringHole -= foodCount forageAmount = self.forage(specIdx, wateringHole) wateringHole -= forageAmount foodCount += forageAmount foodCount += self.cooperate(specIdx, foodCount, wateringHole) return foodCount """ If the given species has the foraging trait, give it one more food @param specIdx: index of the species to feed @param wateringHole: the amount of food in the dealer's watering hole @return the amount of food this species ate """ def forage(self, specIdx, wateringHole): spec = self.species[specIdx] amountFed = 0 if wateringHole > 0 and spec.hasTrait( "foraging") and spec.population > spec.food: spec.eatFood(1) amountFed += 1 return amountFed """ Cooperate @param specIdx: index of the species to feed @param foodCount: amount of food to try to feed @param wateringHole: the amount of food in the dealer's watering hole @return the amount of food all species in the cooperation chain ate Nat, Nat, Nat -> Nat """ def cooperate(self, specIdx, foodCount, wateringHole): spec = self.species[specIdx] amountFed = 0 left, right = self.getNeighbors(specIdx) if spec.hasTrait("cooperation") and right is not False: for i in range(foodCount): if wateringHole > 0: fedThisSpecies = self.feedSpecies(specIdx + 1, 1, wateringHole) amountFed += fedThisSpecies wateringHole -= fedThisSpecies return amountFed """ After a carnivore attack, have all species with the scavenge trait eat from left to right @param wateringHole: the amount of food that can be handed out amongst the scavengers @return the amount of food eaten amongst our scavengers Nat -> Nat """ def scavenge(self, wateringHole): amountFed = 0 for i in range(len(self.species)): if self.speciesHasTrait(i, "scavenger"): fedThisSpecies = self.feedSpecies(i, 1, wateringHole) amountFed += fedThisSpecies wateringHole -= fedThisSpecies return amountFed
class TestStrategy(unittest.TestCase): def setUp(self): self.player = SillyPlayer(1, [], 0) self.strat = strategy.Strategy() self.carnivore = species.Species(0, 1, 1, []) self.carnivore.setTraits([trait.Trait.carnivore]) self.fat_carnivore = species.Species(0, 1, 1, []) self.fat_carnivore.setTraits([trait.Trait.carnivore]) self.fat_carnivore.setBodySize(5) self.herbavore = species.Species(0, 1, 1, []) self.fat_herbavore = species.Species(0, 1, 1, []) self.fat_herbavore.setBodySize(4) self.fat_tissue = species.Species(0, 1, 1, []) self.fat_tissue.setBodySize(3) self.fat_tissue.setTraits([trait.Trait.fat_tissue]) self.fat_fat_tissue = species.Species(0, 1, 1, []) self.fat_fat_tissue.setBodySize(6) self.fat_fat_tissue.setTraits([trait.Trait.fat_tissue]) self.opherb = species.Species(0, 1, 1, []) self.opfatherb = species.Species(0, 1, 1, []) self.opfatherb.setBodySize(4) self.opponent1 = SillyPlayer(1, [], 0) self.opponent1.setSpeciesBoards([self.opherb, self.opfatherb]) self.opponents = [[self.opherb, self.opfatherb]] self.dealer = dealer.Dealer(4, [self.player, self.opponent1]) def tearDown(self): del self.player del self.carnivore del self.herbavore del self.fat_tissue del self.opherb del self.opfatherb del self.opponent1 del self.opponents del self.dealer def testFatTissueFirst(self): self.player.setSpeciesBoards([self.herbavore, self.fat_tissue]) self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), [1, 3]) def testBiggestFatTissueFirst(self): self.player.setSpeciesBoards([self.fat_tissue, self.fat_fat_tissue]) self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), [1, 4]) def testHerbBeforeCarni(self): self.player.setSpeciesBoards([self.herbavore, self.carnivore]) self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), 0) def testLargestHerbFirst(self): self.player.setSpeciesBoards([self.herbavore, self.fat_herbavore]) self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), 1) def testLargestCarnivoreFirstIfAllHerbFed(self): self.herbavore.setFood(1) self.player.setSpeciesBoards([self.herbavore, self.carnivore, self.fat_carnivore]) self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), [2, 0, 1]) def testWontAttackSelf(self): self.player.setSpeciesBoards([self.fat_carnivore]) self.opponents = [] self.assertEqual(self.player.feedNext(4, self.opponents, [self.player.getFoodBag(), self.player.getHand(), self.player.getSpeciesBoards()]), False) # #Unit Test Helper Methods def testSortByLexPop(self): self.herbavore.setPopulation(1) self.carnivore.setPopulation(3) loa = [self.herbavore, self.carnivore] self.assertEqual(self.strat.sortByLex(loa, False), [self.carnivore, self.herbavore]) def testSortByLexFood(self): self.herbavore.setPopulation(1) self.carnivore.setPopulation(1) self.herbavore.setFood(1) self.carnivore.setFood(3) loa = [self.carnivore, self.herbavore] self.assertEqual(self.strat.sortByLex(loa, False), [self.carnivore, self.herbavore]) def testSortByLexBodySize(self): self.herbavore.setPopulation(1) self.carnivore.setPopulation(1) self.herbavore.setFood(1) self.carnivore.setFood(1) self.herbavore.setBodySize(1) self.carnivore.setBodySize(3) loa = [self.carnivore, self.herbavore] self.assertEqual(self.strat.sortByLex(loa, False), [self.carnivore, self.herbavore]) def testSortByLex(self): self.herbavore.setPopulation(1) self.herbavore.setFood(1) self.herbavore.setBodySize(3) self.carnivore.setPopulation(2) self.carnivore.setFood(1) self.carnivore.setBodySize(2) self.fat_tissue.setPopulation(1) self.fat_tissue.setFood(2) self.fat_tissue.setBodySize(3) loa = [self.herbavore, self.carnivore, self.fat_tissue] loas = self.strat.sortByLex(loa, False) self.assertEqual(loas, [self.carnivore, self.fat_tissue, self.herbavore]) def testStereotypeAnimals(self): loa = [self.fat_herbavore, self.herbavore, self.fat_carnivore, self.fat_tissue] expectedOutput = ([self.fat_tissue], [self.fat_carnivore], [self.fat_herbavore, self.herbavore]) self.assertEqual(self.strat.stereotypeAnimals(loa), expectedOutput) def testFindFattestIfFatTissue(self): fat = [self.fat_tissue] carni = [self.fat_carnivore] herb = [self.fat_herbavore, self.herbavore] self.assertEqual(self.strat.findFattest(fat, carni, herb), (self.fat_tissue, trait.Trait.fat_tissue)) def testFindFattestIfHerbi(self): fat = [] carni = [self.fat_carnivore] herb = [self.fat_herbavore, self.herbavore] self.assertEqual(self.strat.findFattest(fat, carni, herb), (self.fat_herbavore, False)) def testFindFattestIfCarni(self): fat = [] carni = [self.fat_carnivore] herb = [] self.assertEqual(self.strat.findFattest(fat, carni, herb), (self.fat_carnivore, trait.Trait.carnivore)) def testFeedNext(self): loa = [self.fat_herbavore, self.herbavore, self.fat_carnivore, self.fat_tissue] self.assertEqual(self.strat.feedNext(loa), (self.fat_tissue, trait.Trait.fat_tissue)) def testSortOpponentsSpecies(self): inpt = [[self.herbavore, self.fat_tissue], [self.opherb, self.opfatherb]] output = [[self.fat_tissue, self.herbavore] , [self.opfatherb, self.opherb]] self.assertEqual(self.strat.sortOpponentsSpecies(inpt), output) def testGetNeighborsNoLeft(self): self.assertEqual(self.strat.getNeighbors([self.herbavore, self.fat_tissue], self.fat_tissue), (self.herbavore, False)) def testGetNeighborsNoRight(self): self.assertEqual(self.strat.getNeighbors([self.herbavore, self.fat_tissue], self.herbavore), (False, self.fat_tissue)) def testPickVictim(self): self.assertEqual(self.strat.pickVictim([self.carnivore], [[self.herbavore, self.fat_tissue], [self.opherb, self.opfatherb]]), [1, 1 , self.carnivore])
def setUp(self): self.t1 = TraitCard("horns", 3) self.t2 = TraitCard("ambush", 1) self.t3 = TraitCard("carnivore", 2) self.t4 = TraitCard("fat-tissue", 0) self.t5 = TraitCard("foraging", 3) self.vegHorns = Species(1, 2, 3, [TraitCard("horns")], 0) self.vegCoop = Species(1, 2, 3, [TraitCard("cooperation")], 0) self.fat = Species(4, 3, 4, [TraitCard("fat-tissue")], 3) self.fatScav = Species( 2, 3, 4, [TraitCard("fat-tissue"), TraitCard("scavenger")], 1) self.fatFor = Species(4, 3, 4, [TraitCard("fat-tissue"), TraitCard("foraging")], 1) self.carnCoop = Species( 3, 4, 5, [TraitCard("carnivore"), TraitCard("cooperation")], 0) self.carnForage = Species( 3, 4, 5, [TraitCard("carnivore"), TraitCard("foraging")], 0) self.carnForage1 = Species( 3, 4, 5, [TraitCard("carnivore"), TraitCard("foraging")], 0) self.extinct = Species(0, 0, 0, [], 0) self.p1 = PlayerState(1, 0, [self.vegCoop, self.fat, self.carnForage], [], SillyPlayer()) self.p2 = PlayerState(2, 0, [self.vegHorns, self.fatScav, self.carnCoop], [], SillyPlayer()) self.p3 = PlayerState(3, 0, [self.vegCoop, self.carnCoop, self.carnForage1], [], SillyPlayer()) self.p4 = PlayerState(4, 0, [self.vegCoop], []) self.p5 = PlayerState(5, 0, [self.vegHorns], []) self.p6 = PlayerState(6, 0, [self.carnCoop], []) self.p7 = PlayerState(7, 0, [self.fatScav], []) self.p8 = PlayerState(8, 0, [self.fatFor, self.extinct], []) self.dealer = Dealer([self.p1, self.p2, self.p3], 3, [self.t1, self.t2, self.t3, self.t4, self.t5]) self.p2dealer = Dealer([self.p6, self.p5], 3, []) self.p3dealer = Dealer([self.p8], 3, [self.t1, self.t2, self.t3, self.t4, self.t5]) self.xstep3spec = Species(0, 5, 2, [TraitCard("foraging")], 0) self.xstep3p = PlayerState(1, 0, [self.xstep3spec], []) self.xstep3deal = Dealer([self.xstep3p], 5, []) # 8949-0357-4 self.pCFS1 = PlayerState(1, 3, [ Species(4, 2, 5, [TraitCard("carnivore"), TraitCard("cooperation")], 0), Species(1, 3, 4, [ TraitCard("foraging"), TraitCard("carnivore"), TraitCard("scavenger") ], 0) ], []) self.pCFS2 = PlayerState( 2, 4, [Species(2, 3, 3, [TraitCard("burrowing")], 0)], []) self.pCFS3 = PlayerState(3, 5, [], []) self.dCFS = Dealer([self.pCFS1, self.pCFS2, self.pCFS3], 10, []) # for step4 self.t6 = TraitCard("herding", 0) self.defSpec = Species(0, 0, 1, [], 0) self.specWGrownBody = Species(0, 1, 1, [], 0) self.specW3t = Species(0, 0, 1, [self.t3, self.t4, self.t5], 0) self.specWAll = Species(2, 1, 2, [self.t4], 1) self.playerWithManyCards = PlayerState( 1, 0, [], [self.t1, self.t2, self.t3, self.t4, self.t5, self.t6]) self.playerForAll = PlayerState(1, 0, [self.specWAll], []) self.playerFor3t = PlayerState(1, 0, [self.specW3t], [self.t6]) self.playerForDefSpec = PlayerState(1, 0, [self.defSpec], [self.t5, self.t6]) self.playerForBodyNewSpec = PlayerState( 1, 0, [self.specWGrownBody], [self.t3, self.t4, self.t5, self.t6]) self.noAct = Action4(0, [], [], [], []) self.actGP = Action4(0, [GainPopulation(0, 0)], [], [], []) self.actGB = Action4(0, [], [GainBodySize(0, 1)], [], []) self.actRT = Action4(0, [], [], [], [ReplaceTrait(0, 1, 1)]) self.actBT0t = Action4(0, [], [], [BuySpeciesBoard(1, [])], []) self.actBT1t = Action4(0, [], [], [BuySpeciesBoard(1, [2])], []) self.actBT2t = Action4(0, [], [], [BuySpeciesBoard(1, [2, 3])], []) self.actBT3t = Action4(0, [], [], [BuySpeciesBoard(1, [2, 3, 4])], []) self.actBT4t = Action4(0, [], [], [BuySpeciesBoard(1, [2, 3, 4, 5])], []) self.addBodyToNewSpec = Action4(0, [GainPopulation(1, 1)], [], [BuySpeciesBoard(2, [3])], []) self.actAll = Action4(0, [GainPopulation(0, 1)], [GainBodySize(0, 2)], [BuySpeciesBoard(4, [5])], [ReplaceTrait(0, 0, 3)]) self.simpleDealerForStep4 = Dealer([self.playerWithManyCards], 0, []) self.dealerForRevokingCards = Dealer([ PlayerState(1, 0, [], [self.t1, self.t2]), PlayerState(2, 0, [], [self.t3, self.t4, self.t5]), PlayerState(3, 0, [], [self.t6]) ], 0, []) self.dealerManyActions = Dealer([ PlayerState(1, 0, [self.defSpec], [self.t1, self.t2]), PlayerState(2, 0, [self.vegHorns, self.fatScav, self.carnCoop], [self.t3, self.t4, self.t5, self.t6, self.t1]), PlayerState(3, 0, [self.vegCoop, self.carnCoop, self.carnForage1], [self.t6]) ], 0, [])
def new(self, pid): """ add a player to this proxyDealer :param pid: int """ self.externalPlayer = SillyPlayer(pid, [], 0)
class ProxyDealer: def __init__(self): self.sock = None #self.streamer = xstream.EchoStream() self.proxyPlayer = None self.externalPlayer = None # SillyPlayer(9, [], 0) self.gotOK = False def receiveData(self): data = None try: data = self.sock.recv(SIZE) return data except socket.error: return data def disconnect(self): self.sock.close() def getExternalPlayer(self): return self.externalPlayer def signUp(self, s): """ send a massage to the server in order to join the game :param s: String """ self.sock.sendall(json.dumps(s)) def new(self, pid): """ add a player to this proxyDealer :param pid: int """ self.externalPlayer = SillyPlayer(pid, [], 0) def start(self, s): """ intializes the externalPlayer :param s: [int, int, [Species_j+, ...], [SpeciesCard, ...]] :effect: calls the start method of the external player """ t = parse_json.parse_s(s) self.externalPlayer.start(t) # self.sock.sendall(json.dumps("ok")) def choose(self, cdj): """ asks the external player how it chooses the cards :param cdj: [[[Species_j+, ...], ...], [[Species_j+, ...], ...]] :effect: calls the choose method of the external player :return: Action4 """ c, d = parse_json.parse_cdj(cdj) action4 = self.externalPlayer.choose(c, d) self.sock.sendall(json.dumps(action4)) def feedNext(self, zs): """ asks the external player what species to feed next :param zs: [int, [Species_j+, ...], [SpeciesCard, ...], int, [[Species_j, ...], ...]] :effect: calls the feedNext method in the external player :return: FeedingChoice """ ys = parse_json.parse_state(zs) feeding = self.externalPlayer.feedNext(ys[0], ys[1], ys[2]) self.sock.sendall(json.dumps(feeding)) def callMethod(self, data): """ calls the correct method based on the received data :param data: List """ if ((data == "ok") and (not self.gotOK)): self.gotOk = True elif self.gotOk: if (not isinstance(data, list) and (data != "ok")): self.new(data) elif len(data) == 2: self.choose(data) elif len(data) == 4: self.start(data) elif len(data) == 5: self.feedNext(data) else: self.disconnect() else: self.disconnect() def main(self): """ Setup and manage TCP connection to game server; deliver messages as Python objects to the appropriate player proxy method, return their responses (as JSON) to the game server. """ try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as msg: raise Exception('Socket error {} : {}'.format(msg[0], msg[1])) try: self.sock.connect((HOST, PORT)) except socket.error as msg: raise Exception('Socket error {} : {}'.format(msg[0], msg[1])) self.signUp("Pikachu") while True: data = self.receiveData() if data: try: d = json.loads(data) self.callMethod(d) except ValueError: self.disconnect() self.disconnect()