11
8
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.
Game Rules
- 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.
Coding
All submissions should be compatible with Python 3.7. You must write a class that directly inherits from WhiteElephantBot
. For instance:
class FooBot(WhiteElephantBot):
# 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 beNone
.
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 presents
:
{
'Alice': (0.35, 0),
'Bob': (0.81, 2),
'Charlie': (0.57, 1)
}
Your 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 str
or 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.
Test Driver
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.
Baseline Competitors
- 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.
Additional Rules
- 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)
Can there be any number of steals in a row? When I have played, usually there is a limit of 2 steals in a row or something, and the third person from would have to open one. This prevents the same gift from being stolen more than once per turn. – mbomb007 – 2018-07-25T15:43:15.190
@mbomb007 Yes. Chain-stealing is unlimited, except by the other rules that make certain presents immune to stealing: each present can only be stolen 3 times and you can't steal from the player who just stole from you. – Beefster – 2018-07-25T15:47:08.273
Can you steal a present and then re-steal the original one you had? – Erik the Outgolfer – 2018-07-25T16:25:16.200
@EriktheOutgolfer: yes, as long as there was another turn in between. You just can't re-steal immediately after your present is stolen. – Beefster – 2018-07-25T16:30:13.997
No, I meant something like 1) Steal most valuable present 2) Check if now there's something more valuable 3) If so, steal again 4) Open, and let next turn to come. – Erik the Outgolfer – 2018-07-25T16:31:35.760
Why only one entry per person? I have several fundamentally distinct ideas, and I'd rather not have to throw out old ones to implement something new. – None – 2018-07-25T18:30:19.537
@EriktheOutgolfer Once you steal the most valuable present, its no longer your turn to choose, so that doesn't work. The player (bot) that just had its present stolen takes another turn. – BradC – 2018-07-25T18:39:38.497
@Mnemonic: one of the big issues is that you can make multiple bots work together. Since each bot present affects the metagame, you can use different bots to make one of your others do better. Maybe that's not a real problem. I'll have to think about it. – Beefster – 2018-07-25T18:58:52.833
1Yankee swap!? What's next, a shared birthday party? – ngm – 2018-07-25T19:05:51.513
It would be nice to know how many rounds you had to play before one bot reached 500 points – Black Owl Kai – 2018-08-08T18:57:26.623
@Heiteira That's a good idea. I'll think about it. I think it might also be good to run games until there is a clear winner, but I don't really know the best way to determine that statistically. – Beefster – 2018-08-08T19:34:19.187