Esempio 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
Esempio 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
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 5
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))
Esempio n. 6
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)
Esempio n. 7
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
Esempio n. 8
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))
Esempio n. 9
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)
Esempio n. 10
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