Contest overview

What is UPAC?

UPAC (University Poker Algorithm Competition) is a virtual contest that aims to bring together students from around the world to compete in developing the best poker algorithms.

We plan to host formal contests with different formats and prizes. The first contest will be a heads-up no-limit Texas Hold'em competition. The competition will be held on the UPAC platform, which is a custom-built platform for running poker competitions.

The platform is currently live for testing, and for fun, but the first official contest will be held in Fall 2024.

Schedule (TBD)

EventDate
Start of the competitionFall 2024
Submission closes-
Winners announcement-

Prizes (TBD)

EventDate
1st-
2nd-
3rd-

Eligibility and Registration

Teams

Right now the UPAC platform is open to everyone, but future competitions with prizes will only available to students.

We invite prize-elligible teams to join the competition with a size ranging from 1 to 5 members. Each team member must meet the following criteria:

  • Currently a student enrolled at a Canadian university (high school, undergrad, masters or PhD).

  • Not a member of UPAC's team.

Registration

Registrations are not currently available, but they will be made through our website upac.dev. The competition will start in Spring 2024.

Developing bots

The game

Bots play 2-player Texas Holdem' with fixed blinds. We chose this format instead of larger games or tournament style because it has fewer factors for bots to deal with. This way you can focus on understanding your opponent and betting intelligently.

How to play

At the start of the game the 'button' is assigned to a random player. Before every round the button is forced to put the small blind into the pot ($1), and the other player is forced to put the big blind ($2).

Building a Bot

The game

Bots in UPAC play a version of No Limit Holdem. Games are always played between two bots. One is labelled the challenger, and the other labelled the defender. These labels don't mean much for now, but they might become relevant in the future. Games are played for 100 rounds, or until one bot runs out of chips. Bots start with 50 chips, so the total number of chips in a game is 100. The number of chips you end with is the 'score', used to calculate your bot's elo change.

Communicating with the engine

Bots get the game state and make their moves by communicating through stdin and stdout. The stdout and stdin of each bot is stored in the 'public log' for a game, and the stderr for each bot is stored in the 'defender log' or 'challenger log'

This is the structure of a round. I will assume that you know the rules for heads up no limit holdem.

  1. START (SB|BB), where START SB means you're the small blind for this round, and START BB means you're the big blind for this round.
  2. PREFLOP (Card) (Card). These two cards are your hole cards. The other player cannot see them.
  3. The engine enters a betting round. See the following section for an explanation.
  4. FLOP (Card) (Card) (Card). These are three shared cards. Both players see the same cards.
  5. A betting round
  6. TURN (Card). This is shared card.
  7. A betting round
  8. RIVER (Card). This is a shared card
  9. A betting round
  10. END SHOWDOWN (TIE (Card) (Card)|WINNER (SB|BB) (HIDDEN|SHOWN (Card) (Card))). This means the round ended by going to a showdown. If the showdown was a tie, then the engine prints END SHOWDOWN TIE (Card) (Card), where the two cards are the opponents hole cards. Else if the showdown was not a tie, the engine outputs a winner. The engine always outputs END SHOWDOWN WINNER (SB|BB) SHOWN (Card) (Card) to the loser, since the winner must show their cards (the printed cards are the ones belonging to the opposing player). If the loser was the last aggressor (last person to raise by a positive amount) then they must show their hand to the winner too. Otherwise the winner receives END SHOWDOWN WINNER (SB|BB) HIDDEN

Betting rounds

Betting rounds are where bots get to act. They are structured like this:

  1. STACK (a) (b) (c) (d). This message is sent to you when it's time to make an action. it contains four non-negative integers between 0 and 50. a is the number of chips that your bot has pushed in this round. b is the total number of chips in your stack (including the amount that you pushed in this round). And c and d are these quantities but for the opposing player
  2. Your bot gives an action, either outputting F, C, or R<n> (<n> is an integer, e.g. R6). These actions respectively represent "Fold", "Call", or "Raise by n". Raising will first match the opponent's bet, and then push an additional n chips. Note that this means that C is equivalent R0.
  3. If a player folds, then both players receive END FOLD (SB|BB), where END FOLD SB means that the small blind folded and END FOLD BB means that the big blind folded.
  4. Once both players have made an action in this betting round, and they have both pushed the same amount, the betting round ends.

Representing cards

Cards are always 2 characters. The first represents value and the second represents suit. The value of a card is either represented as a single digit (for 2-9), or as the first letter of its name (T=10, J=Jack, Q=Queen, K=King, A=Ace). The suit is represented as the first letter of its name (s=Spades, h=Hearts, c=Clubs, d=Diamonds).

For example: 2d represents the 2 of diamonds, and Tc represents the 10 of clubs.

Programming a bot

Bots are uploaded as a zipped folder containing a file named bot.json. This file contains a name, a build command, and a run command. For example:

{
    "name": "FOY",
    "build": "g++ bot.cpp -O2 -o bot",
    "run": "./bot"
}

Right now your zip file must be created by zipping a folder named bot. When you upload a zip file, a build event gets queued. The bot is then built in an environment where it has write access. The built bot is then zipped, uploaded, and a test game is queued to verify that there aren't any simple errors with running the bot. After the test game is finished, you will be able to make this bot active so it will play games for you.

Matchmaking

Every few seconds a new game is queued for each team with an active bot. The game is always queued with a bot of similar rating. After a game is finished, the final chip values divided by 100 are used as the score in an elo calculation. If a bot has a runtime error during the game then its score is considered to be zero, and the other bot gets 1 (this is harsh but necessary to prevent bots from self-destructing when they are losing).

Bot Testing and Submission

Currently, both testing and submission can be carried out on our platform at upac.dev.

Bot requirements

To ensure uninterrupted gameplay during a match, your bot must meet the following criteria at any point in time:

  • Output response time after receiving a message is under 1 second.
  • Maintain RAM usage below 1GB.
  • Keep disk usage under 5MB.

For Python users only: your bot only use the following packages: numpy, pandas, scipy, scikit-learn.

If you want to use other python packages, please reach out the dev team on our Discord server.

Scoring

Scoring is done using the Elo rating system. We calculate the expected score for each player and then update their ratings based on the actual score. The expected score is calculated using the following formula:

$$E_i = \frac{1}{1 + 10^{(R_j - R_i)/400}}$$ (see get_rating_change)

Where $R_i$ and $R_j$ are the ratings of the two players and $E$ is the expected score for player $i$. The actual score is determined by the proportion of the total number of chips in the game that each player has at the end of the game. For example in a game where both players start with 500 chips, if at the end player 1 has 800 and player 2 has 200, then player 1's score is 0.8 and player 2's score is 0.2.

The rating change for each player is then calculated using the following formula:

$$\Delta R_i = K(S_i - E_i)$$ (see get_rating_change)

Where $S_i$ is the actual score for player $i$, $E_i$ is the expected score for player $i$, and $K$ is a constant that determines the maximum rating change. In our case, we use $K = 12$ (which is subject to change).

FAQ

What technologies can I use to build my bot?

Participants are free to use any programming language they are comfortable with since all the communications with the engine are made through I/O. Just make sure to satisfy the bot requirements.

Can I have multiple bots?

Yes, each team can build as many bots as they want!

Appendices

This section will contain a variety of files that will be useful to participants.

Game log

Here is a piece of a game log from a match:

261ms System > round 10/100
261ms Defender < START SB
261ms Challenger < START BB
261ms Defender < PREFLOP 6h 2d
261ms Challenger < PREFLOP 7s 8c
261ms Challenger < STACK 1 74 2 26
262ms Challenger > C
262ms Defender < STACK 2 26 2 74
262ms Defender > F
262ms Defender < END FOLD BB
262ms Challenger < END FOLD BB
262ms System > round 11/100
262ms Defender < START BB
262ms Challenger < START SB
262ms Defender < PREFLOP Js 8d
263ms Challenger < PREFLOP Kc Qs
263ms Defender < STACK 1 24 2 76
263ms Defender > R0
263ms Challenger < STACK 2 76 2 24
263ms Challenger > C
263ms Defender < FLOP 9c 9s 6h
263ms Challenger < FLOP 9c 9s 6h
263ms Challenger < STACK 2 76 2 24
264ms Challenger > C
264ms Defender < STACK 2 24 2 76
264ms Defender > R0
264ms Defender < TURN 6s
264ms Challenger < TURN 6s
264ms Challenger < STACK 2 76 2 24
264ms Challenger > C
264ms Defender < STACK 2 24 2 76
264ms Defender > R0
264ms Defender < RIVER 7h
264ms Challenger < RIVER 7h
265ms Challenger < STACK 2 76 2 24
265ms Challenger > C
265ms Defender < STACK 2 24 2 76
265ms Defender > R0
265ms Defender < END SHOWDOWN WINNER BB SHOWN Kc Qs
265ms Challenger < END SHOWDOWN WINNER BB HIDDEN
265ms System > round 12/100
266ms Defender < START SB
266ms Challenger < START BB
266ms Defender < PREFLOP 9d 7s
266ms Challenger < PREFLOP Qs Kh
266ms Challenger < STACK 1 78 2 22
266ms Challenger > C
266ms Defender < STACK 2 22 2 78
267ms Defender > F
267ms Defender < END FOLD BB
267ms Challenger < END FOLD BB
267ms System > round 13/100
267ms Defender < START BB
267ms Challenger < START SB
267ms Defender < PREFLOP Ac 6h
267ms Challenger < PREFLOP Qs Jh
267ms Defender < STACK 1 20 2 80
268ms Defender > R2
268ms Challenger < STACK 2 80 4 20
268ms Challenger > C
268ms Defender < FLOP 2c Jc 3s
268ms Challenger < FLOP 2c Jc 3s
268ms Challenger < STACK 4 80 4 20
268ms Challenger > C
268ms Defender < STACK 4 20 4 80
268ms Defender > R0
268ms Defender < TURN 2d
268ms Challenger < TURN 2d
268ms Challenger < STACK 4 80 4 20
269ms Challenger > C
269ms Defender < STACK 4 20 4 80
269ms Defender > R0
269ms Defender < RIVER Tc
269ms Challenger < RIVER Tc
269ms Challenger < STACK 4 80 4 20
269ms Challenger > C
269ms Defender < STACK 4 20 4 80
270ms Defender > R0
270ms Defender < END SHOWDOWN WINNER BB SHOWN Qs Jh
270ms Challenger < END SHOWDOWN WINNER BB SHOWN Ac 6h

Sponsorship

Contact us at alex@alexwp.com!

Support & Community

Join our Discord server!

Report an Issue

If you encounter any bugs while submitting your bot, notice any issues in the frontend, or identify errors in the documentation, kindly report the problem here.