Exemplo n.º 1
0
  def chanceOpponentHasProtection(self, team, attack):
    # Chance that a particular opponent has protection from a particular attack in their hand.
    safety = Cards.attackToSafety(attack)
    remedy = Cards.attackToRemedy(attack)

    if safety in team.safeties:
      self.debug("Team %d has already played safety v. %s",
                 team.number,
                 Cards.cardToString(attack))
      return 1.0

    # Odds based on number of the card lurking out there somewhere.
    odds = self.percentOfCardsRemaining(safety, remedy)

    # Boost likelihood by 50% for each remedy they've discarded.
    remedyDiscards = 0
    for player in team.playerNumbers:
      for _ in xrange(self.interestingRemedyDiscardsByPlayer[player][remedy]):
        remedyDiscards += 1
        odds *= self.__class__.constants.remedy_discard_boost

    self.debug("Team %d protection odds %r v. %s, based on %d safety %d remedy %d discards.",
               team.number,
               odds,
               Cards.cardToString(attack),
               self.cardsUnseen[safety],
               self.cardsUnseen[remedy],
               remedyDiscards)
    return odds
Exemplo n.º 2
0
    def chanceOpponentHasProtection(self, team, attack):
        # Chance that a particular opponent has protection from a particular attack in their hand.
        safety = Cards.attackToSafety(attack)
        remedy = Cards.attackToRemedy(attack)

        if safety in team.safeties:
            self.debug("Team %d has already played safety v. %s", team.number,
                       Cards.cardToString(attack))
            return 1.0

        # Odds based on number of the card lurking out there somewhere.
        odds = self.percentOfCardsRemaining(safety, remedy)

        # Boost likelihood by 50% for each remedy they've discarded.
        remedyDiscards = 0
        for player in team.playerNumbers:
            for _ in xrange(
                    self.interestingRemedyDiscardsByPlayer[player][remedy]):
                remedyDiscards += 1
                odds *= self.__class__.constants.remedy_discard_boost

        self.debug(
            "Team %d protection odds %r v. %s, based on %d safety %d remedy %d discards.",
            team.number, odds, Cards.cardToString(attack),
            self.cardsUnseen[safety], self.cardsUnseen[remedy], remedyDiscards)
        return odds
Exemplo n.º 3
0
    def findValidPlays(self):
        for card in self.hand:
            # You can always discard
            self.validMoves.append(Move(Move.DISCARD, card))

            type = Cards.cardToType(card)
            if (card == self.us.needRemedy or
                (card == Cards.REMEDY_END_OF_LIMIT and self.us.speedLimit) or
                (self.us.moving and type == Cards.MILEAGE and
                 ((not self.us.speedLimit) or card in Cards.LOW_MILEAGE) and
                 (self.us.twoHundredsPlayed < 2 or card != Cards.MILEAGE_200)
                 and
                 (self.us.mileage + Cards.cardToMileage(card) <= self.target))
                    or type == Cards.SAFETY):
                self.validMoves.append(Move(Move.PLAY, card))
            elif type == Cards.ATTACK:
                for opponent in self.opponents:
                    if card == Cards.ATTACK_SPEED_LIMIT:
                        if ((not opponent.speedLimit)
                                and Cards.SAFETY_RIGHT_OF_WAY
                                not in opponent.safeties):
                            self.validMoves.append(
                                Move(Move.PLAY, card, opponent.number))
                    elif (opponent.moving and Cards.attackToSafety(card)
                          not in opponent.safeties):
                        self.validMoves.append(
                            Move(Move.PLAY, card, opponent.number))
Exemplo n.º 4
0
  def playerPlayed(self, player, move):
    type = Cards.cardToType(move.card)
    if move.type == Move.PLAY and type == Cards.ATTACK:

      ElliotAI.adjustScoresForAttack(move.card, self.attackCounts, self.priorities)
    elif move.type == Move.DISCARD and type == Cards.REMEDY:
      # When a team discards a remedy, they're a less attractive target for
      # that attack
      self.priorities[Move(Move.PLAY, Cards.remedyToAttack(move.card), player.teamNumber)] += -.5
Exemplo n.º 5
0
 def adjustScoresForAttack(card, attackCounts, priorities):
     # Discarding the associated remedy is a better move, and an
     # auto-discard if all three have been played now
     # Also that safety is less useful as a coup fourre
     attackCounts[card] += 1
     if attackCounts[card] == 3:
         priorities[Move(Move.PLAY, Cards.attackToSafety(card))] = 100
         priorities[Move(Move.DISCARD, Cards.attackToRemedy(card))] = 0
     else:
         priorities[Move(Move.PLAY, Cards.attackToSafety(card))] += 1
         priorities[Move(Move.DISCARD, Cards.attackToRemedy(card))] += .5
Exemplo n.º 6
0
    def playerPlayed(self, player, move):
        type = Cards.cardToType(move.card)
        if move.type == Move.PLAY and type == Cards.ATTACK:

            ElliotAI.adjustScoresForAttack(move.card, self.attackCounts,
                                           self.priorities)
        elif move.type == Move.DISCARD and type == Cards.REMEDY:
            # When a team discards a remedy, they're a less attractive target for
            # that attack
            self.priorities[Move(Move.PLAY, Cards.remedyToAttack(move.card),
                                 player.teamNumber)] += -.5
Exemplo n.º 7
0
 def adjustScoresForAttack(card, attackCounts, priorities):
   # Discarding the associated remedy is a better move, and an
   # auto-discard if all three have been played now
   # Also that safety is less useful as a coup fourre
   attackCounts[card] += 1
   if attackCounts[card] == 3:
     priorities[Move(Move.PLAY, Cards.attackToSafety(card))] = 100
     priorities[Move(Move.DISCARD, Cards.attackToRemedy(card))] = 0
   else:
     priorities[Move(Move.PLAY, Cards.attackToSafety(card))] += 1
     priorities[Move(Move.DISCARD, Cards.attackToRemedy(card))] += .5
Exemplo n.º 8
0
 def __str__(self):
   ret = "Team " + str(self.number) + ': ' + str(self.mileage) + " miles\n"
   if self.needRemedy != None:
     ret += '  Needs ' + Cards.cardToString(self.needRemedy) + "\n"
   if self.moving:
     ret += "  Moving\n"
   if self.speedLimit:
     ret += "  Under a speed limit\n"
   for safety in self.safeties:
     ret += '  ' + Cards.cardToString(safety) + "\n"
   return ret
Exemplo n.º 9
0
 def __str__(self):
     ret = "Team " + str(self.number) + ': ' + str(
         self.mileage) + " miles\n"
     if self.needRemedy != None:
         ret += '  Needs ' + Cards.cardToString(self.needRemedy) + "\n"
     if self.moving:
         ret += "  Moving\n"
     if self.speedLimit:
         ret += "  Under a speed limit\n"
     for safety in self.safeties:
         ret += '  ' + Cards.cardToString(safety) + "\n"
     return ret
Exemplo n.º 10
0
    def goForExtension(self, gameState):
        score = 0
        # Safeties played
        #    print str(len(gameState.us.safeties)) + ' safeties played'
        score += len(gameState.us.safeties) * 200

        # Mileage in hand
        mileage = 0
        for card in gameState.hand:
            try:
                mileage += Cards.cardToMileage(card)
            except ValueError:
                pass
        if mileage > 300:
            mileage = 300
#    print str(mileage) + ' miles in hand'
        score += mileage

        # Each card is on average worth 33 miles
        expectedMiles = 33 * (gameState.cardsLeft / len(gameState.opponents) +
                              1)
        if expectedMiles > 300 - mileage:
            expectedMiles = 300 - mileage
        score += expectedMiles
        #    print str(expectedMiles) + ' expected miles in ' + str(gameState.cardsLeft) + ' cards'

        # Played attacks
        for attack in Cards.ATTACKS:
            if not Cards.attackToSafety(attack) in gameState.us.safeties:
                score += 60 * self.attackCounts[attack]
#        print str(self.attackCounts[attack]) + ' ' + Cards.cardToString(attack) + ' cards played'

# Opponents
        for opponent in gameState.opponents:
            score -= opponent.mileage
            #      print 'Team ' + str(opponent.number) + ' has ' + str(opponent.mileage) + ' miles'
            score -= len(opponent.safeties) * 100
            #      print 'Team ' + str(opponent.number) + ' has ' + str(len(opponent.safeties)) + ' safeties'
            if opponent.moving:
                #        print 'Team ' + str(opponent.number) + ' is moving'
                score -= 200


#    print 'Score: ' + str(score)
        if score > 500:
            return True
        else:
            return False
Exemplo n.º 11
0
 def ConsiderPlaySafety(self, state, safeties):
   # If I'm stuck and the safety resolves it, play it
   if (not state.us.moving):
     needRemedy = state.us.needRemedy
     needSafe = Cards.remedyToSafety(needRemedy)
     for safety in safeties:
       if (safety.card == needSafe):
         return safety
   # If all the hazards are visible, just play the safety
   for safety in safeties:
     if (safety.card == Cards.SAFETY_PUNCTURE_PROOF):
       flats = self.CountCard(state, Cards.ATTACK_FLAT_TIRE)
       if (flats >= 3):
         return safety
     elif (safety.card == Cards.SAFETY_EXTRA_TANK):
       outs = self.CountCard(state, Cards.ATTACK_OUT_OF_GAS)
       if (outs >= 3):
         return safety
     elif (safety.card == Cards.SAFETY_DRIVING_ACE):
       acc = self.CountCard(state, Cards.ATTACK_ACCIDENT)
       if (acc >= 3):
         return safety
   # Out of cards, just play the safety
   if (len(state.hand) == len(safeties)):
     return safety
   # Been stuck for too long, have to do something
   if (self.needRoll >= 10):
     return safeties[0]
Exemplo n.º 12
0
  def movePlayed(self, game, playerNum, drawnCard, move):
    cardType = Cards.cardToType(move.card)
    player = game.players[playerNum]
    team = game.teams[game.players[playerNum].teamNumber]
    playerStr = self.currentGamePlayers[playerNum]
    teamPlayers = self.currentGameTeams[team.number]

    if game.target > self.currentHandTarget:
      self.currentHandTarget = game.target
      self.sawPlayerEvent("declaredExtension", playerStr, teamPlayers)

    if team.needRemedy and team.needRemedy != Cards.REMEDY_GO and team.needRemedy != Cards.REMEDY_END_OF_LIMIT:
      self.sawPlayerEvent("needRemedyTurn", playerStr, teamPlayers)
    elif not team.moving:
      self.sawPlayerEvent("needGoTurn", playerStr, teamPlayers)

    if team.speedLimit:
      self.sawPlayerEvent("speedLimitTurn", playerStr, teamPlayers)

    if move.type == Move.DISCARD:
      self.sawPlayerEvent("discard", playerStr, teamPlayers)
    elif cardType == Cards.ATTACK:
      self.sawPlayerEvent("attack", playerStr, teamPlayers)
      self.sawTeamEvent("targeted", self.currentGameTeams[move.target])
    elif cardType == Cards.MILEAGE:
      if drawnCard is None:
        self.sawPlayerEvent("movedWithEmptyDeck", playerStr, teamPlayers)
    elif cardType == Cards.SAFETY:
      if move.coupFourre:
        self.sawPlayerEvent("coupFourred", playerStr, teamPlayers)
        self.sawPlayerEvent("attackFailed", self.lastPlayerMoved, teamPlayers)
      self.sawPlayerEvent("safety", playerStr, teamPlayers)
      
    self.lastPlayerMoved = playerStr
Exemplo n.º 13
0
  def GetBestAttack(self, state, attacks):
    # Best attack is one where safety is visible
    for attack in attacks:
      safety = Cards.attackToSafety(attack.card)
      safetyVisible = self.CountCard(state, safety)
      if (safetyVisible >= 1):
        return attack
    # Count remedies for 3 regular attacks, and figure out which is best
    gas = self.CountCard(state, Cards.REMEDY_GASOLINE)
    repairs = self.CountCard(state, Cards.REMEDY_REPAIRS)
    spares = self.CountCard(state, Cards.REMEDY_SPARE_TIRE)

    bestAttack = attacks[0] # Could be Stop or Limit
    for attack in attacks:
      if attack.card == Cards.ATTACK_OUT_OF_GAS:
        if ((gas >= repairs) & (gas >= spares)):
          bestAttack = attack
      elif attack.card == Cards.ATTACK_ACCIDENT:
        if ((repairs >= gas) & (repairs >= spares)):
          bestAttack = attack
      elif attack.card == Cards.ATTACK_FLAT_TIRE:
        if ((spares >= gas) & (spares >= repairs)):
          bestAttack = attack
      if ((bestAttack.card == Cards.ATTACK_STOP) | (bestAttack.card == Cards.ATTACK_SPEED_LIMIT)):
          # Anything's better than Stop/Limit
          bestAttack = attack
    return bestAttack
Exemplo n.º 14
0
 def getDangerCards(self, gameState):
   #Danger cards are cards that can actually stop us
   dangerCards = 0
   if len(gameState.us.safeties) == 4:
     #If we have all of the safeties, there are no danger cards.
     return 0
   else:
     for card in self.cardsLeft:
       if Cards.cardToType(card) == Cards.ATTACK and Cards.attackToSafety(card) not in gameState.us.safeties and card != Cards.ATTACK_SPEED_LIMIT:
       #For each card that's an attack and we don't have the safety
         if Cards.attackToRemedy(card) not in gameState.hand:
           #If the remedy isn't in our hand, all cards are danger cards
           dangerCards+=self.cardsLeft[card]
         elif gameState.hand.count(Cards.attackToRemedy(card)) < self.cardsLeft[card]:
           #If The number of remedies we have is less than the number of attacks out there
           dangerCards+=(self.cardsLeft[card] - gameState.hand.count(Cards.attackToRemedy(card)))
Exemplo n.º 15
0
  def mileageCardValue(self, card):
    # TODO: This assumes an extension.
    tripMileageRemaining = 1000 - self.gameState.us.mileage
    tripRemainingMileagePercentConsumed = Cards.cardToMileage(card) / tripMileageRemaining
    # TODO: Factor in delayed action, safe trip, shutout.
    # TODO: Assumes extension.

    # e.g. the game is currently at 0 points (0% done), and completing this trip will net 600 points
    # (600/5000=12% done).  And the trip is currently at 900km (100km remaining), and playing this mileage
    # card will get us to 1000k (100% of remaining distance.)  Value of playing this move is:
    #   1.00 * 0.12
    ret = tripRemainingMileagePercentConsumed * self.valueOfPoints(400 + 200, self.gameState.us) * self.__class__.constants.mileage_boost
    self.debug("Value of %dkm: %r, since it covers %r of remaining trip distance.",
               Cards.cardToMileage(card),
               ret,
               tripRemainingMileagePercentConsumed)
    return ret
Exemplo n.º 16
0
 def goForExtension(self, state):
   milesInHand = 0
   for card in state.hand:
     if (Cards.cardToType(card) == Cards.MILEAGE):
       milesInHand = milesInHand + Cards.cardToMileage(card)
   if ((state.cardsLeft < 5) & (milesInHand < 300)):
     # Not enough cards to bother
     return False
   theirSafeties = 0
   # If opponent is at 600, or they have all the safeties, don't extend
   for opponent in state.opponents:
     if opponent.mileage >= 600:
       return False
     theirSafeties = theirSafeties + len(opponent.safeties)
   if theirSafeties >= 3:
     return False;
   return True
Exemplo n.º 17
0
  def goForExtension(self, gameState):
    score = 0
    # Safeties played
#    print str(len(gameState.us.safeties)) + ' safeties played'
    score += len(gameState.us.safeties) * 200

    # Mileage in hand
    mileage = 0
    for card in gameState.hand:
      try:
        mileage += Cards.cardToMileage(card)
      except ValueError:
        pass
    if mileage > 300:
      mileage = 300
#    print str(mileage) + ' miles in hand'
    score += mileage

    # Each card is on average worth 33 miles
    expectedMiles = 33 * (gameState.cardsLeft / len(gameState.opponents) + 1)
    if expectedMiles > 300 - mileage:
      expectedMiles = 300 - mileage
    score += expectedMiles
#    print str(expectedMiles) + ' expected miles in ' + str(gameState.cardsLeft) + ' cards'

    # Played attacks
    for attack in Cards.ATTACKS:
      if not Cards.attackToSafety(attack) in gameState.us.safeties:
        score += 60 * self.attackCounts[attack]
#        print str(self.attackCounts[attack]) + ' ' + Cards.cardToString(attack) + ' cards played'

    # Opponents
    for opponent in gameState.opponents:
      score -= opponent.mileage
#      print 'Team ' + str(opponent.number) + ' has ' + str(opponent.mileage) + ' miles'
      score -= len(opponent.safeties) * 100
#      print 'Team ' + str(opponent.number) + ' has ' + str(len(opponent.safeties)) + ' safeties'
      if opponent.moving:
#        print 'Team ' + str(opponent.number) + ' is moving'
        score -= 200

#    print 'Score: ' + str(score)
    if score > 500:
      return True
    else:
      return False
Exemplo n.º 18
0
 def playerPlayed(self, player, move):
   if player == self._usPlayerNumber:
     return
   self.cardSeen(move.card)
   if Cards.cardToType(move.card) == Cards.REMEDY and move.card != Cards.REMEDY_GO:
     if move.type == Move.DISCARD:
       self.interestingRemedyDiscardsByPlayer[player][move.card] += 1
     else:
       self.interestingRemedyDiscardsByPlayer[player][move.card] = 0
Exemplo n.º 19
0
 def playerPlayed(self, player, move):
     if player == self._usPlayerNumber:
         return
     self.cardSeen(move.card)
     if Cards.cardToType(
             move.card) == Cards.REMEDY and move.card != Cards.REMEDY_GO:
         if move.type == Move.DISCARD:
             self.interestingRemedyDiscardsByPlayer[player][move.card] += 1
         else:
             self.interestingRemedyDiscardsByPlayer[player][move.card] = 0
Exemplo n.º 20
0
  def GetDiscard(self, state, discards):

    milesLeft = state.target - state.us.mileage
    milesInHand = 0
    for discard in discards:
      # Excess mileage; discard the card that puts me over the top
      if (Cards.cardToType(discard.card) == Cards.MILEAGE):
        milesInHand = milesInHand + Cards.cardToMileage(discard.card)
        if (milesInHand > milesLeft): 
          return discard
      # Too many 200s
      if (discard.card == Cards.MILEAGE_200):
        total200 = state.us.twoHundredsPlayed + state.hand.count(Cards.MILEAGE_200)
        if (total200 > 2):
          return discard
      # Attack that opponent has a safety for, if only 1 opponent
      if (len(state.opponents) == 1) & (Cards.cardToType(discard.card) == Cards.ATTACK):
        safety = Cards.attackToSafety(discard.card)
        if safety in state.opponents[0].safeties:
          return discard
      # Remedy for a safety that I have
      if Cards.cardToType(discard.card) == Cards.REMEDY:
        safety = Cards.remedyToSafety(discard.card)
        if (safety in state.hand) | (safety in state.us.safeties):
          return discard
    # Now that we've gone through the best options, try second-tier discards
    for discard in discards:
      # 2 of the same remedy, or 3 if it's GO
      if Cards.cardToType(discard.card) == Cards.REMEDY:
        count = state.hand.count(discard.card)
        if (count > 1) & (discard.card != Cards.REMEDY_GO):
          return discard
        if count > 2:
          return discard
        # Weak mileage, unless near the end of the game
        if (milesLeft > 100):
          if discard.card == Cards.MILEAGE_25:
            return discard
          if discard.card == Cards.MILEAGE_50:
            return discard
          if discard.card == Cards.MILEAGE_75:
            return discard
    # Nothing good to discard; just toss something that's not attack or safety
    for d in discards:
      if ((Cards.cardToType(d.card) != Cards.SAFETY) &
          (Cards.cardToType(d.card) != Cards.ATTACK)):
        return d;
Exemplo n.º 21
0
 def playSafety(self, team, card):
   team.safeties.append(card)
   if card == Cards.SAFETY_RIGHT_OF_WAY:
     team.speedLimit = False
   if Cards.remedyToSafety(team.needRemedy) == card:
     if (card == Cards.SAFETY_RIGHT_OF_WAY
      or Cards.SAFETY_RIGHT_OF_WAY in team.safeties):
       team.needRemedy = None
       team.moving = True
     else:
       team.needRemedy = Cards.REMEDY_GO
Exemplo n.º 22
0
 def playSafety(self, team, card):
     team.safeties.append(card)
     if card == Cards.SAFETY_RIGHT_OF_WAY:
         team.speedLimit = False
     if Cards.remedyToSafety(team.needRemedy) == card:
         if (card == Cards.SAFETY_RIGHT_OF_WAY
                 or Cards.SAFETY_RIGHT_OF_WAY in team.safeties):
             team.needRemedy = None
             team.moving = True
         else:
             team.needRemedy = Cards.REMEDY_GO
Exemplo n.º 23
0
    def mileageCardValue(self, card):
        # TODO: This assumes an extension.
        tripMileageRemaining = 1000 - self.gameState.us.mileage
        tripRemainingMileagePercentConsumed = Cards.cardToMileage(
            card) / tripMileageRemaining
        # TODO: Factor in delayed action, safe trip, shutout.
        # TODO: Assumes extension.

        # e.g. the game is currently at 0 points (0% done), and completing this trip will net 600 points
        # (600/5000=12% done).  And the trip is currently at 900km (100km remaining), and playing this mileage
        # card will get us to 1000k (100% of remaining distance.)  Value of playing this move is:
        #   1.00 * 0.12
        ret = tripRemainingMileagePercentConsumed * self.valueOfPoints(
            400 + 200,
            self.gameState.us) * self.__class__.constants.mileage_boost
        self.debug(
            "Value of %dkm: %r, since it covers %r of remaining trip distance.",
            Cards.cardToMileage(card), ret,
            tripRemainingMileagePercentConsumed)
        return ret
Exemplo n.º 24
0
 def GetBestMove(self,  state, mileage):
   # If the race is almost over, may not want to play highest card
   needToPlay = -1
   if self.milesLeft == 125:  # 100/25 or 75/50
     if ((Cards.MILEAGE_75 in state.hand) & (Cards.MILEAGE_50 in state.hand)):
       needToPlay = Cards.MILEAGE_75
     if ((Cards.MILEAGE_100 in state.hand) & (Cards.MILEAGE_25 in state.hand)):
       needToPlay = Cards.MILEAGE_100
   elif self.milesLeft == 100:  # 75/25 or 50/50, or 100
     if (state.hand.count(Cards.MILEAGE_50) >= 2):
       needToPlay= Cards.MILEAGE_50
     if (Cards.MILEAGE_100 in state.hand):
       needToPlay = Cards.MILEAGE_100
   highCard = mileage[0]
   for mileCard in mileage:
     if (mileCard.card == needToPlay):
       return mileCard
     if (Cards.cardToMileage(mileCard.card)) > (Cards.cardToMileage(highCard.card)):
       highCard = mileCard
   return highCard
Exemplo n.º 25
0
 def makeMove(self, gameState):
   print 'Opponents:'
   for opponent in gameState.opponents:
     print opponent
   print 'Us:'
   print gameState.us
   print 'Cards left in deck: ' + str(gameState.cardsLeft)
   print 'Target: ' + str(gameState.target) + ' miles'
   print 'Your hand: ',
   print Cards.cardsToStrings(gameState.hand)
   print 'Valid moves:'
   for i in range(len(gameState.validMoves)):
     print str(i) + ':',
     print gameState.validMoves[i]
   moveint = -1
   while moveint not in range(len(gameState.validMoves)):
     move = raw_input('Enter move index: ')
     try:
       moveint = int(move)
     except ValueError:
       moveint = -1
   return gameState.validMoves[int(move)]
Exemplo n.º 26
0
 def makeMove(self, gameState):
     print 'Opponents:'
     for opponent in gameState.opponents:
         print opponent
     print 'Us:'
     print gameState.us
     print 'Cards left in deck: ' + str(gameState.cardsLeft)
     print 'Target: ' + str(gameState.target) + ' miles'
     print 'Your hand: ',
     print Cards.cardsToStrings(gameState.hand)
     print 'Valid moves:'
     for i in range(len(gameState.validMoves)):
         print str(i) + ':',
         print gameState.validMoves[i]
     moveint = -1
     while moveint not in range(len(gameState.validMoves)):
         move = raw_input('Enter move index: ')
         try:
             moveint = int(move)
         except ValueError:
             moveint = -1
     return gameState.validMoves[int(move)]
Exemplo n.º 27
0
  def findValidPlays(self):
    for card in self.hand:
      # You can always discard
      self.validMoves.append(Move(Move.DISCARD, card))

      type = Cards.cardToType(card)
      if (card == self.us.needRemedy
       or (card == Cards.REMEDY_END_OF_LIMIT and self.us.speedLimit)
       or (self.us.moving and type == Cards.MILEAGE
           and ((not self.us.speedLimit) or card in Cards.LOW_MILEAGE)
           and (self.us.twoHundredsPlayed < 2 or card != Cards.MILEAGE_200)
           and (self.us.mileage + Cards.cardToMileage(card) <= self.target))
       or type == Cards.SAFETY):
        self.validMoves.append(Move(Move.PLAY, card))
      elif type == Cards.ATTACK:
        for opponent in self.opponents:
          if card == Cards.ATTACK_SPEED_LIMIT:
            if ((not opponent.speedLimit)
             and Cards.SAFETY_RIGHT_OF_WAY not in opponent.safeties):
              self.validMoves.append(Move(Move.PLAY, card, opponent.number))
          elif (opponent.moving
           and Cards.attackToSafety(card) not in opponent.safeties):
            self.validMoves.append(Move(Move.PLAY, card, opponent.number))
Exemplo n.º 28
0
  def makeMove(self, gameState):
    discards = []
    mileage = []
    attacks = []
    remedies = []
    safeties = []
    for play in gameState.validMoves:
      if (play.type == Move.DISCARD):
        discards.append(play)
      else:
        type = Cards.cardToType(play.card)
        if type == Cards.MILEAGE:
          mileage.append(play)
        elif type == Cards.REMEDY:
          remedies.append(play)
        elif type == Cards.ATTACK:
          attacks.append(play)
        elif type == Cards.SAFETY:
          safeties.append(play)

    # If we can move, move
    if len(mileage) > 0:
      return mileage[0]

    # Play a red card if appropriate
    if len(attacks) > 0:
      return attacks[0]

    # Play a remedy if we can
    if len(remedies) > 0:
      return remedies[0]

    # Play a safety rather than discard
    if len(safeties) > 0:
      return safeties[0]
    
    # Discard something
    return discards[0]
Exemplo n.º 29
0
    def makeMove(self, gameState):
        discards = []
        mileage = []
        attacks = []
        remedies = []
        safeties = []
        for play in gameState.validMoves:
            if (play.type == Move.DISCARD):
                discards.append(play)
            else:
                type = Cards.cardToType(play.card)
                if type == Cards.MILEAGE:
                    mileage.append(play)
                elif type == Cards.REMEDY:
                    remedies.append(play)
                elif type == Cards.ATTACK:
                    attacks.append(play)
                elif type == Cards.SAFETY:
                    safeties.append(play)

        # If we can move, move
        if len(mileage) > 0:
            return mileage[0]

        # Play a red card if appropriate
        if len(attacks) > 0:
            return attacks[0]

        # Play a remedy if we can
        if len(remedies) > 0:
            return remedies[0]

        # Play a safety rather than discard
        if len(safeties) > 0:
            return safeties[0]

        # Discard something
        return discards[0]
Exemplo n.º 30
0
    def movePlayed(self, game, playerNum, drawnCard, move):
        cardType = Cards.cardToType(move.card)
        player = game.players[playerNum]
        team = game.teams[game.players[playerNum].teamNumber]
        playerStr = self.currentGamePlayers[playerNum]
        teamPlayers = self.currentGameTeams[team.number]

        if game.target > self.currentHandTarget:
            self.currentHandTarget = game.target
            self.sawPlayerEvent("declaredExtension", playerStr, teamPlayers)

        if team.needRemedy and team.needRemedy != Cards.REMEDY_GO and team.needRemedy != Cards.REMEDY_END_OF_LIMIT:
            self.sawPlayerEvent("needRemedyTurn", playerStr, teamPlayers)
        elif not team.moving:
            self.sawPlayerEvent("needGoTurn", playerStr, teamPlayers)

        if team.speedLimit:
            self.sawPlayerEvent("speedLimitTurn", playerStr, teamPlayers)

        if move.type == Move.DISCARD:
            self.sawPlayerEvent("discard", playerStr, teamPlayers)
        elif cardType == Cards.ATTACK:
            self.sawPlayerEvent("attack", playerStr, teamPlayers)
            self.sawTeamEvent("targeted", self.currentGameTeams[move.target])
        elif cardType == Cards.MILEAGE:
            if drawnCard is None:
                self.sawPlayerEvent("movedWithEmptyDeck", playerStr,
                                    teamPlayers)
        elif cardType == Cards.SAFETY:
            if move.coupFourre:
                self.sawPlayerEvent("coupFourred", playerStr, teamPlayers)
                self.sawPlayerEvent("attackFailed", self.lastPlayerMoved,
                                    teamPlayers)
            self.sawPlayerEvent("safety", playerStr, teamPlayers)

        self.lastPlayerMoved = playerStr
Exemplo n.º 31
0
    def handleMove(self,
                   currentPlayer,
                   currentTeam,
                   move,
                   forceExtension=False):
        if True:  # To keep the indent level of all this the same as in upstream and make the diff prettier. :(
            currentPlayerNumber = currentPlayer.number

            # Handle moves
            if move.type == Move.PLAY:
                card = move.card
                type = Cards.cardToType(card)
                if type == Cards.MILEAGE:
                    currentTeam.mileage += Cards.cardToMileage(card)
                    currentTeam.mileagePile.append(card)
                    if card == Cards.MILEAGE_200:
                        currentTeam.safeTrip = False
                        currentTeam.twoHundredsPlayed += 1
                    if currentTeam.mileage == self.target:
                        tempState = self.makeState(currentPlayer)
                        if self.extensionPossible and (
                                forceExtension
                                or currentPlayer.ai.goForExtension(tempState)):
                            if self.debug:
                                print 'Player ' + str(
                                    currentPlayerNumber
                                ) + ' goes for the extension'
                            self.extension = True
                            self.extensionPossible = False
                            self.target = 1000
                        else:
                            if self.debug:
                                print 'Race complete'
                            self.winner = currentPlayer.teamNumber
                            self.tripComplete = True
                            return
                elif type == Cards.REMEDY:
                    currentTeam.battlePile.append(card)
                    if card == Cards.REMEDY_END_OF_LIMIT:
                        currentTeam.speedLimit = False
                    else:
                        currentTeam.needRemedy = Cards.REMEDY_GO
                    if (card == Cards.REMEDY_GO or Cards.SAFETY_RIGHT_OF_WAY
                            in currentTeam.safeties):
                        currentTeam.needRemedy = None
                        currentTeam.moving = True
                elif type == Cards.ATTACK:
                    targetTeam = self.teams[(move.target)]

                    # Check for coup fourre
                    neededSafety = Cards.attackToSafety(card)
                    coupFourrePlayerNumber = -1
                    for targetPlayerNumber in targetTeam.playerNumbers:
                        targetPlayer = self.players[targetPlayerNumber]
                        if neededSafety in targetPlayer.hand:
                            tempState = self.makeState(targetPlayer)
                            if targetPlayer.ai and targetPlayer.ai.playCoupFourre(
                                    card, tempState):
                                coupFourrePlayerNumber = targetPlayerNumber
                            # There's only one of each safety, so if we found it, we don't
                            # need to keep looking
                            break

                    if coupFourrePlayerNumber == -1:
                        # The attack resolves
                        targetTeam.battlePile.append(card)
                        if card == Cards.ATTACK_SPEED_LIMIT:
                            self.teams[move.target].speedLimit = True
                        else:
                            self.teams[move.target].moving = False
                            self.teams[
                                move.target].needRemedy = Cards.attackToRemedy(
                                    card)
                    else:
                        # Coup fourre
                        self.playSafety(targetTeam, neededSafety)
                        nextPlayerNumber = coupFourrePlayerNumber
                        # Remove the safety from the player's hand
                        del self.players[coupFourrePlayerNumber].hand[
                            self.players[coupFourrePlayerNumber].hand.index(
                                neededSafety)]
                        # Draw an extra card to replace the one just played
                        try:
                            player = self.players[coupFourrePlayerNumber]
                            cfCard = self.draw(player)
                            player.hand.append(cfCard)
                        except IndexError:
                            cfCard = None
                            pass
                        targetTeam.coupFourres += 1
                        cfMove = Move(Move.PLAY, neededSafety, None, True)
                        if self.debug:
                            print self.players[nextPlayerNumber],
                            print cfMove
                        cfPlayer = copy(self.players[nextPlayerNumber])
                        cfPlayer.hand = []
                        cfPlayer.ai = None
                        self.notifyPlayers(cfPlayer, cfMove)
                        if self.transcriptWriter:
                            self.transcriptWriter.writeMove(
                                cfPlayer.number, cfCard, cfMove, False)
                elif type == Cards.SAFETY:
                    self.playSafety(currentTeam, card)
                    nextPlayerNumber = currentPlayerNumber
                else:
                    raise ValueError('Unknown card type!')
            elif move.type == Move.DISCARD:
                self.discardPile.append(move.card)
Exemplo n.º 32
0
  def handleMove(self, currentPlayer, currentTeam, move, forceExtension = False):
    if True:  # To keep the indent level of all this the same as in upstream and make the diff prettier. :(
      currentPlayerNumber = currentPlayer.number

      # Handle moves
      if move.type == Move.PLAY:
        card = move.card
        type = Cards.cardToType(card)
        if type == Cards.MILEAGE:
          currentTeam.mileage += Cards.cardToMileage(card)
          currentTeam.mileagePile.append(card)
          if card == Cards.MILEAGE_200:
            currentTeam.safeTrip = False
            currentTeam.twoHundredsPlayed += 1
          if currentTeam.mileage == self.target:
            tempState = self.makeState(currentPlayer)
            if self.extensionPossible and (forceExtension or
                                           currentPlayer.ai.goForExtension(tempState)):
              if self.debug:
                print 'Player ' + str(currentPlayerNumber) + ' goes for the extension'
              self.extension = True
              self.extensionPossible = False
              self.target = 1000
            else:
              if self.debug:
                print 'Race complete'
              self.winner = currentPlayer.teamNumber
              self.tripComplete = True
              return
        elif type == Cards.REMEDY:
          currentTeam.battlePile.append(card)
          if card == Cards.REMEDY_END_OF_LIMIT:
            currentTeam.speedLimit = False
          else:
            currentTeam.needRemedy = Cards.REMEDY_GO
          if (card == Cards.REMEDY_GO
              or Cards.SAFETY_RIGHT_OF_WAY in currentTeam.safeties):
            currentTeam.needRemedy = None
            currentTeam.moving = True
        elif type == Cards.ATTACK:
          targetTeam = self.teams[(move.target)]

          # Check for coup fourre
          neededSafety = Cards.attackToSafety(card)
          coupFourrePlayerNumber = -1
          for targetPlayerNumber in targetTeam.playerNumbers:
            targetPlayer = self.players[targetPlayerNumber]
            if neededSafety in targetPlayer.hand:
              tempState = self.makeState(targetPlayer)
              if targetPlayer.ai and targetPlayer.ai.playCoupFourre(card, tempState):
                coupFourrePlayerNumber = targetPlayerNumber
              # There's only one of each safety, so if we found it, we don't
              # need to keep looking
              break

          if coupFourrePlayerNumber == -1:
            # The attack resolves
            targetTeam.battlePile.append(card)
            if card == Cards.ATTACK_SPEED_LIMIT:
              self.teams[move.target].speedLimit = True
            else:
              self.teams[move.target].moving = False
              self.teams[move.target].needRemedy = Cards.attackToRemedy(card)
          else:
            # Coup fourre
            self.playSafety(targetTeam, neededSafety)
            nextPlayerNumber = coupFourrePlayerNumber
            # Remove the safety from the player's hand
            del self.players[coupFourrePlayerNumber].hand[self.players[coupFourrePlayerNumber].hand.index(neededSafety)]
            # Draw an extra card to replace the one just played
            try:
              player = self.players[coupFourrePlayerNumber]
              cfCard = self.draw(player)
              player.hand.append(cfCard)
            except IndexError:
              cfCard = None
              pass
            targetTeam.coupFourres += 1
            cfMove = Move(Move.PLAY, neededSafety, None, True)
            if self.debug:
              print self.players[nextPlayerNumber],
              print cfMove
            cfPlayer = copy(self.players[nextPlayerNumber])
            cfPlayer.hand = []
            cfPlayer.ai = None
            self.notifyPlayers(cfPlayer, cfMove)
            if self.transcriptWriter:
              self.transcriptWriter.writeMove(cfPlayer.number,
                                              cfCard,
                                              cfMove,
                                              False)
        elif type == Cards.SAFETY:
          self.playSafety(currentTeam, card)
          nextPlayerNumber = currentPlayerNumber
        else:
          raise ValueError('Unknown card type!')
      elif move.type == Move.DISCARD:
        self.discardPile.append(move.card)
Exemplo n.º 33
0
 def cardSeen(self, card):
     self.cardsUnseen[card] -= 1
     self.numCardsUnseen -= 1
     self.debug("After seeing %s, unseen cards:\n%s",
                Cards.cardToString(card), self.unseenCardsToString)
Exemplo n.º 34
0
  def makeMove(self, gameState):
    discards = []
    mileage = []
    attacks = []
    remedies = []
    safeties = []
    worthlessCards = [] #These are cards that cannot ever help us and are first to be discarded.
    milesToGo = gameState.target - gameState.us.mileage
    numMiles = []
    targetTeam = self.priorityTarget(gameState)
    
    for play in gameState.validMoves:
      type = Cards.cardToType(play.card)
      if (play.type == Move.DISCARD):
	    #Never discard a safety.
        if type != Cards.SAFETY:
          if type == Cards.MILEAGE:
            #Mileage cards are worthless if they put us over 1000 miles.
            if Cards.cardToMileage(play.card) + gameState.us.mileage > 1000:
              worthlessCards.append(play)
              
            #200 miles is worthless if we've played 2 of them, or if # played + # in hand > 2, the surplus is worthless
            else:
              discards.append(play)
          elif type == Cards.ATTACK:
            #Attack cards are worthless if we only have one opponent and they have played the safety
            if targetTeam == -1:
              for opponent in gameState.opponents:
                if Cards.attackToSafety(play.card) in opponent.safeties:
                  worthlessCards.append(play)
                else:
                  discards.append(play)
            else:
              discards.append(play)
            
          elif type == Cards.REMEDY:
            #Remedies are worthless if the we have played the safety
            if Cards.remedyToSafety(play.card) in gameState.us.safeties:
              worthlessCards.append(play)
            #Remedies are worthless if we have the safety for it in our hand
            elif Cards.remedyToSafety(play.card) in gameState.hand:
              worthlessCards.append(play)
            #Remedies are worthless if all of the appropriate attack cards have been played and we do not need it right now.
            elif self.cardsLeft[Cards.remedyToAttack(play.card)] == 0 and gameState.us.needRemedy != Cards.remedyToAttack(play.card):
              worthlessCards.append(play)
            else:
              discards.append(play)
      else:
        if type == Cards.MILEAGE:
          #Sort as we insert, biggest mileage at the front of the list
          if len(mileage) == 0:
            numMiles.append(Cards.cardToMileage(play.card))
            mileage.append(play)
          elif len(mileage) == 1:
            if Cards.cardToMileage(play.card) > numMiles[0]:
              numMiles.insert(0, Cards.cardToMileage(play.card))
              mileage.insert(0, play)
            else:
              numMiles.append(Cards.cardToMileage(play.card))
              mileage.append(play)
          elif len(mileage) == 2:
            if Cards.cardToMileage(play.card) > numMiles[0]:
              numMiles.insert(0, Cards.cardToMileage(play.card))
              mileage.insert(0, play)
            elif Cards.cardToMileage(play.card) > numMiles[1]:
              numMiles.insert(1, Cards.cardToMileage(play.card))
              mileage.insert(1, play)
            else:
              numMiles.append(Cards.cardToMileage(play.card))
              mileage.append(play)
          else:
            #If it's biggest, insert it first
            if Cards.cardToMileage(play.card) > numMiles[0]:
              numMiles.insert(0, Cards.cardToMileage(play.card))
              mileage.insert(0, play)
            #If it's smallest, insert it last
            elif Cards.cardToMileage(play.card) < numMiles[len(numMiles) - 1]:
              numMiles.insert((1 - len(numMiles)), Cards.cardToMileage(play.card))
              mileage.insert((1 - len(mileage)), play)
            #Otherwise Insert it at index 1
            else:
              numMiles.insert(1, Cards.cardToMileage(play.card))
              mileage.insert(1, play)
            
        elif type == Cards.ATTACK:
          if targetTeam == -1:
            #No priority target
            attacks.append(play)
          #Sort as we insert, priority targets in front
          elif play.target == targetTeam:
            attacks.insert(0, play)
          else:
            attacks.append(play)
        elif type == Cards.REMEDY:
          remedies.append(play)
        elif type == Cards.SAFETY:
          safeties.append(play)
    
    
    
	#If there are less than 10 cards left, play any safeties in our hand
	# NOTE: Investigate how much this changes AI results
    if gameState.cardsLeft <= 10:
      if len(safeties) > 0:
        return safeties[0]
			
	#If we can win the game, play a safety if we can, then check to see if we are safe to go for delayed action, otherwise win the game.
    if milesToGo in numMiles:
      if len(safeties) > 0:
        return safeties[0]
      elif gameState.cardsLeft == 0:
        #Win the game if we already have a delayed action.
        return mileage[numMiles.index(milesToGo)]
      elif self.getDangerCards(gameState) == 0:
        #If we are safe, attack if we can, pitch a worthless card if we can't, win the game otherwise.
        if len(attacks) > 0:
          return attacks[0]
        elif len(worthlessCards) > 0:
          return worthlessCards[0]
        else:
          return mileage[numMiles.index(milesToGo)]
      else:
        #For the time being, consider even one potential attack too deadly, and end the game.
        #TINKER HERE LATER
        return mileage[numMiles.index(milesToGo)]
        
    if len(attacks) > 0:
      attacks = self.sortAttacks(attacks, targetTeam)        
      #Attack if we can in a two player game always.
      if targetTeam == -1 :
        return attacks[0]
      #If we can't move in a 3 player game, attack first.
      elif len(mileage) == 0:
        return attacks[0]
      #If we have a valid move for 100 miles or more and we've got a ways to go, move, otherwise attack.
      elif Cards.cardToMileage(mileage[0].card) >= 100 and milesToGo >= 400:
        return mileage[0]
      else:
        return attacks[0]
    
	#Fix what needs fixing in a two player game, attack in a 3 player game (since we aren't moving)
    if len(remedies) > 0:
      return remedies[0]
   
  #If we need a remedy and we have the safety for it after move 10, just play it.
    if gameState.us.needRemedy != None and len(safeties) > 0:
      for s in safeties:
        if Cards.remedyToSafety(gameState.us.needRemedy) == s.card and len(self.gameHistory) >= 10:
          return s
	  
  # If we can move
    if len(mileage) > 0:
      #Move as fast as we can if we haven't gone too far
      if milesToGo > 400:
        return mileage[0]
      #If we've already played a 200 and our biggest mileage card leaves us at or over 100 miles, play it
      if (milesToGo - Cards.cardToMileage(mileage[0].card) >= 100):
        if (gameState.us.twoHundredsPlayed > 0):
          return mileage[0]
      #If we have more than 200 miles to go, haven't played a 200, have a 100, and we're not under a speed limit, play the 100
      if milesToGo > 200 and gameState.us.twoHundredsPlayed == 0 and Cards.MILEAGE_100 in gameState.hand and not(gameState.us.speedLimit):
        for i in mileage:
          if numMiles[mileage.index(i)] == 100:
            return i
      #If we're over 100 miles away and we can get to 100 miles away, do it
      if milesToGo > 100:
        for i in numMiles:
          if milesToGo - i == 100:
            return mileage[numMiles.index(i)]
      #If we're under a speed limit, play the biggest mileage we have
      if gameState.us.speedLimit:
        return mileage[0]
      #If we're at 200 miles or less, play our smallest mileage (if we could win the game, we already would have done so)
      if milesToGo <= 200:
        mileage.reverse()
        return mileage[0]
      #Return our biggest mileage
      return mileage[0]
    
  # Discard something worthless if we have it
    if len(worthlessCards) > 0:
      return worthlessCards[0]
    
    #If we are at the end of the game, discard high mileage, then remedies, then attacks, then low mileage.
    if gameState.cardsLeft == 0:
      for d in discards:
        if d.card <= 4:
          if d.card >= 2:
            return d
      for d in discards:
        if d.card <= 9:
          if d.card >= 2:
            return d
      for d in discards:
        if d.card <= 14:
          if d.card >= 2:
            return d
      for d in discards:
        if d.card <= 2:
          return d
    
    for d in discards:
      #If we have more of a remedy than there are attacks in the game, discard it.
      if Cards.cardToType(d.card) == Cards.REMEDY and discards.count(d) > self.cardsLeft[Cards.remedyToAttack(d.card)]:
        return d
      #If we have 3 of any given card, discard it.
      if discards.count(d) >= 3:
        return d
      #If we're under a speed limit, discard 75 if we have it, 100 if we already popped our safeTrip cherry, 200 if we haven't and are halfway through the race, the rest of the mileage.
      if gameState.us.speedLimit:
        if d.card == Cards.MILEAGE_75:
          return d
        if gameState.us.safeTrip and ((gameState.target == 1000 and gameState.us.handScore >= 600) or (gameState.target == 700 and gameState.us.handScore > 400)) and d.card == Cards.MILEAGE_200:
          return d
        if d.card == Cards.MILEAGE_100:
          return d
        if d.card == Cards.MILEAGE_200:
          return d
      else:
        if d.card == Cards.MILEAGE_25:
          return d
          
    #Pitch doubles next - low mileage first, then high mileage, then remedies
    for d in discards:
       if discards.count(d) > 1:
        if d.card <= 1:
          return d
    for d in discards:
      if discards.count(d) > 1:
        if d.card <= 4:
          return d
    for d in discards:
      if discards.count(d) > 1:
        if d.card <= 9:
          return d    
          
    #Pitch crappy single cards.
    if Cards.MILEAGE_25 in gameState.hand:
      return Move(Move.DISCARD, Cards.MILEAGE_25)
    if Cards.MILEAGE_75 in gameState.hand:
      return Move(Move.DISCARD, Cards.MILEAGE_75)
    if Cards.MILEAGE_50 in gameState.hand:
      return Move(Move.DISCARD, Cards.MILEAGE_50)
    if Cards.REMEDY_END_OF_LIMIT in gameState.hand:
      return Move(Move.DISCARD, Cards.REMEDY_END_OF_LIMIT)
    
    #Pitch any mileage that puts us over 700 if the target is 700
    for d in discards:
      if Cards.cardToType(d.card) == Cards.MILEAGE:
        if gameState.target == 700 and Cards.cardToMileage(d.card) + gameState.us.mileage > 700:
          return d
    
    #If we have an attack and the remedy for the attack, pitch the remedy
    for d in discards:
      if Cards.cardToType(d.card) == Cards.ATTACK:
        if Cards.attackToRemedy(d.card) in gameState.hand:
          return Move(Move.DISCARD, Cards.attackToRemedy(d.card))
          
    
    
    #Pitch duplicate attack cards now, but only if we don't have the safety for it already played.
    for d in discards:
      if discards.count(d) > 1:
        if d.card <= 14 and Cards.attackToSafety(d.card) not in gameState.us.safeties:
          return d
    
    #If we've gotten here we have a pretty good hand - so play a safety if we have one 
    if len(safeties) > 0:
      return safeties[0]
      
    #Pitch attacks we don't have the safety for
    for d in discards:
      if Cards.cardToType(d.card) == Cards.ATTACK and Cards.attackToSafety(d.card) not in gameState.us.safeties:
          return d

    #Pitch any duplicates at this point
    for d in discards:
      if discards.count(d) > 1:
        return d

    #Pitch Speed Limit next
    for d in discards:
      if d.card == 14:
        return d

    #Pitch Stop next
    for d in discards:
      if d.card == 13:
        return d

    #In nearly a million runs total this hasn't ever triggered.  But it seems best to leave it here.
    return discards[0]
Exemplo n.º 35
0
readTranscript = None
writeTranscript = None
#readTranscript = "/tmp/millegame"
#writeTranscript = "/tmp/millegame"

# End configurable parameters

if readTranscript:
  reader = TranscriptReader(
    readTranscript,
    lambda *args: stdout.write("Transcript game start!\n"),
    lambda *args: stdout.write("Transcript hand start!\n"),
    lambda game, player, drawnCard, move: stdout.write(
      "Transcript move: %d drew %s %s\n" % (
        player, Cards.cardToString(drawnCard) if drawnCard else "nothing", move)),
    lambda *args: stdout.write("Transcript hand end!\n"),
    lambda game: stdout.write("Transcript game end!  Scores: %s\n" % (
        " ".join(map(lambda team: "%d" % team.totalScore,
                     game.teams)))))
  reader.read(debug = True)
  exit(0)

players = []
competitor = 0
for i in range(numPlayers):
  players.append(competitors[competitor]())
  competitor += 1
  if competitor >= len(competitors):
    competitor = 0
Exemplo n.º 36
0
    def chanceTeamWillCompleteTrip(self, team):
        if self.useMonteCarloSimulation():
            self.debug(
                "Using monte carlo method for team trip completion estimate.")
            teamResults = [
                result[team.number + 1]
                for result in self.monteCarloMileageSimulation()
            ]
            completionCount = 0
            for result in teamResults:
                if result == 0:
                    completionCount += 1
            ret = completionCount / len(teamResults)
            self.debug("%r chance that %d will complete trip (%d/%d)", ret,
                       team.number, completionCount, len(teamResults))
        else:
            self.debug(
                "Using card-counting method for team trip completion estimate."
            )
            turnsLeft = self.deckExhaustionTurnsLeft()
            playersOnTeam = len(team.playerNumbers)
            teamMovesLeft = turnsLeft * playersOnTeam

            if team.moving:
                goCoeff = 1.0
            else:
                goCoeff = min(
                    1.0,
                    self.percentOfCardsRemaining(Cards.REMEDY_GO) *
                    teamMovesLeft)

            if team.needRemedy and team.needRemedy != Cards.REMEDY_GO:
                remedyCoeff = min(
                    1.0,
                    self.percentOfCardsRemaining(
                        team.needRemedy, Cards.remedyToSafety(team.needRemedy))
                    * teamMovesLeft)
            else:
                remedyCoeff = 1.0

            if goCoeff == 0.0 or remedyCoeff == 0.0:
                self.debug(
                    "Team %d can't complete trip due to remedy unavailable.",
                    team.number)
                return 0.0

            needMileage = 1000 - team.mileage
            validMileageCards = [
                card for card in Cards.MILEAGE_CARDS
                if Cards.cardToMileage(card) <= needMileage
            ]
            validMileageCards.sort(reverse=True)
            validMileagePct = self.percentOfCardsRemaining(*validMileageCards)
            unseenTotalMileage = sum([
                Cards.cardToMileage(card) * self.cardsUnseen[card]
                for card in validMileageCards
            ])
            if unseenTotalMileage < needMileage:
                self.debug(
                    "Not enough mileage left in deck for team %d to complete trip.",
                    team.number)
                ret = 0.0
            else:
                ret = min(1.0, (validMileagePct *
                                (unseenTotalMileage / needMileage) *
                                teamMovesLeft * remedyCoeff * goCoeff))
                self.debug(
                    "Team %d has %r of trip completion, based on crude card count: %r * (%r / %r) * %r * %r * %r",
                    team.number, ret, validMileagePct, unseenTotalMileage,
                    needMileage, teamMovesLeft, remedyCoeff, goCoeff)

        return ret
Exemplo n.º 37
0
  def monteCarloMileageSimulation(self):
    # Returns a list of many (turns elapsed, team 0 trip mileage remaining, team 1 trip remaining, ...)
    # TODO: Assumes extension.
    results = []
    for _ in xrange(self.perfConstants.monteCarloIterations):
      needMileage = dict((team.number, team.mileage) for team in self.gameState.teams)
      moving = dict((team.number, team.moving) for team in self.gameState.teams)
      needRemedy = dict((team.number, team.needRemedy) for team in self.gameState.teams)
      twoHundredsPlayed = dict((team.number, team.twoHundredsPlayed) for team in self.gameState.teams)

      tripCompletedBy = None
      deck = collections.deque()
      for (card, qty) in self.cardsUnseen.iteritems():
        for _ in xrange(qty):
          deck.append(card)
      random.shuffle(deck)

      turnsElapsed = 1
      while deck:
        for currentTurnTeam in self.gameState.teams:
          if not deck:
            break

          teamNo = currentTurnTeam.number
          teamNeedMileage = needMileage[teamNo]
          teamNeedRemedy = needRemedy[teamNo]
          teamMoving = moving[teamNo]
          teamTwoHundredsPlayed = twoHundredsPlayed[teamNo]
          if teamNeedRemedy:
            teamNeedSafety = Cards.remedyToSafety(teamNeedRemedy)
          else:
            teamNeedSafety = None

          for playerNum in currentTurnTeam.playerNumbers:
            if tripCompletedBy == playerNum:
              deck = None
              break
            if not deck:
              break

            card = deck.pop()
            cardType = Cards.cardToType(card)
            if Cards.cardToType(card) != Cards.MILEAGE:
              if card == Cards.REMEDY_GO:
                teamMoving = True
                if teamNeedRemedy == Cards.REMEDY_GO:
                  teamNeedRemedy = None
              elif teamNeedRemedy:
                if ((cardType == Cards.SAFETY and teamNeedSafety == card) or
                    (cardType == Cards.REMEDY and needRemedy[teamNo] == card)):
                  teamNeedRemedy = None
            else:
              mileage = Cards.cardToMileage(card)
              if mileage == 200 and teamTwoHundredsPlayed >= 2:
                continue
              elif mileage > teamNeedMileage:
                continue
              elif mileage == 200:
                teamTwoHundredsPlayed += 1

              teamNeedMileage -= mileage

            if teamNeedMileage == 0 and teamMoving and not teamNeedRemedy:
              tripCompletedBy = playerNum
              break

          needMileage[teamNo] = teamNeedMileage
          needRemedy[teamNo] = teamNeedRemedy
          moving[teamNo] = teamMoving
          twoHundredsPlayed[teamNo] = teamTwoHundredsPlayed

        turnsElapsed += 1

      result = [turnsElapsed]
      for i in xrange(len(self.gameState.opponents) + 1):
        if i == self.gameState.us.number:
          team = self.gameState.us
        else:
          team = self.gameState.teamNumberToTeam(i)

        if needRemedy[i] or not moving[i]:
          mileage = 1000 - team.mileage
        else:
          mileage = needMileage[i]
        result.append(mileage)
      results.append(result)
    return results
Exemplo n.º 38
0
    def makeMove(self, gameState):
        discards = []
        mileage = []
        attacks = []
        remedies = []
        safeties = []

        cardsPlayed = []
        us = gameState.us
        cardsPlayed = cardsPlayed + us.mileagePile
        cardsPlayed = cardsPlayed + us.speedPile
        cardsPlayed = cardsPlayed + us.battlePile
        cardsPlayed = cardsPlayed + us.safeties

        MyMileage = us.mileage
        MyRunningTotal = MyMileage + us.totalScore + len(us.safeties) * 100 + us.coupFourres * 300

        opponents = gameState.opponents
        ourSafeties = us.safeties
        playedSafeties = ourSafeties
        opponentsCount = 0
        opponentsSafeties = []
        for opponent in opponents:
            opponentsCount = opponentsCount + 1
            opponentsSafeties = opponentsSafeties + opponent.safeties
            cardsPlayed = cardsPlayed + opponent.mileagePile
            cardsPlayed = cardsPlayed + opponent.speedPile
            cardsPlayed = cardsPlayed + opponent.battlePile
            cardsPlayed = cardsPlayed + opponent.safeties
        playedSafeties = playedSafeties + opponentsSafeties

        cardsPlayed = cardsPlayed + gameState.discardPile
        cardPlayedByType = {}
        for x in xrange(0, 19):
            cardPlayedByType[x] = 0

        for card in cardsPlayed:
            cardPlayedByType[card] += 1

        target = gameState.target
        target_minus_25 = target - 25
        target_minus_50 = target - 50
        target_minus_75 = target - 75
        target_minus_100 = target - 100
        target_minus_200 = target - 200

        for play in gameState.validMoves:
            if play.type == Move.DISCARD:
                discards.append(play)
            else:
                type = Cards.cardToType(play.card)
                if type == Cards.MILEAGE:
                    mileage.append(play)
                elif type == Cards.REMEDY:
                    remedies.append(play)
                elif type == Cards.ATTACK:
                    attacks.append(play)
                elif type == Cards.SAFETY:
                    safeties.append(play)

        #######################
        #  IF CAN GO FOR WIN  DO IT!
        #######################

        if len(mileage) > 0:
            if us.mileage == target_minus_25:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_25:
                        return mi
            elif us.mileage == target_minus_50:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_50:
                        return mi
            elif us.mileage == target_minus_75:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_75:
                        return mi
            elif us.mileage == target_minus_100:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_100:
                        return mi
            elif us.mileage == target_minus_200:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_200:
                        return mi

        ########################
        #  play a red card based on weighted factors
        #  but check to see if the corrosponding safety is known in play or in your hand
        #  if not known  dont play if less then X cards in deck
        #####################################

        numberOfCardsLeftToNotAttack = 10

        if len(attacks) > 0:
            highestWeight = -10
            weightedAttacks = {}
            for attack in attacks:
                opponent = gameState.teamNumberToTeam(attack.target)
                opponentMileage = opponent.mileage
                opponentRunningTotal = (
                    opponentMileage + opponent.totalScore + len(opponent.safeties) * 100 + opponent.coupFourres * 300
                )
                weight = 0
                if opponentRunningTotal >= 3000:
                    #         print "opponentRunningTotal >= 3500"
                    weight += 1
                if opponentRunningTotal >= 3500:
                    #         print "opponentRunningTotal >= 3500"
                    weight += 1
                if opponentRunningTotal >= 4000:
                    #          print "opponentRunningTotal >= 4000"
                    weight += 1
                if opponentRunningTotal >= 4500:
                    #         print "opponentRunningTotal >= 4500"
                    weight += 2
                if opponentRunningTotal >= MyRunningTotal + 1000:
                    #        print "opponentRunningTotal >= myRunningTotal+2000"
                    weight += 1
                if opponentRunningTotal >= MyRunningTotal + 2000:
                    #        print "opponentRunningTotal >= myRunningTotal+2000"
                    weight += 3
                if opponentMileage >= MyMileage + 400:
                    #       print "opponentMileage >= my mileage + 400"
                    weight += 1

                if opponentMileage >= target_minus_200:
                    if opponentMileage >= target_minus_50 and attack.card == Cards.ATTACK_SPEED_LIMIT:
                        weight = -10
                    #        print "opponet withi 50 of end and attack=limit"
                    else:
                        weight += 1
                #       print "opponent within 200 of end"
                if attack.card != Cards.ATTACK_SPEED_LIMIT and attack.card != Cards.ATTACK_STOP:
                    weight += 0.6
                if attack.card == Cards.ATTACK_SPEED_LIMIT:
                    weight += 0
                if attack.card == Cards.ATTACK_STOP:
                    weight += 0.01
                #    print "attack card not limit or stop"

                corrospondingSafetyisNotKnown = True
                corrospondingSafety = Cards.attackToSafety(attack.card)
                if cardPlayedByType[corrospondingSafety] == 1:
                    corrospondingSafetyisNotKnown = False
                for safet in safeties:
                    if Cards.attackToSafety(attack.card) == safet.card:
                        corrospondingSafetyisNotKnown = False

                if corrospondingSafetyisNotKnown:
                    if gameState.cardsLeft < numberOfCardsLeftToNotAttack:
                        weight = -10  # nop
                    #     print "safety NOT known and gameState.cardsLeft < numberOfCardsLeftToNotAttack"
                    else:
                        #    print "safety not known"
                        weight -= 0.5
                    # print "proceed with attack!!!!!!!!!!"
                else:
                    # print "safety KNOWN!"
                    weight += 0.5
                # print "weight="+str(weight)
                if weight > highestWeight:
                    highestWeight = weight
                weightedAttacks[weight] = attack

            if highestWeight > -1:
                # print "=============highest Weight="+str(highestWeight)
                # print weightedAttacks[highestWeight]
                return weightedAttacks[highestWeight]

        ##################3
        # play a remedy
        ##################

        if len(remedies) > 0:
            remedies.sort(key=lambda x: x.card)
            if remedies[0].card == Cards.REMEDY_END_OF_LIMIT and us.mileage >= target_minus_50 and len(mileage) > 0:
                mileage.sort(key=lambda x: x.card, reverse=True)
                # print "remedy= EOL AND us.mileage="+str(us.mileage)+" mileage[0]="+str(mileage[0].card)
                return mileage[0]
            else:
                return remedies[0]

        #####################
        # play a mileage:
        #      first check to see if you are 200 or less away, if any 2 card combonation in hand will finish race
        #      if not, play highest mileage
        ######################

        if len(mileage) > 0:
            mileage.sort(key=lambda x: x.card, reverse=True)
            if len(mileage) > 2 and us.mileage > target_minus_200:
                num = 0

                for mi in mileage:
                    num += 1
                    mileageCopy = mileage[num:]
                    for mi2 in mileageCopy:
                        mivalue = Cards.cardToMileage(mi.card)
                        mi2value = Cards.cardToMileage(mi2.card)
                        total = us.mileage + mivalue + mi2value
                        if total == target:
                            return mi
            return mileage[0]

        ##############################
        #  If have safety that solves a problem we have... use it
        ############################

        remedyNeeded = us.needRemedy
        if remedyNeeded > 0:
            for safet in safeties:
                if safet.card == Cards.remedyToSafety(remedyNeeded):
                    return safet
        if us.speedLimit == True:
            for safet in safeties:
                if safet.card == Cards.SAFETY_RIGHT_OF_WAY:
                    return safet

        ####################
        # ENTER EASY DISCARD PHASE
        ##############

        # reuse these because this used to be in a seperate function
        mileage = []
        attacks = []
        remedies = []

        for play in discards:
            type = Cards.cardToType(play.card)
            if type == Cards.MILEAGE:
                mileage.append(play)
            elif type == Cards.REMEDY:
                remedies.append(play)
            elif type == Cards.ATTACK:
                attacks.append(play)

        ##################
        # Remedies we have safeties for in play, in hand or for all attacks have been played
        ################

        if len(remedies) > 0:
            for remedy in remedies:
                for safet in safeties:
                    if Cards.remedyToSafety(remedy.card) == safet.card:
                        return remedy

                if Cards.remedyToSafety(remedy.card) in ourSafeties:
                    return remedy
                corrospondingAttack = Cards.remedyToAttack(remedy.card)
                if corrospondingAttack == Cards.ATTACK_FLAT_TIRE:
                    if cardPlayedByType[Cards.ATTACK_FLAT_TIRE] == 3:
                        #            print "discard spare due to all flats played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_OUT_OF_GAS:
                    if cardPlayedByType[Cards.ATTACK_OUT_OF_GAS] == 3:
                        #           print "discard gas due to all out of gas played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_ACCIDENT:
                    if cardPlayedByType[Cards.ATTACK_ACCIDENT] == 3:
                        #          print "discard repairs due to all accidents played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_SPEED_LIMIT:
                    if cardPlayedByType[Cards.ATTACK_SPEED_LIMIT] == 4:
                        #         print "discard end of limit due to all spedlimits played"
                        return remedy

        ########################
        #   Attacks that opponents have safeties for (if not 3 or 6 person game)
        ######################

        if len(attacks) > 0:
            if opponentsCount == 1:
                for attack in attacks:
                    if Cards.attackToSafety(attack.card) in opponentsSafeties:
                        return attack

        ###################
        # mileage discard due to limit:
        #     if an opponent has right of way and all EOL played and we have speed limit  discard mileage over 50
        ######################

        mileage.sort(key=lambda x: x.card)
        if len(mileage) > 0:
            opponentRightOfWay = False
            for safet in opponentsSafeties:
                if safet == Cards.SAFETY_RIGHT_OF_WAY:
                    opponentRightOfWay = True
            if cardPlayedByType[Cards.REMEDY_END_OF_LIMIT] == 6 and us.speedLimit and opponentRightOfWay:

                for mi in mileage:
                    if mi.card > 1:
                        # print "discarding mi:" + Cards.cardToString(mi.card)
                        return mi

            ########################
            #  milage that we can no longer play due to being to close to the end
            # or playing 2 2 hundreds
            #########################

            thp = us.twoHundredsPlayed

            for mi in mileage:

                if thp == 2 or us.mileage > target_minus_200:
                    if mi.card == Cards.MILEAGE_200:
                        return mi
                if us.mileage > target_minus_100:
                    if mi.card == Cards.MILEAGE_100:
                        return mi
                if us.mileage > target_minus_75:
                    if mi.card == Cards.MILEAGE_75:
                        return mi
                if us.mileage > target_minus_50:
                    if mi.card == Cards.MILEAGE_50:
                        return mi

        #########################
        #  Enter "Smart" discard phases
        ########################

        ########################
        # Remedy smart discard:  remedies we have dupes of (save 1 of each, except GO  save 2)
        ###########################

        remedyDupes = {}
        for x in xrange(5, 10):
            remedyDupes[x] = 0
        if len(remedies) > 0:
            for remedy in remedies:
                remedyDupes[remedy.card] += 1
            if remedyDupes[Cards.REMEDY_SPARE_TIRE] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_SPARE_TIRE:
                        return remedy
            elif remedyDupes[Cards.REMEDY_GASOLINE] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_GASOLINE:
                        return remedy
            elif remedyDupes[Cards.REMEDY_REPAIRS] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_REPAIRS:
                        return remedy
            elif remedyDupes[Cards.REMEDY_GO] > 2:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_GO:
                        return remedy
            elif remedyDupes[Cards.REMEDY_END_OF_LIMIT] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_END_OF_LIMIT:
                        return remedy

        ####################
        # play a safety as no more easy discards are available
        ###################

        # Play a safety rather than discard
        if len(safeties) > 0:

            return safeties[0]

        ####################
        #  attack smart discard: if have more then 2 attack cards  discard stops/ speedlimits
        ####################

        attackDupes = {}
        for x in xrange(10, 16):
            attackDupes[x] = 0

        if len(attacks) > 0:
            totalAttackCardsInHand = 0
            for attack in attacks:
                totalAttackCardsInHand += 1
                attackDupes[attack.card] += 1
            if totalAttackCardsInHand > 2:
                for attack in attacks:
                    if attack.card == Cards.ATTACK_SPEED_LIMIT:
                        return attack
                    if attack.card == Cards.ATTACK_STOP:
                        return attack

        #####################
        # final "smart" discard: if more then one mileage in hand discard lowest mileage
        # if exactly 1 mileage in hand  first discard a non GO remedy(starting with EOL, then an attack (order EOL, stop, then others)
        ########################

        if len(mileage) > 0:
            if len(mileage) == 1:

                remedies.sort(key=lambda x: x.card, reverse=True)
                for remedy in remedies:
                    if remedy.card != Cards.REMEDY_GO:
                        return remedy
                attacks.sort(key=lambda x: x.card, reverse=True)
                for attack in attacks:
                    return attack
            else:
                return mileage[0]

        ##################
        #  discard whatever is left
        ##################

        return discards[0]  # toDiscard
Exemplo n.º 39
0
  def chanceTeamWillCompleteTrip(self, team):
    if self.useMonteCarloSimulation():
      self.debug("Using monte carlo method for team trip completion estimate.")
      teamResults = [result[team.number + 1]
                     for result
                     in self.monteCarloMileageSimulation()]
      completionCount = 0
      for result in teamResults:
        if result == 0:
          completionCount += 1
      ret = completionCount/len(teamResults)
      self.debug("%r chance that %d will complete trip (%d/%d)",
                 ret, team.number, completionCount, len(teamResults))
    else:
      self.debug("Using card-counting method for team trip completion estimate.")
      turnsLeft = self.deckExhaustionTurnsLeft()
      playersOnTeam = len(team.playerNumbers)
      teamMovesLeft = turnsLeft * playersOnTeam

      if team.moving:
        goCoeff = 1.0
      else:
        goCoeff = min(1.0, self.percentOfCardsRemaining(Cards.REMEDY_GO) * teamMovesLeft)

      if team.needRemedy and team.needRemedy != Cards.REMEDY_GO:
        remedyCoeff = min(1.0, self.percentOfCardsRemaining(
            team.needRemedy,
            Cards.remedyToSafety(team.needRemedy)) * teamMovesLeft)
      else:
        remedyCoeff = 1.0

      if goCoeff == 0.0 or remedyCoeff == 0.0:
        self.debug("Team %d can't complete trip due to remedy unavailable.", team.number)
        return 0.0

      needMileage = 1000 - team.mileage
      validMileageCards = [card
                           for card in Cards.MILEAGE_CARDS
                           if Cards.cardToMileage(card) <= needMileage]
      validMileageCards.sort(reverse=True)
      validMileagePct = self.percentOfCardsRemaining(*validMileageCards)
      unseenTotalMileage = sum([Cards.cardToMileage(card) * self.cardsUnseen[card]
                                for card in validMileageCards])
      if unseenTotalMileage < needMileage:
        self.debug("Not enough mileage left in deck for team %d to complete trip.",
                   team.number)
        ret = 0.0
      else:
        ret = min(1.0,
                  (validMileagePct *
                   (unseenTotalMileage / needMileage) *
                   teamMovesLeft *
                   remedyCoeff *
                   goCoeff))
        self.debug("Team %d has %r of trip completion, based on crude card count: %r * (%r / %r) * %r * %r * %r",
                   team.number,
                   ret,
                   validMileagePct,
                   unseenTotalMileage,
                   needMileage,
                   teamMovesLeft,
                   remedyCoeff,
                   goCoeff)

    return ret
Exemplo n.º 40
0
  def goForExtension(self, gameState):
    milesInHand = 0
    opponentScore = 0
    haveATwoHundred = False
    dangerscore = 0
    remainingCards = 0
    expectedMiles = 0
    totalPlayers = len(gameState.us.playerNumbers)
    if totalPlayers == 3 or totalPlayers == 6:
      numTeams = 3
    else:
      numTeams = 2
      
    for i in self.cardsLeft:
      remainingCards += self.cardsLeft[i]
    
    for i in gameState.opponents:
      totalPlayers += len(i.playerNumbers)
      opponentScore = i.totalScore + i.mileage + 100 * len(i.safeties) + 300 * i.coupFourres
      if opponentScore > 5000:
        dangerscore = opponentScore
        
    scoreIfWeStop = gameState.us.totalScore + 700 + 100 * len(gameState.us.safeties) + 300 * gameState.us.coupFourres + 400
    if remainingCards == 0:
      scoreIfWeStop += 300
    if gameState.us.safeTrip == True:
      scoreIfWeStop += 300
    #I am being lazy and not including shutout - if we have a shutout it's kinda hard to mess up.
    
    #Don't go for an extension if the win puts us over 5000 points and no opponent would have more
    if scoreIfWeStop >= 5000 and scoreIfWeStop > dangerscore:
      return False
    
    #Can't lose the game on purpose!
    if dangerscore > scoreIfWeStop:
      return True
      
    #If we have a safe trip let's not mess with it and just stop now.  This makes later logic much easier for 200 cards.
    if gameState.us.safeTrip == True:
      return False
    
    for h in gameState.hand:
      if Cards.cardToType(h) == Cards.MILEAGE:
        if h == Cards.MILEAGE_200 and gameState.us.twoHundredsPlayed == 1:
          haveATwoHundred = True
          milesInHand += Cards.cardToMileage(h)
        else:
          milesInHand += Cards.cardToMileage(h)

    #We have enough to make it directly, so let's go for it.    
    if milesInHand >= 300:
      return True

    #If we don't have 300 miles in hand and there are no cards to draw then we definitely don't want to go for it.
    if remainingCards == 0:
      return False
      
    #Plan: Assign equal probability for any mileage to be in any given players' unknown cards, remove those from the list.
    #Assign equal weight to draw each card to our team (just use 2 vs 3 for simplicity)
    #If we should draw the mileage we need more than X% of the time, we should go for it.
    #Start with x = 57%, test different values though on 50k runs minimum - start with 0%, 57%, 100%, make sure we can see
    #A difference over 50k runs, then adjust up or down from 57% based on results using a half the distance method.
    #Note: 57% is 4/7 and should be GTO based on scoring considerations.
      
    #Need to handle 200 mileage cards differently - we could only play 1, and we can only do that if we haven't played 2.
    #Making these floats also because math.
    unknown25s = self.cardsLeft[0] * 1.0
    unknown50s = self.cardsLeft[1] * 1.0
    unknown75s = self.cardsLeft[2] * 1.0
    unknown100s = self.cardsLeft[3] * 1.0
    
    
    #If we can play a 200 and they exist in the deck
    if gameState.us.twoHundredsPlayed == 1 and self.cardsLeft[4] > 0:
      unknown200s = self.cardsLeft[4] * 1.0
      #Subtract expected number of 200s left in the deck after accounting for other players' hands
      unknown200s -= unknown200s * (6.0 * (totalPlayers - 1) / remainingCards)
      #Presume even chance for us to get one, but we can only use one.
      if (unknown200s / totalPlayers) > 1.0:
        expectedMiles += 200
      #If there's less than an even chance for us to get one, expected miles goes up by the chance we'll get one times 200.
      else:
        expectedMiles += (unknown200s / totalPlayers) * 200
      
    #We can use any number of 100s/75s/50s/25s so we can just do this:
    unknown100s -= unknown100s * (6.0 * (totalPlayers - 1) / remainingCards)
    expectedMiles += (unknown100s / totalPlayers) * 100

    unknown75s -= unknown75s * (6.0 * (totalPlayers - 1) / remainingCards)
    expectedMiles += (unknown75s / totalPlayers) * 75

    unknown50s -= unknown50s * (6.0 * (totalPlayers - 1) / remainingCards)
    expectedMiles += (unknown50s / totalPlayers) * 50        

    unknown25s -= unknown25s * (6.0 * (totalPlayers - 1) / remainingCards)
    expectedMiles += (unknown25s / totalPlayers) * 25
      
    #Amazingly this is the same for any game size.
    if expectedMiles >= 1250:
      return True
  
    else:
      return False
Exemplo n.º 41
0
  def cardValue(self, card, cardIdx, cards):
    # cardIdx and cards let us disambiguate between two equal cards in our hand.
    #
    # All equally worthless:
    # * Safeties in play or elsewhere in our hand
    # * Remedies for safeties in play or elsewhere in our hand
    # * 200mi if we've already maxed out
    # * Mileage > distance remaining (assuming extension will be played)
    #   TODO: ...but what if an extension *won't* be played?
    # * Safeties we have in our hand

    # How many of this card do we already have in our hand?
    numDuplicates = len([c for c in cards if c == card])
    # Make this card less valuable if we have more if it on our hand.
    # The obvious thing to do is a straight divisor:
    # If we have 2 dupes, value each at 1/2; if 3, value each at 1/3.
    # But that's too severe, having 2 200km is more valuable than having
    # 1 200km!  So, we take the "duplicate fraction", 1/numDuplicates,
    # and we want to scale down *the inverse of that* to bring it
    # nearer to 1 (to reduce the severity of the penalty), and then
    # invert again to cancel out the inversion.
    dupeFrac = 1/numDuplicates
    dupePenaltyFactor = self.__class__.constants.dupe_penalty_factor
    dupeCoefficient = 1-(1-dupeFrac)/dupePenaltyFactor

    cardType = Cards.cardToType(card)
    if cardType == Cards.MILEAGE:
      mileage = Cards.cardToMileage(card)
      mileageRemaining = 1000 - self.gameState.us.mileage
      if mileage > mileageRemaining:
        return 0.0 * dupeCoefficient
      elif mileage == 200 and self.gameState.us.twoHundredsPlayed >= 2:
        return 0.0 * dupeCoefficient
      elif mileage == 25 and cards.index(card) == cardIdx:
        # Try to hold onto a single 25km card in case we need it to finish.
        return 1.0 * dupeCoefficient
      else:
        return self.mileageCardValue(card) * dupeCoefficient
    elif cardType == Cards.REMEDY:
      
      # Attacks that could necessitate this card.
      if card == Cards.REMEDY_GO:
        relevantAttacks = Cards.ATTACKS[:]
      else:
        relevantAttacks = [Cards.remedyToAttack(card)]

      relevantAttacks = [c for c in relevantAttacks
                         if not Cards.attackToSafety(c) in self.gameState.us.safeties + cards]

      # Factor in:
      # 1. Value of taking a turn.
      # 2. Likelihood of getting hit with a relevant attack.
      #    (Number of attacks remaining / number of teams in game.)
      #    NB: If no attacks are relevant, this will be 0.
      # TODO: Also add likelihood of drawing another remedy (or the safety.)
      turnPoints = self.expectedTurnPoints(self.gameState.us)
      turnPointValue = self.valueOfPoints(turnPoints, self.gameState.us)
      # Hold onto at least one of the card if we already know we need it!
      if (cards.index(card) == cardIdx and
          ((not self.gameState.us.moving and card == Cards.REMEDY_GO) or
           (self.gameState.us.speedLimit and card == Cards.REMEDY_END_OF_LIMIT) or
           (self.gameState.us.needRemedy and card == self.gameState.us.needRemedy))):
        self.debug("We need %s, attack on us odds == 1.0!", Cards.cardToString(card))
        attackOnUsOdds = 1.0
      else:
        attackOdds = self.percentOfCardsRemaining(*relevantAttacks) * self.expectedTurnsLeft()
        attackOnUsOdds = attackOdds / (len(self.gameState.opponents) + 1)
      value = turnPointValue * attackOnUsOdds
      self.debug("Card %s val: %r = %r * %r = val(%d) * pctLeft(%s)/#teams",
                 Cards.cardToString(card),
                 value,
                 turnPointValue, attackOnUsOdds,
                 turnPoints,
                 ",".join([Cards.cardToString(c) for c in relevantAttacks]))
      return value * dupeCoefficient
    elif cardType == Cards.SAFETY:
      # Never discard a safety!
      # (Assuming default deck composition of 1 of each type...)
      return 1.0 * dupeCoefficient
    elif cardType == Cards.ATTACK:
      safety = Cards.attackToSafety(card)
      remedy = Cards.attackToRemedy(card)

      valuesPerTarget = []
      for target in self.gameState.opponents:
        valuesPerTarget.append(
          (1-self.chanceOpponentHasProtection(target, card)) *
          (1-self.percentOfCardsRemaining(safety, remedy)) *
          self.valueOfPoints(self.expectedTurnPoints(target), target))
      return sum(valuesPerTarget)/len(valuesPerTarget) * dupeCoefficient
    else:
      raise Exception("Unknown card type for %r: %r" % (card, cardType))
Exemplo n.º 42
0
  def makeMove(self, gameState):
    # If an opponent is threatening to win, play safeties
    for opponent in gameState.opponents:
      if (opponent.mileage > gameState.target - 100
        or (opponent.mileage == gameState.target - 200
            and opponent.twoHundredsPlayed < 2)):
        self.priorities[Move(Move.PLAY, Cards.SAFETY_PUNCTURE_PROOF)] = 100
        self.priorities[Move(Move.PLAY, Cards.SAFETY_DRIVING_ACE)] = 100
        self.priorities[Move(Move.PLAY, Cards.SAFETY_RIGHT_OF_WAY)] = 100
        self.priorities[Move(Move.PLAY, Cards.SAFETY_EXTRA_TANK)] = 100
        break

    # If we can't play any more 200s, they're automatic discards
    if gameState.us.twoHundredsPlayed == 2:
      self.priorities[Move(Move.DISCARD, Cards.MILEAGE_200)] = 0

    # Adjust priorities based on our hand contents
    priorities = deepcopy(self.priorities)
    attackCounts = copy(self.attackCounts)
    remedyCounts = {}
    for card in gameState.hand:
      type = Cards.cardToType(card)
      if type == Cards.ATTACK:
        ElliotAI.adjustScoresForAttack(card, attackCounts, priorities)
      elif type == Cards.REMEDY:
        try:
          remedyCounts[card] += 1
        except KeyError:
          remedyCounts[card] = 1
    for remedy, count in remedyCounts.items():
      if remedy == Cards.REMEDY_GO:
        if count > 3:
          self.priorities[Move(Move.DISCARD, remedy)] = 0
        elif count > 2:
          self.priorities[Move(Move.DISCARD, remedy)] = -2
      else:
        if count > 2:
          self.priorities[Move(Move.DISCARD, remedy)] = 0
        elif count == 2:
          self.priorities[Move(Move.DISCARD, remedy)] = -2

    movePriorities = {}
    
    # Shuffle possible plays so that we pick a random move when two
    # are equally good
    shuffle(gameState.validMoves)
    for play in gameState.validMoves:
      try:
        priority = self.priorities[play]
        movePriorities[priority] = play
      except:
        pass

    sortedMoves = sorted(movePriorities.items(), None, None, True)
    if gameState.debug:
      for i in sortedMoves:
        print str(i[0]) + ': ' + str(i[1])
    myMove = sortedMoves[0][1]

    # If this move would make us win, see if we can play a safety first
    # instead
    if (myMove.type == Move.PLAY
        and Cards.cardToType(myMove.card) == Cards.MILEAGE
        and Cards.cardToMileage(myMove.card) + gameState.us.mileage == gameState.target):
      for move in gameState.validMoves:
        if (move.type == Move.PLAY
            and Cards.cardToType(move.card) == Cards.SAFETY):
          return move

    return myMove
Exemplo n.º 43
0
  def makeMove(self, state):

    if (state.us.needRemedy == Cards.REMEDY_GO):
      self.needRoll = self.needRoll + 1
    else:
      self.needRoll = 0

    # Miles we need to win
    self.milesLeft = state.target - state.us.mileage
    
    discards = []
    mileage = []
    attacks = []
    remedies = []
    safeties = []
    #print '--- AI cards ---'
    #print Cards.cardsToStrings(state.hand)
    #print '------'
    for play in state.validMoves:
      if (play.type == Move.DISCARD):
        discards.append(play)
      else:
        type = Cards.cardToType(play.card)
        if type == Cards.MILEAGE:
          mileage.append(play)
        elif type == Cards.REMEDY:
          remedies.append(play)
        elif type == Cards.ATTACK:
          attacks.append(play)
        elif type == Cards.SAFETY:
          safeties.append(play)

    # If there's only one card left, play a safety to draw it
    if ((state.cardsLeft == 1) & (len(safeties)>0)):
        return safeties[0]

    # Could this be the last round?
    lastRound = False
    iCanWin = False
    if (((self.milesLeft == 25) & (Cards.MILEAGE_25 in state.hand)) |
        ((self.milesLeft == 50) & (Cards.MILEAGE_50 in state.hand)) |
        ((self.milesLeft == 75) & (Cards.MILEAGE_75 in state.hand)) |
        ((self.milesLeft == 100) & (Cards.MILEAGE_100 in state.hand)) |
        ((self.milesLeft == 200) & (Cards.MILEAGE_200 in state.hand))):
      lastRound = True
      iCanWin = True
    for team in state.opponents:
      milesOther = state.target - team.mileage
      if ((milesOther == 25) | (milesOther == 50) | (milesOther == 75) |
          (milesOther == 100) | (milesOther == 200)):
        lastRound = True

    # If anyone can win and I have a safety, play it.
    if (lastRound) & (len(safeties) > 0):
      return safeties[0]

    # Play the best red card if possible, unless I can win
    if ((not(iCanWin)) & (len(attacks) > 0)):
      best = self.GetBestAttack(state, attacks)
      return best

    # Play a remedy, EoL as lowest priority
    for remedy in remedies:
      if remedy.card != Cards.REMEDY_END_OF_LIMIT:
        return remedy
    # Consider EoL now, unless near the end of the game
    for remedy in remedies:
        # Play EOL unless near the end of the game
        if (self.milesLeft > 50):
          return remedy

    # If we can move, play the highest mileage; this may win
    if len(mileage) > 0:
      best = self.GetBestMove(state, mileage)
      return best

    # Consider playing a safety
    if len(safeties) > 0:
      safety = self.ConsiderPlaySafety(state, safeties)
      if (not safety is None):
        return safeties[0]
    
    # Discard something
    disc = self.GetDiscard(state, discards)
    if (not (disc is None)):
      return disc

    # Hand is all safeties and attacks.  Play safety
    if len(safeties) > 0:
      return safeties[0]
    # Discard random
    return discards[0]
Exemplo n.º 44
0
debug = False

readTranscript = None
writeTranscript = None
#readTranscript = "/tmp/millegame"
#writeTranscript = "/tmp/millegame"

# End configurable parameters

if readTranscript:
    reader = TranscriptReader(
        readTranscript, lambda *args: stdout.write("Transcript game start!\n"),
        lambda *args: stdout.write("Transcript hand start!\n"),
        lambda game, player, drawnCard, move: stdout.write(
            "Transcript move: %d drew %s %s\n" %
            (player, Cards.cardToString(drawnCard)
             if drawnCard else "nothing", move)),
        lambda *args: stdout.write("Transcript hand end!\n"),
        lambda game: stdout.write("Transcript game end!  Scores: %s\n" % (
            " ".join(map(lambda team: "%d" % team.totalScore, game.teams)))))
    reader.read(debug=True)
    exit(0)

players = []
competitor = 0
for i in range(numPlayers):
    players.append(competitors[competitor]())
    competitor += 1
    if competitor >= len(competitors):
        competitor = 0
Exemplo n.º 45
0
  def moveValue(self, move, discardIdx, discardCards):
    # Value of a move is the amount it moves us closer to winning,
    # or (amount it harms an opponent / number of opponents), or
    # (for discard) expected net value of replacement card.

    card = move.card
    cardType = Cards.cardToType(card)

    if move.type == Move.DISCARD:
      cardValue = self.cardValue(card, discardIdx, discardCards)
      # TODO: Factor in expected value of replacement card.
      return (1 - cardValue) * self.__class__.constants.discard_move_value_penalty

    # TODO: Factor in "safe trip" cost of playing 200km,
    # "shutout" cost of failing to play an attack,
    # and "delayed action" cost of failing to discard.

    card = move.card
    cardType = Cards.cardToType(card)
    if cardType == Cards.MILEAGE:
      # TODO: Avoid playing a 75 unless we have a 25,
      # and avoid playing a 25 unless we need it.
      value = self.mileageCardValue(card)
      mileage = Cards.cardToMileage(card)

      if mileage == 200 and self.gameState.us.twoHundredsPlayed == 0:
        safeTripFactor = self.__class__.constants.safe_trip_factor
      else:
        safeTripFactor = 1.0

      if mileage == self.gameState.target - self.gameState.us.mileage:
        return 1.0 * safeTripFactor
      elif mileage == 25 and len([card for card in discardCards if card == card]) < 2:
        # Don't play our last 25km (unless we need to).
        return 0.0
      else:
        return value * safeTripFactor
    elif cardType == Cards.REMEDY:
      if card == Cards.REMEDY_END_OF_LIMIT and not self.gameState.us.speedLimit:
        return 0.0

      # If we need a remedy to move, and we have that remedy, it's a rather strong play!
      return 1.0
    elif cardType == Cards.SAFETY:
      return self.__class__.constants.safety_horde_factor
    elif cardType == Cards.ATTACK:
      target = self.gameState.teamNumberToTeam(move.target)
      if card == Cards.ATTACK_SPEED_LIMIT:
        # If they're already under a speed limit, don't bother with another.
        if target.speedLimit:
          return 0.0
      else:
        # If they already need a remedy, don't bother with another -- unless they need
        # "go", in which case the attack is still worthwhile because now they need
        # the specific attack's remedy *in addition to* go.
        if target.needRemedy and target.needRemedy != Cards.REMEDY_GO:
          return 0.0

      # TODO: Balance these, and also factor in chance opponent can get protection in the future.
      # And also factor in trip distance remaining for speed limit.
      if card == Cards.ATTACK_STOP:
        attackQualityModifier = self.__class__.constants.attack_quality_mod_stop
      elif card == Cards.ATTACK_SPEED_LIMIT:
        attackQualityModifier = self.__class__.constants.attack_quality_mod_limit
      else:
        attackQualityModifier = 1.0

      # TODO: Add an "aggressiveness" constant?
      return ((1 - self.chanceOpponentHasProtection(target, card)) *
              self.chanceTeamWillWin(target) *
              self.chanceTeamWillCompleteTrip(target) *
              attackQualityModifier *
              self.__class__.constants.aggressiveness)


    # than playing them outright, so that we can save safeties for coup fourre.
    if len(safeties) > 0:
      return safeties[0]
Exemplo n.º 46
0
    def moveValue(self, move, discardIdx, discardCards):
        # Value of a move is the amount it moves us closer to winning,
        # or (amount it harms an opponent / number of opponents), or
        # (for discard) expected net value of replacement card.

        card = move.card
        cardType = Cards.cardToType(card)

        if move.type == Move.DISCARD:
            cardValue = self.cardValue(card, discardIdx, discardCards)
            # TODO: Factor in expected value of replacement card.
            return (1 - cardValue
                    ) * self.__class__.constants.discard_move_value_penalty

        # TODO: Factor in "safe trip" cost of playing 200km,
        # "shutout" cost of failing to play an attack,
        # and "delayed action" cost of failing to discard.

        card = move.card
        cardType = Cards.cardToType(card)
        if cardType == Cards.MILEAGE:
            # TODO: Avoid playing a 75 unless we have a 25,
            # and avoid playing a 25 unless we need it.
            value = self.mileageCardValue(card)
            mileage = Cards.cardToMileage(card)

            if mileage == 200 and self.gameState.us.twoHundredsPlayed == 0:
                safeTripFactor = self.__class__.constants.safe_trip_factor
            else:
                safeTripFactor = 1.0

            if mileage == self.gameState.target - self.gameState.us.mileage:
                return 1.0 * safeTripFactor
            elif mileage == 25 and len(
                [card for card in discardCards if card == card]) < 2:
                # Don't play our last 25km (unless we need to).
                return 0.0
            else:
                return value * safeTripFactor
        elif cardType == Cards.REMEDY:
            if card == Cards.REMEDY_END_OF_LIMIT and not self.gameState.us.speedLimit:
                return 0.0

            # If we need a remedy to move, and we have that remedy, it's a rather strong play!
            return 1.0
        elif cardType == Cards.SAFETY:
            return self.__class__.constants.safety_horde_factor
        elif cardType == Cards.ATTACK:
            target = self.gameState.teamNumberToTeam(move.target)
            if card == Cards.ATTACK_SPEED_LIMIT:
                # If they're already under a speed limit, don't bother with another.
                if target.speedLimit:
                    return 0.0
            else:
                # If they already need a remedy, don't bother with another -- unless they need
                # "go", in which case the attack is still worthwhile because now they need
                # the specific attack's remedy *in addition to* go.
                if target.needRemedy and target.needRemedy != Cards.REMEDY_GO:
                    return 0.0

            # TODO: Balance these, and also factor in chance opponent can get protection in the future.
            # And also factor in trip distance remaining for speed limit.
            if card == Cards.ATTACK_STOP:
                attackQualityModifier = self.__class__.constants.attack_quality_mod_stop
            elif card == Cards.ATTACK_SPEED_LIMIT:
                attackQualityModifier = self.__class__.constants.attack_quality_mod_limit
            else:
                attackQualityModifier = 1.0

            # TODO: Add an "aggressiveness" constant?
            return ((1 - self.chanceOpponentHasProtection(target, card)) *
                    self.chanceTeamWillWin(target) *
                    self.chanceTeamWillCompleteTrip(target) *
                    attackQualityModifier *
                    self.__class__.constants.aggressiveness)

        # than playing them outright, so that we can save safeties for coup fourre.
        if len(safeties) > 0:
            return safeties[0]
Exemplo n.º 47
0
 def cardSeen(self, card):
   self.cardsUnseen[card] -= 1
   self.numCardsUnseen -= 1
   self.debug("After seeing %s, unseen cards:\n%s",
              Cards.cardToString(card),
              self.unseenCardsToString)
Exemplo n.º 48
0
    def cardValue(self, card, cardIdx, cards):
        # cardIdx and cards let us disambiguate between two equal cards in our hand.
        #
        # All equally worthless:
        # * Safeties in play or elsewhere in our hand
        # * Remedies for safeties in play or elsewhere in our hand
        # * 200mi if we've already maxed out
        # * Mileage > distance remaining (assuming extension will be played)
        #   TODO: ...but what if an extension *won't* be played?
        # * Safeties we have in our hand

        # How many of this card do we already have in our hand?
        numDuplicates = len([c for c in cards if c == card])
        # Make this card less valuable if we have more if it on our hand.
        # The obvious thing to do is a straight divisor:
        # If we have 2 dupes, value each at 1/2; if 3, value each at 1/3.
        # But that's too severe, having 2 200km is more valuable than having
        # 1 200km!  So, we take the "duplicate fraction", 1/numDuplicates,
        # and we want to scale down *the inverse of that* to bring it
        # nearer to 1 (to reduce the severity of the penalty), and then
        # invert again to cancel out the inversion.
        dupeFrac = 1 / numDuplicates
        dupePenaltyFactor = self.__class__.constants.dupe_penalty_factor
        dupeCoefficient = 1 - (1 - dupeFrac) / dupePenaltyFactor

        cardType = Cards.cardToType(card)
        if cardType == Cards.MILEAGE:
            mileage = Cards.cardToMileage(card)
            mileageRemaining = 1000 - self.gameState.us.mileage
            if mileage > mileageRemaining:
                return 0.0 * dupeCoefficient
            elif mileage == 200 and self.gameState.us.twoHundredsPlayed >= 2:
                return 0.0 * dupeCoefficient
            elif mileage == 25 and cards.index(card) == cardIdx:
                # Try to hold onto a single 25km card in case we need it to finish.
                return 1.0 * dupeCoefficient
            else:
                return self.mileageCardValue(card) * dupeCoefficient
        elif cardType == Cards.REMEDY:

            # Attacks that could necessitate this card.
            if card == Cards.REMEDY_GO:
                relevantAttacks = Cards.ATTACKS[:]
            else:
                relevantAttacks = [Cards.remedyToAttack(card)]

            relevantAttacks = [
                c for c in relevantAttacks
                if not Cards.attackToSafety(c) in self.gameState.us.safeties +
                cards
            ]

            # Factor in:
            # 1. Value of taking a turn.
            # 2. Likelihood of getting hit with a relevant attack.
            #    (Number of attacks remaining / number of teams in game.)
            #    NB: If no attacks are relevant, this will be 0.
            # TODO: Also add likelihood of drawing another remedy (or the safety.)
            turnPoints = self.expectedTurnPoints(self.gameState.us)
            turnPointValue = self.valueOfPoints(turnPoints, self.gameState.us)
            # Hold onto at least one of the card if we already know we need it!
            if (cards.index(card) == cardIdx and
                ((not self.gameState.us.moving and card == Cards.REMEDY_GO) or
                 (self.gameState.us.speedLimit
                  and card == Cards.REMEDY_END_OF_LIMIT) or
                 (self.gameState.us.needRemedy
                  and card == self.gameState.us.needRemedy))):
                self.debug("We need %s, attack on us odds == 1.0!",
                           Cards.cardToString(card))
                attackOnUsOdds = 1.0
            else:
                attackOdds = self.percentOfCardsRemaining(
                    *relevantAttacks) * self.expectedTurnsLeft()
                attackOnUsOdds = attackOdds / (len(self.gameState.opponents) +
                                               1)
            value = turnPointValue * attackOnUsOdds
            self.debug(
                "Card %s val: %r = %r * %r = val(%d) * pctLeft(%s)/#teams",
                Cards.cardToString(card), value, turnPointValue,
                attackOnUsOdds, turnPoints,
                ",".join([Cards.cardToString(c) for c in relevantAttacks]))
            return value * dupeCoefficient
        elif cardType == Cards.SAFETY:
            # Never discard a safety!
            # (Assuming default deck composition of 1 of each type...)
            return 1.0 * dupeCoefficient
        elif cardType == Cards.ATTACK:
            safety = Cards.attackToSafety(card)
            remedy = Cards.attackToRemedy(card)

            valuesPerTarget = []
            for target in self.gameState.opponents:
                valuesPerTarget.append(
                    (1 - self.chanceOpponentHasProtection(target, card)) *
                    (1 - self.percentOfCardsRemaining(safety, remedy)) *
                    self.valueOfPoints(self.expectedTurnPoints(target),
                                       target))
            return sum(valuesPerTarget) / len(
                valuesPerTarget) * dupeCoefficient
        else:
            raise Exception("Unknown card type for %r: %r" % (card, cardType))
Exemplo n.º 49
0
    def playHand(self):
        self.resetHandState()

        # Fresh deck
        self.deck = Deck()

        # Deal hands
        for player in self.players:
            player.hand = self.draw(player, 6)

        if self.transcriptWriter:
            self.transcriptWriter.writeHandStart()

        currentPlayerNumber = 0
        # Normally this is currentPlayerNumber + 1, but in the case of a coup
        # fourre it gets changed to give the player another turn
        nextPlayerNumber = 1

        while True:
            currentPlayer = self.players[currentPlayerNumber]
            currentTeam = self.teams[currentPlayer.teamNumber]

            drewCardThisMove = None
            try:
                drewCardThisMove = self.draw(currentPlayer)
                currentPlayer.hand.append(drewCardThisMove)
            except IndexError:
                self.delayedAction = True

            if self.debug:
                print 'Hand contents:',
                print Cards.cardsToStrings(currentPlayer.hand)

            if len(currentPlayer.hand) == 0:
                totalHandSize = 0
                for player in self.players:
                    totalHandSize += len(player.hand)
                if totalHandSize == 0:
                    # Everyone's out of cards - game over
                    break
                else:
                    # Pass and let someone else go
                    currentPlayerNumber = nextPlayerNumber
                    nextPlayerNumber += 1
                    if nextPlayerNumber >= len(self.players):
                        nextPlayerNumber = 0
                    continue

            state = self.makeState(currentPlayer)
            state.findValidPlays()
            # Store a copy of this locally, just in case the AI changes it
            validMoves = state.validMoves
            move = currentPlayer.ai.makeMove(state)

            # Replace invalid moves with a random discard
            if move not in validMoves:
                print 'Warning: invalid play'
                move = Move(Move.DISCARD, currentPlayer.hand[0])

            if self.debug:
                print currentPlayer,
                print move

            sanitizedPlayer = copy(currentPlayer)
            sanitizedPlayer.hand = []
            sanitizedPlayer.ai = None
            self.notifyPlayers(sanitizedPlayer, move)

            oldTarget = self.target
            self.handleMove(currentPlayer, currentTeam, move)
            if self.transcriptWriter:
                extensionWasDeclared = self.target > oldTarget
                self.transcriptWriter.writeMove(currentPlayer.number,
                                                drewCardThisMove, move,
                                                extensionWasDeclared)
            if self.tripComplete:
                break

            # Remove the card from the player's hand
            del currentPlayer.hand[currentPlayer.hand.index(move.card)]

            if self.debug:
                for team in self.teams:
                    print team
                print ''

            # Go on to the next player. If a safety got played, nextPlayerNumber
            # got changed and will cause us to break out of the normal rotation
            currentPlayerNumber = nextPlayerNumber
            nextPlayerNumber += 1
            if nextPlayerNumber >= len(self.players):
                nextPlayerNumber = 0

        if self.debug:
            print 'Hand complete'

        if self.transcriptWriter:
            self.transcriptWriter.writeHandEnd()

        self.computeHandScores()
Exemplo n.º 50
0
    def monteCarloMileageSimulation(self):
        # Returns a list of many (turns elapsed, team 0 trip mileage remaining, team 1 trip remaining, ...)
        # TODO: Assumes extension.
        results = []
        for _ in xrange(self.perfConstants.monteCarloIterations):
            needMileage = dict(
                (team.number, team.mileage) for team in self.gameState.teams)
            moving = dict(
                (team.number, team.moving) for team in self.gameState.teams)
            needRemedy = dict((team.number, team.needRemedy)
                              for team in self.gameState.teams)
            twoHundredsPlayed = dict((team.number, team.twoHundredsPlayed)
                                     for team in self.gameState.teams)

            tripCompletedBy = None
            deck = collections.deque()
            for (card, qty) in self.cardsUnseen.iteritems():
                for _ in xrange(qty):
                    deck.append(card)
            random.shuffle(deck)

            turnsElapsed = 1
            while deck:
                for currentTurnTeam in self.gameState.teams:
                    if not deck:
                        break

                    teamNo = currentTurnTeam.number
                    teamNeedMileage = needMileage[teamNo]
                    teamNeedRemedy = needRemedy[teamNo]
                    teamMoving = moving[teamNo]
                    teamTwoHundredsPlayed = twoHundredsPlayed[teamNo]
                    if teamNeedRemedy:
                        teamNeedSafety = Cards.remedyToSafety(teamNeedRemedy)
                    else:
                        teamNeedSafety = None

                    for playerNum in currentTurnTeam.playerNumbers:
                        if tripCompletedBy == playerNum:
                            deck = None
                            break
                        if not deck:
                            break

                        card = deck.pop()
                        cardType = Cards.cardToType(card)
                        if Cards.cardToType(card) != Cards.MILEAGE:
                            if card == Cards.REMEDY_GO:
                                teamMoving = True
                                if teamNeedRemedy == Cards.REMEDY_GO:
                                    teamNeedRemedy = None
                            elif teamNeedRemedy:
                                if ((cardType == Cards.SAFETY
                                     and teamNeedSafety == card)
                                        or (cardType == Cards.REMEDY
                                            and needRemedy[teamNo] == card)):
                                    teamNeedRemedy = None
                        else:
                            mileage = Cards.cardToMileage(card)
                            if mileage == 200 and teamTwoHundredsPlayed >= 2:
                                continue
                            elif mileage > teamNeedMileage:
                                continue
                            elif mileage == 200:
                                teamTwoHundredsPlayed += 1

                            teamNeedMileage -= mileage

                        if teamNeedMileage == 0 and teamMoving and not teamNeedRemedy:
                            tripCompletedBy = playerNum
                            break

                    needMileage[teamNo] = teamNeedMileage
                    needRemedy[teamNo] = teamNeedRemedy
                    moving[teamNo] = teamMoving
                    twoHundredsPlayed[teamNo] = teamTwoHundredsPlayed

                turnsElapsed += 1

            result = [turnsElapsed]
            for i in xrange(len(self.gameState.opponents) + 1):
                if i == self.gameState.us.number:
                    team = self.gameState.us
                else:
                    team = self.gameState.teamNumberToTeam(i)

                if needRemedy[i] or not moving[i]:
                    mileage = 1000 - team.mileage
                else:
                    mileage = needMileage[i]
                result.append(mileage)
            results.append(result)
        return results
Exemplo n.º 51
0
    def makeMove(self, gameState):
        discards = []
        mileage = []
        attacks = []
        remedies = []
        safeties = []

        cardsPlayed = []
        us = gameState.us
        cardsPlayed = cardsPlayed + us.mileagePile
        cardsPlayed = cardsPlayed + us.speedPile
        cardsPlayed = cardsPlayed + us.battlePile
        cardsPlayed = cardsPlayed + us.safeties

        MyMileage = us.mileage
        MyRunningTotal = MyMileage + us.totalScore + len(
            us.safeties) * 100 + us.coupFourres * 300

        opponents = gameState.opponents
        ourSafeties = us.safeties
        playedSafeties = ourSafeties
        opponentsCount = 0
        opponentsSafeties = []
        for opponent in opponents:
            opponentsCount = opponentsCount + 1
            opponentsSafeties = opponentsSafeties + opponent.safeties
            cardsPlayed = cardsPlayed + opponent.mileagePile
            cardsPlayed = cardsPlayed + opponent.speedPile
            cardsPlayed = cardsPlayed + opponent.battlePile
            cardsPlayed = cardsPlayed + opponent.safeties
        playedSafeties = playedSafeties + opponentsSafeties

        cardsPlayed = cardsPlayed + gameState.discardPile
        cardPlayedByType = {}
        for x in xrange(0, 19):
            cardPlayedByType[x] = 0

        for card in cardsPlayed:
            cardPlayedByType[card] += 1

        target = gameState.target
        target_minus_25 = target - 25
        target_minus_50 = target - 50
        target_minus_75 = target - 75
        target_minus_100 = target - 100
        target_minus_200 = target - 200

        for play in gameState.validMoves:
            if (play.type == Move.DISCARD):
                discards.append(play)
            else:
                type = Cards.cardToType(play.card)
                if type == Cards.MILEAGE:
                    mileage.append(play)
                elif type == Cards.REMEDY:
                    remedies.append(play)
                elif type == Cards.ATTACK:
                    attacks.append(play)
                elif type == Cards.SAFETY:
                    safeties.append(play)

        #######################
        #  IF CAN GO FOR WIN  DO IT!
        #######################

        if len(mileage) > 0:
            if us.mileage == target_minus_25:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_25:
                        return mi
            elif us.mileage == target_minus_50:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_50:
                        return mi
            elif us.mileage == target_minus_75:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_75:
                        return mi
            elif us.mileage == target_minus_100:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_100:
                        return mi
            elif us.mileage == target_minus_200:
                for mi in mileage:
                    if mi.card == Cards.MILEAGE_200:
                        return mi

        ########################
        #  play a red card based on weighted factors
        #  but check to see if the corrosponding safety is known in play or in your hand
        #  if not known  dont play if less then X cards in deck
        #####################################

        numberOfCardsLeftToNotAttack = 10

        if len(attacks) > 0:
            highestWeight = -10
            weightedAttacks = {}
            for attack in attacks:
                opponent = gameState.teamNumberToTeam(attack.target)
                opponentMileage = opponent.mileage
                opponentRunningTotal = opponentMileage + opponent.totalScore + len(
                    opponent.safeties) * 100 + opponent.coupFourres * 300
                weight = 0
                if opponentRunningTotal >= 3000:
                    #         print "opponentRunningTotal >= 3500"
                    weight += 1
                if opponentRunningTotal >= 3500:
                    #         print "opponentRunningTotal >= 3500"
                    weight += 1
                if opponentRunningTotal >= 4000:
                    #          print "opponentRunningTotal >= 4000"
                    weight += 1
                if opponentRunningTotal >= 4500:
                    #         print "opponentRunningTotal >= 4500"
                    weight += 2
                if opponentRunningTotal >= MyRunningTotal + 1000:
                    #        print "opponentRunningTotal >= myRunningTotal+2000"
                    weight += 1
                if opponentRunningTotal >= MyRunningTotal + 2000:
                    #        print "opponentRunningTotal >= myRunningTotal+2000"
                    weight += 3
                if opponentMileage >= MyMileage + 400:
                    #       print "opponentMileage >= my mileage + 400"
                    weight += 1

                if opponentMileage >= target_minus_200:
                    if opponentMileage >= target_minus_50 and attack.card == Cards.ATTACK_SPEED_LIMIT:
                        weight = -10
        #        print "opponet withi 50 of end and attack=limit"
                    else:
                        weight += 1
        #       print "opponent within 200 of end"
                if attack.card != Cards.ATTACK_SPEED_LIMIT and attack.card != Cards.ATTACK_STOP:
                    weight += 0.6
                if attack.card == Cards.ATTACK_SPEED_LIMIT:
                    weight += 0
                if attack.card == Cards.ATTACK_STOP:
                    weight += 0.01
            #    print "attack card not limit or stop"

                corrospondingSafetyisNotKnown = True
                corrospondingSafety = Cards.attackToSafety(attack.card)
                if cardPlayedByType[corrospondingSafety] == 1:
                    corrospondingSafetyisNotKnown = False
                for safet in safeties:
                    if Cards.attackToSafety(attack.card) == safet.card:
                        corrospondingSafetyisNotKnown = False

                if corrospondingSafetyisNotKnown:
                    if gameState.cardsLeft < numberOfCardsLeftToNotAttack:
                        weight = -10  #nop
            #     print "safety NOT known and gameState.cardsLeft < numberOfCardsLeftToNotAttack"
                    else:
                        #    print "safety not known"
                        weight -= 0.5
                    #print "proceed with attack!!!!!!!!!!"
                else:
                    # print "safety KNOWN!"
                    weight += 0.5
                #print "weight="+str(weight)
                if weight > highestWeight:
                    highestWeight = weight
                weightedAttacks[weight] = attack

            if highestWeight > -1:
                #print "=============highest Weight="+str(highestWeight)
                #print weightedAttacks[highestWeight]
                return weightedAttacks[highestWeight]

        ##################3
        # play a remedy
        ##################

        if len(remedies) > 0:
            remedies.sort(key=lambda x: x.card)
            if remedies[
                    0].card == Cards.REMEDY_END_OF_LIMIT and us.mileage >= target_minus_50 and len(
                        mileage) > 0:
                mileage.sort(key=lambda x: x.card, reverse=True)
                #print "remedy= EOL AND us.mileage="+str(us.mileage)+" mileage[0]="+str(mileage[0].card)
                return mileage[0]
            else:
                return remedies[0]

        #####################
        # play a mileage:
        #      first check to see if you are 200 or less away, if any 2 card combonation in hand will finish race
        #      if not, play highest mileage
        ######################

        if len(mileage) > 0:
            mileage.sort(key=lambda x: x.card, reverse=True)
            if len(mileage) > 2 and us.mileage > target_minus_200:
                num = 0

                for mi in mileage:
                    num += 1
                    mileageCopy = mileage[num:]
                    for mi2 in mileageCopy:
                        mivalue = Cards.cardToMileage(mi.card)
                        mi2value = Cards.cardToMileage(mi2.card)
                        total = us.mileage + mivalue + mi2value
                        if total == target:
                            return mi
            return mileage[0]

        ##############################
        #  If have safety that solves a problem we have... use it
        ############################

        remedyNeeded = us.needRemedy
        if remedyNeeded > 0:
            for safet in safeties:
                if safet.card == Cards.remedyToSafety(remedyNeeded):
                    return safet
        if us.speedLimit == True:
            for safet in safeties:
                if safet.card == Cards.SAFETY_RIGHT_OF_WAY:
                    return safet

        ####################
        # ENTER EASY DISCARD PHASE
        ##############

    # reuse these because this used to be in a seperate function
        mileage = []
        attacks = []
        remedies = []

        for play in discards:
            type = Cards.cardToType(play.card)
            if type == Cards.MILEAGE:
                mileage.append(play)
            elif type == Cards.REMEDY:
                remedies.append(play)
            elif type == Cards.ATTACK:
                attacks.append(play)

        ##################
        # Remedies we have safeties for in play, in hand or for all attacks have been played
        ################

        if len(remedies) > 0:
            for remedy in remedies:
                for safet in safeties:
                    if Cards.remedyToSafety(remedy.card) == safet.card:
                        return remedy

                if Cards.remedyToSafety(remedy.card) in ourSafeties:
                    return remedy
                corrospondingAttack = Cards.remedyToAttack(remedy.card)
                if corrospondingAttack == Cards.ATTACK_FLAT_TIRE:
                    if cardPlayedByType[Cards.ATTACK_FLAT_TIRE] == 3:
                        #            print "discard spare due to all flats played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_OUT_OF_GAS:
                    if cardPlayedByType[Cards.ATTACK_OUT_OF_GAS] == 3:
                        #           print "discard gas due to all out of gas played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_ACCIDENT:
                    if cardPlayedByType[Cards.ATTACK_ACCIDENT] == 3:
                        #          print "discard repairs due to all accidents played"
                        return remedy
                elif corrospondingAttack == Cards.ATTACK_SPEED_LIMIT:
                    if cardPlayedByType[Cards.ATTACK_SPEED_LIMIT] == 4:
                        #         print "discard end of limit due to all spedlimits played"
                        return remedy

        ########################
        #   Attacks that opponents have safeties for (if not 3 or 6 person game)
        ######################

        if len(attacks) > 0:
            if opponentsCount == 1:
                for attack in attacks:
                    if Cards.attackToSafety(attack.card) in opponentsSafeties:
                        return attack

        ###################
        # mileage discard due to limit:
        #     if an opponent has right of way and all EOL played and we have speed limit  discard mileage over 50
        ######################

        mileage.sort(key=lambda x: x.card)
        if len(mileage) > 0:
            opponentRightOfWay = False
            for safet in opponentsSafeties:
                if safet == Cards.SAFETY_RIGHT_OF_WAY:
                    opponentRightOfWay = True
            if cardPlayedByType[
                    Cards.
                    REMEDY_END_OF_LIMIT] == 6 and us.speedLimit and opponentRightOfWay:

                for mi in mileage:
                    if mi.card > 1:
                        #print "discarding mi:" + Cards.cardToString(mi.card)
                        return mi

        ########################
        #  milage that we can no longer play due to being to close to the end
        # or playing 2 2 hundreds
        #########################

            thp = us.twoHundredsPlayed

            for mi in mileage:

                if thp == 2 or us.mileage > target_minus_200:
                    if mi.card == Cards.MILEAGE_200:
                        return mi
                if us.mileage > target_minus_100:
                    if mi.card == Cards.MILEAGE_100:
                        return mi
                if us.mileage > target_minus_75:
                    if mi.card == Cards.MILEAGE_75:
                        return mi
                if us.mileage > target_minus_50:
                    if mi.card == Cards.MILEAGE_50:
                        return mi

        #########################
        #  Enter "Smart" discard phases
        ########################

        ########################
        # Remedy smart discard:  remedies we have dupes of (save 1 of each, except GO  save 2)
        ###########################

        remedyDupes = {}
        for x in xrange(5, 10):
            remedyDupes[x] = 0
        if len(remedies) > 0:
            for remedy in remedies:
                remedyDupes[remedy.card] += 1
            if remedyDupes[Cards.REMEDY_SPARE_TIRE] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_SPARE_TIRE:
                        return remedy
            elif remedyDupes[Cards.REMEDY_GASOLINE] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_GASOLINE:
                        return remedy
            elif remedyDupes[Cards.REMEDY_REPAIRS] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_REPAIRS:
                        return remedy
            elif remedyDupes[Cards.REMEDY_GO] > 2:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_GO:
                        return remedy
            elif remedyDupes[Cards.REMEDY_END_OF_LIMIT] > 1:
                for remedy in remedies:
                    if remedy.card == Cards.REMEDY_END_OF_LIMIT:
                        return remedy

    ####################
    # play a safety as no more easy discards are available
    ###################

    # Play a safety rather than discard
        if len(safeties) > 0:

            return safeties[0]

        ####################
        #  attack smart discard: if have more then 2 attack cards  discard stops/ speedlimits
        ####################

        attackDupes = {}
        for x in xrange(10, 16):
            attackDupes[x] = 0

        if len(attacks) > 0:
            totalAttackCardsInHand = 0
            for attack in attacks:
                totalAttackCardsInHand += 1
                attackDupes[attack.card] += 1
            if totalAttackCardsInHand > 2:
                for attack in attacks:
                    if attack.card == Cards.ATTACK_SPEED_LIMIT:
                        return attack
                    if attack.card == Cards.ATTACK_STOP:
                        return attack

        #####################
        # final "smart" discard: if more then one mileage in hand discard lowest mileage
        # if exactly 1 mileage in hand  first discard a non GO remedy(starting with EOL, then an attack (order EOL, stop, then others)
        ########################

        if len(mileage) > 0:
            if len(mileage) == 1:

                remedies.sort(key=lambda x: x.card, reverse=True)
                for remedy in remedies:
                    if remedy.card != Cards.REMEDY_GO:
                        return remedy
                attacks.sort(key=lambda x: x.card, reverse=True)
                for attack in attacks:
                    return attack
            else:
                return mileage[0]

        ##################
        #  discard whatever is left
        ##################

        return discards[0]  #toDiscard