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])
Beispiel #2
0
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
Beispiel #3
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()