PokerMatic consists of two parts; a server and a set of bot libraries. The server can be thought of
as the virtual poker hall; it is in charge of setting up tables, giving chips to players, and dealing the cards.
The bot libraries can be thought of as the virtual poker players, playing at tables hosted by the server.
Both the PokerServer and PokerBots require the same following dependencies:
- JRuby is recommended for threading performance
- http://jruby.org/download
- If you choose not to use jruby, you may need to change the shebang line in the bin files
- Install the spire.io.rb gem (https://github.com/spire-io/spire.io.rb)
- jgem install bundler
- jgem install spire_io
- Install OpenPGP and Gibberish (for encryption)
- jgem install openpgp
- jgem install gibberish
Both the server and client libraries read their settings from a file config.rb. Make a copy
of config_example.rb and name it config.rb in the root directory of PokerMatic.
To run a server, the only values that you need to set are SPIRE_EMAIL and SPIRE_PASSWORD This should be your spire.io
credentials. (You can sign up for a spire.io account at http://www.spire.io/register.html) If an account doesn’t exist for that email,
a new account will be created.
Once the poker server is started (by running bin/poker_server), an APP_KEY will be displayed.
This is the value that clients will need in order to connect to the server.
Copy the displayed line into your config file. If you are connecting
to a poker server running somewhere else, you will need their APP_KEY to connect.
Starting up the poker server is as simple as running bin/poker_server. Since all communication
occurs through spire.io, there is no need to worry about DNS, IP addresses, or port forwarding.
The only thing clients will need is the APP_KEY that is displayed when the server starts up.
Here is an example output when a server starts up:
>$ bin/poker_server.rb Starting up server Server running: APP_KEY = 'Ap-JQY'
Simply copy the last line printed into your config.rb file
You then have two ways to run a bot; as a single bot by running bin/bot or as a cluster of bots by running bin/bot_cluster.
First make sure you have set your APP_KEY in your config.rb to match the server you are trying to
connect to, and then run either bin/bot or bin/bot_cluster; bin/bot will ask you which class of bot you want to run, while bin/bot_cluster
will ask how many bots of each class you want to run. After the bots are created, you will be given the choice to either create a new table,
join an existing table, or join a tournament.
Here is an example from bin/bot:
>$ bin/bot Choose a bot: 1: AllInBot 2: HumanClient 3: RandomBot 4: SmartBot 5: SuperSteadyBot Choose a bot class: > 2 Player name? > Daniel Tournament or table? (1 = tournament, 2 = table)
With both bin/bot and bin/bot_cluster, after the bots are created you will be given the option to create or join a table:
Tournament or table? (1 = tournament, 2 = table) > 2 Join an existing room or create a new one? type 'join' to join an existing room or the name of a room to create a new one > Awesome Number of players to wait for before starting the table? > 5
This will create a table named ‘Awesome’ that will start once 5 people have joined
To join an existing table the process goes like this:
Tournament or table? (1 = tournament, 2 = table) > 2 Join an existing room or create a new one? type 'join' to join an existing room or the name of a room to create a new one > join Table 1: Awesome Blinds 1 Min Players 5 Join which table? > 1
The bot will now join that table and wait for the table to start.
A PokerMatic tournament allows you to run a multi-table tournament with many bots competing against each other. The tournament
code will take care of splitting players into tables of 10, rebalancing tables as players are eliminated, and also keep track
of blind increases over time. Each player starts with 5000 chips. The tournament is over when only one bot remains!
To create a tournament, you need to use the admin tool. The admin tool will use the SPIRE_EMAIL and SPIRE_PASSWORD from your
config.rb file, so make sure those values match the values that the server is using.
The easiest way to use it is from IRB.
$> bin/admin Tournament name? > Awesome Tournament 1: Wed Feb 01 17:20:00 -0800 2012 2: Wed Feb 01 17:21:00 -0800 2012 3: Wed Feb 01 17:22:00 -0800 2012 4: Wed Feb 01 17:23:00 -0800 2012 5: Wed Feb 01 17:24:00 -0800 2012 6: Wed Feb 01 17:25:00 -0800 2012 7: Wed Feb 01 17:30:00 -0800 2012 8: Wed Feb 01 17:35:00 -0800 2012 9: Wed Feb 01 17:40:00 -0800 2012 10: Wed Feb 01 17:45:00 -0800 2012 11: Wed Feb 01 17:50:00 -0800 2012 12: Wed Feb 01 18:50:00 -0800 2012 13: Wed Feb 01 19:50:00 -0800 2012 14: Wed Feb 01 20:50:00 -0800 2012 15: Wed Feb 01 21:50:00 -0800 2012 Time? > 3 Starting Blinds? > 25 Increase blinds every how many seconds? > 600
This will create a tournament that starts at 5:22 PM with blinds starting at 25 and increasing every 10 minutes.
To join the tournament with a bot:
Tournament or table? (1 = tournament, 2 = table) > 1 Tourney 1: Awesome Tournament Starting at Wed Feb 01 17:22:00 -0800 2012 Join which tourney? > 1
The bot will automatically be assigned to a table when the tournament starts.
PokerMatic comes with a base class (PokerClientBase) that you can extend to create your own poker bots. Bots are
placed in the /bots folder. Included are a few example bots to give you an idea of how a bot works. Also included is a
human_client, which is not really a bot but rather is a CLI client that asks a human for each move; you can use it to actually
play poker (albeit with a poor user interface).
When subclassing PokerClientBase, there is only one method that MUST be defined: ask_for_move, which receives
a GameState object when it is called. This function should return the move the client wants to take; valid moves are
‘fold’, ‘call’, ‘check’, or an amount to bet. Note that all of these moves are not available at all times; you cannot check
if a bet has already occurred, of course. A list of available moves is accessible by calling #available_moves on the GameState
object (this will be explained in more detail below).
For your bot to be included as an available bot when running bin/bot or bin/bot_cluster, just make sure the .rb file is in
the /bots directory and contains at least one class that is a subclass of PokerClientBase. If you do this, it will automatically
be included as a bot option.
The GameState object that is passed to ask_for_move contains all of the information about the current hand being played
and all of the players at the table. It includes both a ruby representation of the JSON object that the poker server
sends after each play at the table, as well as the pocket cards that the client has.
The information stored in a GameState object can be retrieved by either method call or hash.
For example, to access the current hand number, both of these will work:
game_state.hand_number
game_state[‘hand_number’]
Here is a list of all available attributes that the GameState object contains:
hand
An array of the client’s two pocket cards. For example:
[{"name"=>5, “suit”=>"Club", “value”=>5, “string”=>"5 of Clubs"},
{"name"=>"King", “suit”=>"Heart", “value”=>13, “string”=>"King of Hearts"}]
hand_number
The current hand number. Starts at 1, each hand delt at a table increases this by one.
button
The current position of the button (dealer) at the table. Corresponds to the position in
the ‘players’ array (0 indexed).
players
An array of hashes describing the players at the table. For example:
[{"name"=>"Daniel", “bankroll”=>506, “id”=>1804618},
{"name"=>"Rando", “bankroll”=>494, “id”=>1804619}]
acting_seat
The index of the currently acting player in the players array.
last_five_moves
An array of (up to) the last 5 moves of the hand. The most recent action is the last in the array.
For example:
[
{"player"=>1804618, “action”=>"raise", “bet_amount”=>3, “current_total_bet”=>4, “pot”=>6},
{"player"=>1804619, “action”=>"raise", “bet_amount”=>4, “current_total_bet”=>6, “pot”=>10},
{"player"=>1804618, “action”=>"call", “bet_amount”=>2, “current_total_bet”=>6, “pot”=>12}
]
current_bet
The total of the current bet. This is the per player bet, not the total for the round.
minimum_bet
The minimum bet a player can make.
player_bets
A hash of all the total bet each player has made in the current round, indexed by a string version
of the player id. For example:
{"1804618"=> 6, “1804619” => 8}
available_moves
A hash of all the available moves a player has given the current state of the board and the players
bankroll. The key is the name of the move and the value is the cost to the player to take that move. For example:
{"fold"=>0, “bet”=>2, “all_in”=>494, “check”=>0}
The value for bet is the MINIMUM bet, but the bet can be anywhere between this value and the all_in value.
round_history
A complete history of the betting in the current round (pre-flop, flop, etc) in the same format as last_five_moves. The most recent
action is last.
phase_name
Name of the current phase. Possible values are ‘New Hand’, ‘Pre-Flop’, ‘Flop’, ‘Turn’, ‘River’
phase
A numeric representation of the current phase. Values are:
0 – New Hand
1 – Pre-Flop
2 – Flop
3 – Turn
4 – River
players_waiting_to_join
A list of all players who wish to join the table. If a player has money in their bankroll,
they will join the game at the start of the next hand. This is also where players are placed after running
out of money.
all_in
An array of any players who are all in for the hand. Each element of the array is a hash describing the player as
well as the size of the pot they are eligible for (due to side pots). For example:
[
{"player"=>{"name"=>"Rando", “bankroll”=>0, “id”=>1804619}, “pot”=>600},
{"player"=>{"name"=>"Daniel", “bankroll”=>0, “id”=>1804618}, “pot”=>1000}
]
board
An array describing the community cards. Depending on the phase of the game, this will be either 0,3,4 or 5 cards. For example:
[
{"name"=>5, “suit”=>"Spade", “value”=>5, “string”=>"5 of Spades"},
{"name"=>"King", “suit”=>"Spade", “value”=>13, “string”=>"King of Spades"},
{"name"=>"Jack", “suit”=>"Diamond", “value”=>11, “string”=>"Jack of Diamonds"}
]
pot
The current size of the pot
players_in_hand
An array of the ids of players who are still in the hand (not folded).
acting_player
A hash describing the acting player. For example:
{"name"=>"Daniel", “bankroll”=>494, “id”=>1804618}