It's Christmas in July, so what better way to celebrate than a virtual white elephant gift exchange!
For this King of the Hill challenge, you must create a bot that plays in a White Elephant exchange simulation, trying to get the highest-valued present it can.
- The game will be played over many rounds, each made up of a variable number of turns.
- Round Setup: There will be as many presents as there are players in the game, each valued randomly uniformly in the range [0...1), with this value being unknown until the present is "opened". Players will be put in a random order in a queue. The first player will be popped from the front of the queue.
- When it is a player's turn, they may either open a present or steal another player's present, passing turn to the player whose present was stolen.
- Each present may be stolen up to 3 times.
- You cannot steal from the player that just stole from you.
- Each player can only have one present at a time.
- After a present is opened, play advances to the next player popped from the front of the queue. This will be the next player in turn order who has not yet had a turn.
- Round End: When all presents have been opened, the round ends, and the value of the present held by each player is added to that player's score. A new round begins, with each player now holding no present and the player order shuffled.
- Game End: The game will end when at least one player has at scored
100500 points, with victory being awarded to the player with the highest total value of presents.
All submissions should be compatible with Python 3.7. You must write a class that directly inherits from
WhiteElephantBot. For instance:
# Your implementation here
You may provide an
__init__ method (which takes one argument,
name) in your bot class, which must call
super().__init__(name). Your class must have a
take_turn method expecting the following arguments in this order:
players: The list of player names, in turn order, of all players that do not yet have presents.
presents: A dictionary that maps player names to 2-tuples containing the present value held by that player and the number of times that present has been stolen. This will only include other players who are currently holding presents.
just_stole: If the last action taken was a steal, this will be the name of the player who just stole. If not, it will be
Each argument will be immutable or a new object so that mutating any of them will not have an effect on the game. You may keep a copy of any of the arguments if you so desire.
An example value for
'Alice': (0.35, 0),
'Bob': (0.81, 2),
'Charlie': (0.57, 1)
take_turn method should return the name of the player you wish to steal from or
None to open a present. If it raises an exception, returns something other than a
None, or the name of a player you cannot steal from, you will open a present by default.
Your constructor will be called at the beginning of each round, so you do not get to remember state from round to round.
By inheriting from
WhiteElephantBot, you will have access to a
steal_targets method that will take the presents dict and
just_stole and return a list of names of players you can steal from.
Any modules your script needs must be imported at the top of your entry.
The test driver can be found here. You do not need to include
from white_elephant import WhiteElephantBot in your posted answer, however a local module will need to do that.
- Random: Chooses randomly whether to open a new present or to steal, with the steal target chosen uniformly randomly.
- Greedy: steal the most valuable present that can be stolen. If no presents can be stolen, open a present.
- Nice: Always opens a new present. Never steals.
- It is your responsibility to catch all exceptions. If your class fails to catch an exception, it will be disqualified. In addition, please do not catch KeyboardInterrupts.
- Do not use files or other methods to bypass the inability to save state between games. You may not, for instance, save a neural network state to a file mid-run.
- Your bot must be self-contained within class code and related constants.
- You may only use standard library imports.
- There is no strict performance requirement. Be reasonable and prudent. If performance becomes an issue, I reserve the right to add time limits.
One entry per person.If you submit more than one entry, your bots may not work together. I'm going to allow multiple entries per person for now, though I may reban it later if it becomes a problem.
- This is an open competition with no distinct end date. It will be rerun any time I am able when there have been significant changes.
EDIT1: Changed winning score from 100 to 500 so that rankings are more consistent. The test driver has a new bugfix and also reflects the win score changes.
EDIT2: Clarifying note on required imports.
Leaderboard (as of Aug 8, 2018)
- SampleBot (500.093)
- LastMinuteBot (486.163)
- RobinHood (463.160)
- OddTodd (448.825)
- GreedyBot (438.520)
- SecondPlaceBot (430.598)
- ThresholdBot (390.480)
- Gambler (313.362)
- NiceBot (275.536)
- RandomBot (256.172)
- GoodSamaritan (136.298)