This is a challenge to write bots to play the 1st and 2nd players in the following simple poker game.
Rules of the poker game
There are two players, A and B. Each antes $10 into the pot, and is dealt a card, which is a real number in the range [0, 1).
A goes first, and may pass or bet. If A passes, then there is a showdown; the cards are revealed, and whichever player had the higher card wins the pot.
If A bets, A chooses an amount \$b\$ to bet. \$b\$ must be an integer multiple of $1, in the range [$1, $100], and no greater than the amount of money A has at the time. A adds \$b\$ to the pot.
Then B may fold or call.
If B folds, A wins the pot with no showdown.
If B calls, B adds \$b\$ to the pot, and there is a showdown. B may not call if B has less than \$b\$ money at this stage.
Rules of the tournament and matches
The entries will compete in an all-play-all tournament consisting of matches.
Each match has two contestants (call them X and Y). At the start of the match, the tournament controller gives each contestant $500. There then follow a series of games, alternating games where X's A-bot plays Y's B-bot, and games where Y's A-bot plays X's B-bot. This will continue until either 50 games in the match have been played, or one contestant no longer has enough money to start (specifically, post their ante in) a further game.
Interfaces of procedures in an entry
An entry should contain C procedures which have the following prototypes:
int a(const float x, const int m);
int b(const float x, const int m, const int bet);
In a game where the bot is the A-player, the controller will call the function
a(x, m) where
x is the number given to the bot, who currently has $m money. \$0\leqslant x<1\$.
a must return the amount (in $) the bot is to bet. If
a returns 0 or a negative value, that means the bot will pass. Otherwise, the bot will bet the value returned by
a, $100, or $m, whichever is the smallest.
In a game where the bot is the B-player, the controller will call the function
b(x, m, bet) where
x is the number given to the bot, who currently has $m money, and the A-player has just bet an amount $
bet. \$0\leqslant x<1\$. The controller calls
b only if
bet>0 because if A had passed, B does not get to act. It calls
b only if \$a\leqslant m\$ because, if A had bet but B could not afford to call, B must fold.
b must return 0 if the bot is to fold, and any other value if the bot is to call.
In each match each contestant has allocated to it a 50-element array of ints. An entry may optionally supply procedures with the following prototypes:
void writeState(const int i, const int x);
int readState(const int i);
writeState writes the value x into the array's
ith element (\$0\leqslant i<50\$).
readState returns the value of the array's
ith element (\$0\leqslant i<50\$). The array will be zeroed at the start of each match.
X and Y will never be the same entry. So, even if you think each of your bots would be able to tell if its match-opponent is your other bot... it won't be.
Each entry's tournament score will be the sum of its match-scores. [Note that each entry is pitted against every other entry, so all entries play equal numbers of matches.]
Loopholes are forbidden, as is trying to cheat. No bot may try to read or write or tamper with anything external, including the controller or other bots.
Is the game too simple?
I wanted a game where a complete analysis is not trivial, but where entrants might be able to find something out.
How many players?
I have presented the rules as for a 2-player game. What number of players do you think is best? The game is asymmetric, so anyone who wants to enter must write both an A-bot and a B-bot. I see some disadvantages to increasing the number of players. For one thing, the interface would be even unwieldier, so in that case I'd mandate a single function which takes an extra param, namely the bot's playing-order in the current game. For another, the more players, the more my challenge would (unfortunately) be like POKE.
The figures for limits and amounts of money specified above are provisional: $10 ante, $100 max bid, $500 per player at start of match, max 50 games per match. Any thoughts on how these might be improved? I want it to be likely that a match ends naturally by a player (eventually, after many games) no longer being able to afford the ante, but don't want it to be too easy for X to put Y into a position where Y cannot afford to call.
Format for cards
To make it as easy as possible for bots to read and parse what the controller deals them, I propose condensing the deal to just one value (representing one card) per bot. Following the precedent in POKE, I propose making this a float in the range 0.0 to 1.0. Is this best, or is integer in a specified range better?
Reveal the cards?
I propose that my controller will reveal, to both players, both cards dealt in the previous game, no matter how it ended. The idea is so that each bot can learn about the other's propensity to fold (and possibly bluff).
Is this best, or would it be better for my controller to follow poker etiquette by not revealing any card that isn't in a showdown? With the latter behaviour. it won't reveal either player's card to their opponent if B folded so A won the pot without a showdown.
Deal with or without replacement?
I was thinking of the cards for both players for all games being independent variables. If the game is felt to be too simple, would it be improved if, instead, cards were dealt without replacement from a pack \$0,...,c-1\$ with a shuffle whenever the undealt stock runs out? How many cards should be burnt after each shuffle? (I'd want to burn at least 2. I want it to be unlikely for a bot to know for sure that its card is unbeatable.)
How much memory to give each bot?
Is 50 floats to store state in a match enough? The controller needs to control the allocation of, access to, and freeing of, each bot's state-array, so it gets to say how big it is.
If this proposal gets accepted for main, how long after posting it in main should I set the deadline for entries? Or may it be open-ended, so that I might run a tournament, and if I notice that someone's submitted yet another bot, I might run another.