Inhuman-is a poker bot of the Openholdem class. Everything below the action can and should be done in a simple text editor. Or, for large, you can download a text editor here >>>>>>>>>>>>>>>
To check the profile for errors, use the Openholdem robot. Our robot will save your formula in encrypted form and you will not be able to edit it in a text editor. OH can be downloaded here.
Structure Of A PPL-File
If you have used Poker bot in the past you will know that you have to answer several questions: Shall I go allin? Shall I raise? Shall I call? And if you answer all questions with no then Poker bot will fold. That is one approach and it clearly has some pros. But most poker-playing people and non-programers will find a different approach more easy: What shall I do in this situation? And that’s exactly how OpenPPL works.
Simple When Conditions With Actions
The most simple way to code a bot consists of a series of conditions followed by actions to be chosen.
WHEN HaveFlushDraw AND AmountToCall < 1/3 PotSize Call FORCE
These conditions are always evaluated top-down. Once the first condition is true, the appropriate action will be taken. Always! – so the order of programming matters. Let’s assume, that you want to call your flushdraws, but raise to 10bb your nut-flushdraws (expert-strategy 2012). Then you will have to write your commands in the
following order:
WHEN HaveNutFlushDraw RaiseTo 10 FORCE
WHEN HaveFlushDraw Call FORCE
Do it the other way and your nut-flush-draw would trigger the rule for normal flush-draws. A call would be the result. As a consequence of this top-down-evaluation we recommend you deal with:
The bot simply does not know if one rule is “more special” or “more important” — you have to tell it by your coding order.
If you wonder about the keyword force: it was inherited from Shanky-PPL and means, that it overwrites the default bot (without Force). Though we don’t provide a default bot and don’t think, that user-defined actions should be ignored if they lack the FORCE, we kept this keyword to stay compatible and because it is nice to read (syntactical sugar).
Open-Ended When Conditions
Programming your bot with when-conditions alone will — in principle — do the job, but there will be lots of situations that are very similar.
WHEN hand$AT AND StillToAct = 2 AND Raises = 1 AND AmountToCall <= 4 RaisePot FORCE
WHEN hand$AT AND StillToAct = 2 AND Raises = 1 AND AmountToCall > 4 Fold FORCE
WHEN hand$AT AND StillToAct = 2 AND Raises = 2 …
Here one part of the condition gets repeated:
WHEN hand$AT AND StillToAct = 2
For more sophisticated profiles this would be lots of code to write, lots of code to evaluate and a true nightmare to change once you want to improve it. So OpenPPL provides two kinds of conditions: top-level conditions without actions (called “open-ended when-conditions”) and simple “when conditions with actions” like explained above.
Once the first open-ended-when-condition is located all following “normal” when-conditions are bound to that condition and only evaluated when the open-ended when-condition is true. So you could rewrite the example above like that:
WHEN hand$AT AND StillToAct = 2
WHEN Raises = 1 AND AmountToCall <= 4 RaisePot FORCE
WHEN Raises = 1 AND AmountToCall > 4 Fold FORCE
WHEN Raises = 2 …
WHEN hand$A9 AND StillToAct = 2
…
Each open-ended when-condition is active until the next open-ended when-condition is found. In the example above:
WHEN hand$A9 AND StillToAct = 2
To terminate all your open-ended when-conditions just write:
When Others
…
When Others Fold Force
Coding this way makes your code smaller, more easy to read and more easy to change. However: some people would like to take code-structuring to extremes and use multiple nested open-ended when-conditions like below:
WHEN hand$AT
WHEN StillToAct = 2
WHEN Raises = 1
WHEN (AmountToCall <= 4) RaisePot FORCE
WHEN (AmountToCall > 4) Fold FORCE
WHEN Raises = 2
WHEN…
In principle this is a good idea, but it does not work. Simply because there is no way to tell, where one open-ended when-condition ends and where the next one starts. So the semantics would be completely undefined (it is in fact not, but it is for sure not what you want). Sure you could argue about indentation, but spaces have no meaning in most programming languages (except good old Fortran 77) and everybody does it differently. So let’s restate: There is at most one level of open-ended when-conditions (without action), each one bound to a sequence of when-conditions with actions. If you want to structure your code even more (a very good idea!) then we recommend to look at the chapter “Building Symbols On Your Own”.
Controlflow of Open-Ended When-Conditions
Structure Of A PPL-File
Once you understand how when-conditions work, programming your first bot becomes easy and straightforward: you just have to provide a sequence of when-conditions for Preflop, Flop, Turn and River. These 4 main code-sections are named f$preflop..f$river, because that’s how user-defined Poker bot symbols get named and from a technical point of view these code-sections are functions.
##f$preflop##
// This is a comment
// Your code belongs here.
WHEN hand$AA RaiseMax FORCE
WHEN hand$KK …
…
WHEN Others Fold FORCE
##f$flop##
##f$turn##
##f$river##
Unspecified Return Values
It is common practice to add
WHEN Others Fold FORCE
to the end of every code-section. But it does not hurt if you forget to do so. If no condition matches the situation Poker bot will automatically evaluate this function to zero, which is also the encoding for false, and also for check/fold.
More Advanced Coding
Coding sequences of when-conditions is very easy and intuitive, however there is one big disadvantage: poker is a somewhat complex game and there are countless situations to consider. So these code-blocks can become rather large — too large for a sane human mind. But of course there is a solution: OpenPPL supports structured coding, namely:
Both of them are very useful, but a little bit “advanced” and not standard Shanky-PPL. So we discuss them in later chapters of this manual.
Hand And Board Expressions
Hand expressions
One of the most important decisions of the game happens preflop: shall I play this hand and how? This decision can be coded with the self-explanatory hand-expression, like in the example below:
WHEN hand$AA RaiseMax FORCE
WHEN hand$AQSuited OR hand$AJSuited RaiseTo 3 FORCE
WHEN hand$22 OR hand$33 OR hand$44… Call FORCE
AK does include both AKs and AKo. So if you want to play suited hands differently you should code them first, as OpenPPL gets evaluated top down. It will stop at the first condition that matches (evaluates to true). So always remember: strong hands first, exceptions first, bad hands later.
Coding For Specific Suits
If you want you can also code for specific suits, like an ace of diamonds in your hand. This is rarely necessary, but was used in the past (before real randomization was introduced to Standard PPL) to randomize actions.
WHEN hand$AcQd Or hand$JhTs …
// Randomize your Action, the old way
WHEN hand$AdT RaiseTo 10 FORCE
WHEN hand$AT Call FORCE
But be careful with the code below:
WHEN hand$AKs…
It means: any ace and king of spades, but not AK suited
Board Expressions
A lot of the game also depends on the board cards. There are symbols like “HaveStraightDraw” or “FlushPossibleOnTurn“, but for some cases might not be concrete enough. Therefore it is possible to specify board-states similar to the above:
// Calling, if any ace is on the board
WHEN board$A Call FORCE
// Raising, if there is a low pair on board
WHEN board$22 OR board$33 OR board$44… RaiseTo 10 FORCE
// Raising, if there are A and T of the same suit
WHEN board$AT SUITED RaisePot FORCE
You see, this is pretty straightforward, but sometimes lots of code to write. If you want to create code that is easy to understand, easy to reuse and easy to maintain, then you should encapsulate expressions like the second one in functions (place it within its own function):
##f$LowPairOnBoard##
WHEN board$22 OR board$33 OR board$44… RETURN TRUE
User-defined variables would also be possible, but they are not nearly as good as functions.
The main code sections of Open-PPL consist of when-conditions with actions. They look e.g. like this:
##f$preflop##
// Openraising on the button
WHEN (Raises = 0 and Calls = 0 and StillToAct = 2)
// Normal openraises
WHEN ((Hand$AA) or (Hand$KK)…) RaiseTo 3 FORCE
// Pushing according to Sklanky
WHEN (StackSize < 20 and ((Hand$ ...) OR ...)) RaiseMax FORCE
OpenPPL provides 3 kinds of actions:
Fixed Actions
Examples look like
BetMax FORCE
RaiseMax FORCE
BetPot FORCE
RaisePot FORCE
BetThreeFourthPot FORCE
RaiseThreeFourthPot FORCE
BetTwoThirdPot FORCE
RaiseTwoThirdPot FORCE
BetHalfPot FORCE
RaiseHalfPot FORCE
BetThirdPot FORCE
RaiseThirdPot FORCE
BetFourthPot FORCE
RaiseFourthPot FORCE
Bet FORCE // min-bet (fixed limit)
Raise FORCE // min-raise (fixed limit)
BetMin FORCE
RaiseMin FORCE
Call FORCE
Check FORCE
Fold FORCE
Beep FORCE // beep, but don’t act
Contrary to standard PPL OpenPPL does not distinguish bets and raises.Poker bot treats them exactly the same way.
Please note: SitOut is no longer a supported action. In our opinion it is beneficial to separate playing logic and hopper logic. Therefore Poker bot provides some hopper-functionality, especially the functions f$sitin, f$sitout, f$leave and f$close.
Please also note: fixed actions are functions from a technical point of view, therefore they are case-sensitive.
Actions With Fixed Betsize
Examples look like
RaiseTo 3.5 FORCE
or
RaiseBy 2.5 FORCE
RaiseTo specifies your final betsize, RaiseBy specifies the amount you want to add to the aggressors bet-amount.
Actions With Relative Betsize
Examples look like
RaiseBy 70% FORCE
Here the betsize gets measured as a certain percentage of the pot (pot = common pot + all players bets + the amount to call). Potsized bets are always RaiseBy.
Using Expressions For The Bet-Amount
Let’s assume you want to raise to 3 bb in an unraised pot, plus 1 bb for each caller. With standard PPL this would result in clumsy code. But with OpenPPL you can simply write:
WHEN (Raises = 0) RaiseTo (3 + Calls) FORCE
If you want you could take this to extremes and write good code like the following:
##f$MyFavouriteBetsizeForDryBoards##
…
WHEN (…) RaiseTo f$MyFavouriteBetsizeForDryBoards FORCE
Being strict: using “FORCE”
Every action in OpenPPL has to be terminated by the keyword “FORCE”. For standard PPL this keyword was optional. If you left it out, it meant, that the bot continued to evaluate and finally fell back to the default logic. We deviated from that behaviour, as:
in our opinion it does not make any sense to specify actions that have no effect.
OpenPPL does not provide a default bot.
Quickfolding bad hands
Most poker-sites provide pre-action-buttons to act before it is your turn. Especially useful is the prefold-button that makes it possible to click bad hands away and forget about them. Being able to click this button with your bot has at least two positive effects: more human-like behaviour and playing more hands per hour due to faster actions . Nothing could be more easy:
##f$prefold##
WHEN AmountToCall > 0 AND (hand$32 OR hand$43 OR …) Return True FORCE
Be aware of potentially unstable game-states!
Please note:
prefold gets evaluated when it is not your turn. Therefore it might happen that Poker bot takes a screenshot, evaluates and acts while the casino updates its table-display and the game-state is unstable. “Garbage in — garbage out” will happen. Now let’s assume you have some super-nitty bot:
##f$prefold##
WHEN (NOT ((Hand$AA) OR (Hand$KK))) Fold FORCE
Fold when I don’t have a good hand”. But here your good hand can not get recognized because your aces get only displayed partially. Your bot would fold pocket aces! To avoid problems like that it is recommend to code more fail-safe like in the first example: “Fold when I have a bad hand”. It won’t hurt that much if that command failed and worked only on the next heart-beat-cycle.
There are even more consequences of potentially unstable frames: OpenPPL does its main calculations when it is your turn. Especially some more complex symbols which depend on the history of the game get updated only when we have stable frames to guarantee their correctness — RaisesSinceLastPlay or LastCallerPosition are examples. As a consequence these symbols will simply be undefined before your first action preflop. Therefore it is recommended to be extra careful about the GIGO-principle and stick to the most basic symbols only. But this is not too hard for prefold, is it?
Backup actions
It may happen, that a certain action is not available, e.g. you might want to raise by half the pot, but this is currently not possible, e.g. because your opponent made a large raise and half-pot would be less than the minimum. In such situations OpenPPL behaves in the following ways:
betsize invalid (too less or too much (PotLimit or more than your balance)): betsize gets automatically adapted. This happens also to actions like RaisePot and RaiseHalfPot, that get executed with the f$betsize-function.
action can’t be executed, because it is not possible, e.g. there might be no raise-button, because you can only call (allin) or fold. Here OpenPPL behaves in the following way:
RaisePot if RaiseMax is not possible
Raise(Min) if RaisePot or RaiseHalfPot is not possible
Call if no Raise is possible
Check if no Call is possible
Fold if no Check is possible (default behaviour of Poker bot).
This deviates from standard PPL again. However we have the following reasons:
Poker bot evaluates its technical functions in the order above (for details please refer to the OpenHoldem Manual).
we believe, it is better to behave in a more conservative way if an error occurs. Most probably you don’t want to push allin if you specify RaiseHalfPot as your desired action. With a min-raise you are probably more happy (or less unhappy).
Handlists
Poker bot supports preflop handlists to simplify preflop coding.
You can name handlists what you like, but handlist names need to start with the word “list”.
##list007##
// Allin-range against crazy maniacs
AA KK QQ JJ TT 99 // Pairs
AKs AQs AJs ATs KQs // Suited hands
AKo AQo AJo // Offsuited hands
##list0fTr4sh1w4ntT0C4ll##
72o 32o
After that you can use your custom handlist symbol like this:
WHEN (Opponents = 1 AND userManiacFourBetsMe AND list007 RaiseMax FORCE
There is no limit to the number of lists you can define and you can use any name you want. Indeed it is recommended that you choose verbose names that speek for themselves.
Mathematical Expressions
Of course OpenPPL supports arbitary complex mathematical expressions. As an example let us consider odds and outs.
// Calling according to odds and outs
WHEN AmountToCall / (AmountToCall + PotSize) > Outs / CardsLeft Call FORCE
Off course this example is a bit simplistic. It does not consider other players in the pot, implied odds on future streets, the chance to semi-bluff, etc. But I think you get the point.
The following operators are supported:
Equality Operators
Operator | Meaning | Example | Example explained | ||
= | equal |
|
true, if you are on the button | ||
!= | not equal |
|
|
||
< | smaller | AmountToCall < 5 | true, if there are less than 5 big blinds to call | ||
> | larger |
|
true, if the pot is larger than 20 big blinds | ||
<= |
|
AmountToCall <= 5 |
|
||
>= | larger or equal | PotSize >= 20 |
|
Logical Operators
The logical operators “and”, “or”, and “not” should be pretty self-explanatory.
Operator | Example |
Not | WHEN (HaveNothing AND OpponentsLeft >= 2 AND NOT BotIsLastRaiser) Check FORCE |
And | WHEN (BotIsLastRaiser AND OpponentsLeft = 1 AND Bets = 0 And … BetHalfPot FORCE) |
XOr | Meaning: either or, which is true, if exactly one of the operands is true, but not both |
Or | WHEN (hand$AA OR hand$KK) RaiseMax FORCE |
Negation (Not) has highest priority of all operators, thereafter follow And, XOr and OR in decreasing order. So if you want to write an expression like
WHEN AmountToCall <= 4 AND (hand$22 OR hand$33...))
you have to throw in some extra brackets, otherwise the bot will call with 33 any bet and that is probably not what you want. More complicated expressions sometimes lead to confusion. If you have a problem with that you might want to revisit the basics of mathematical logic and the “Laws of De Morgan”.
Arithmetical Operators
OpenPPL also supports basic arithmetic. The usual rules apply of course. The percentage-operator has the same priority like multiplication and division, which is higher than addition, subtraction.
Operator | Meaning | Example |
+ | addition | |
– | subtraction | |
* | multiplication | |
/ | division | |
% | Percentage-operator | WHEN (AmountToCall <= 50% PotSize) Call FORCE |
Mod | Modulus-operator |
Bitwise Operators (for Experts)
Furthermore OpenPPL supports bitwise operations that work on all single bits of bit-vectors or binary numbers simultaneously. They are useful for very low-level-stuff like detecting which chairs are seated with Poker bot’s bitwise symbols (playersseatedbits, playersdealtbits, etc.). Most players won’t ever need these symbols, so we will only give you a link to a good explanation here: http://en.wikipedia.org/wiki/Bitwise_operation
Operator
BitAnd
BitCount
BitNot
BitOr
BitXOr
User-Defined Variables
Most probably you need some game-history to take your decision; then you will find symbols like NoBettingOnFlop and Poker bot’s history symbols and they will be useful for a good portion os use-cases, but identifying very special situations afterwards only with the built-in symbols might be hard or even impossible. So wouldn’t it be helpful if you could remember what happened in the game? Of course you can – with user-defined variables. Let’s take a small example.
User-defined variables need to be prefixed with the word “user”, and the word Set when you give them a value.
WHEN FirstCallerPosition = 9 Set user_UTG_Was_Limping
As you see, there’s the Set command and after it there is a user-defined variable instead of an action after a condition, but no keyword force.
Whenever OpenPPL / Poker bot sees such a construct it evaluates the when-condition. If the condition is true, Poker bot sets the user-variable to true and continues with the evaluation, until it finds a true condition with an action.
All user-defined variables start with false (0). Once you set them they become true (or 1, which is technically the same).
User-defined variables keep their value for the current hand and can’t be reset back by the user. But when the hand is over they get reset automatically.
Naming: every user-defined variable starts with the prefix “user”, followed by a sequence of characters [a-zA-Z], digits [0-9] and underscores [_].
Querying the value of a variable is simple: you can use it just like any other symbol as part of an expression:
##f$preflop##
WHEN Hand$AA RaiseMax FORCE
WHEN Hand$KK Set userDoesNotKnowWhatToDo
WHEN Hand$QQ Set userStartsToCry
WHEN userDoesNotKnowWhatToDo Call FORCE
WHEN userStartsToCry SitOut FORCE
WHEN Others Fold FORCE
Expert Tricks (Memory Symbols)
Do you need variables that can be set to any arbitrary value? Do you need variables that can be reset back? Do you need variables that don’t reset automatically, but keep their values till the next hand or even for the complete session? There is a solution for it (of course). Instead of PPL-like user-variables it is also possible to use Poker bot’s memory-store-command (following example store the decimal number 3,14..):
WHEN (…) Set me_st_MySecretVariable_3_141592653
and then use it later with Poker bot’s memory-recall-command:
WHEN (… me_re_MySecretVariable …) …
This construct is a little bit more mighty, but also contains some possible pitfalls and requires extra care by the user.
Poker bot’s user-defined variables are case sensitive. me_st_x_1 is something different than me_st_X_1.
No underscores allowed in the name of the variable. Underscores are used to separate name and value. (If you wonder, why underscores are allowed in simple user-variables: because the translator removes them).
No automatic reset. If you need such a reset, you could do it e.g. before your first action preflop:
##f$preflop##
WHEN (BotsActionsOnThisRound = 0)
WHEN Others Set me_st_MySecretVariable_0
…
Table occlusion reset the memory variables.
May the force be with you!
Building Symbols On Your Own
The philosophy of (standard) PPL is: provide poker-logical symbols, that can be used by any poker-playing person, no matter how much (or less) programming experience they have. Examples are e.g. MaxOpponentStackSize, StartingStackSize
However this approach has some drawbacks: it shifts all work to the developers and limits the users, who might need additional symbols for their bot-logic. Staying with the example above, they might need: SmallBlindStacksize, BigBlindStacksize, UTGStacksize, …, ButtonStacksize, OpenRaiserStacksize, LimpRaiserStacksize, ThreeBetterStacksize, FlopCheckRaiserStacksize, TurnDonkerStacksize, etc. No matter how busy the development team is, they will never be able to satisfy all needs. Therefore Poker bot’s (and partially OpenPPLs) philosophy is slightly different: provide technical symbols like balance0..balance9 (the stacksizes for chair0..chair9) and let the user figure out the rest. This way the end-user is far more flexible; however at the cost of a bit more work.
As an example we develop a symbol BigBlindStackSize. As a first step we need to know the chair of the big blind. Then as a second step we will be able to return the stacksize for this chair. To solve the first problem we use the Poker bot symbol ac_dealposX which returns the deal-position of chair X. The big blind is (with the very rare exception of a missing small blind) always the second player to be dealt, so we search for a the chair, that got dealt as second player.
##f$BigBlindChair##
WHEN ac_dealpos0 = 2 RETURN 0 FORCE
WHEN ac_dealpos1 = 2 RETURN 1 FORCE
WHEN ac_dealpos2 = 2 RETURN 2 FORCE
WHEN ac_dealpos3 = 2 RETURN 3 FORCE
WHEN ac_dealpos4 = 2 RETURN 4 FORCE
WHEN ac_dealpos5 = 2 RETURN 5 FORCE
WHEN ac_dealpos6 = 2 RETURN 6 FORCE
WHEN ac_dealpos7 = 2 RETURN 7 FORCE
WHEN ac_dealpos8 = 2 RETURN 8 FORCE
WHEN ac_dealpos9 = 2 RETURN 9 FORCE
// Other cases should not happen
WHEN Others RETURN -1 FORCE
Having this information we can continue with the second step (the dull part). We return the stacksize for the chair of the big blind, making use of Poker bot’s stacksize symbols balance0..balance9. As you can see it is possible to use Poker bot Symbols in your OpenPPL code. Of course – we nearly forgot to mention it.
##f$BigBlindStacksize##
WHEN (f$BigBlindChair = 0) RETURN balance0 FORCE
WHEN (f$BigBlindChair = 1) RETURN balance1 FORCE
WHEN (f$BigBlindChair = 2) RETURN balance2 FORCE
WHEN (f$BigBlindChair = 3) RETURN balance3 FORCE
WHEN (f$BigBlindChair = 4) RETURN balance4 FORCE
WHEN (f$BigBlindChair = 5) RETURN balance5 FORCE
WHEN (f$BigBlindChair = 6) RETURN balance6 FORCE
WHEN (f$BigBlindChair = 7) RETURN balance7 FORCE
WHEN (f$BigBlindChair = 8) RETURN balance8 FORCE
WHEN (f$BigBlindChair = 9) RETURN balance9 FORCE
// Other cases should not happen.
// But if you forget about “WHEN Others”
// there always is an implicit “RETURN 0 FORCE”.
WHEN Others RETURN 0 FORCE
You see: it is not that difficult to extend OpenPPL on your own. The possibilites are nearly endless. For the moment we skipped some details, but creating new symbols is self-explaining: each new symbol starts with a function header, that defines its name. The name of user-defined symbols traditionally begines with f$. For example ##f$BigBlindStacksize##. Thereafter follows the function’s code, which usually is in a sequence of (optionally open-ended) when-conditions. These when-conditions usually define actions (in the case of f$preflop… f$river) or they contain return-statements like in the example above.
That’s all. OpenPPL is easy.
Advantages of Symbols
In our early versions of the manual we didn’t talk about the advantages of structured code (especially functions AKA symbols), because they were too obvious for us. This caused some confusions for newbies. Symbols are great:
to get understandable and self-documenting code (good naming; http://en.wikipedia.org/wiki/Information_hiding)
to get reusabel code (named code-snippets)
to get small code (no code clones)
to get maintainable code (change and fix one location only)
to get fast code (because of Poker bot’s symbol-caching: evaluates only once, use the value often)
to get readable log-files (because you see all the symbol-names and their values)
…
So how often should you make use of symbols?
All day. Everywhere. As much as possible. Enjoy them!
Name | Meaning |
AllOpponentsLeftSittingOut | True, if all remaining opponents are sitting out. This symbol is especially meant for use in tournaments |
Bets | The number of bets made by opponents this betting round, can only be 0 or 1 since the 2nd bet is a raise |
BigBlindSittingOut | True, if the big blind is sitting out. This symbol is especially meant for use in tournaments |
BotCalledBeforeFlop | True if we called preflop |
BotCalledOnFlop | True if we called on the flop |
BotCalledOnTurn | True if we called on the turn |
BotCalledOnRiver | True if we called on the river |
BotIsLastRaiser | True if we have the betting / raising initiative, i.e we were the last raiser on the previous round |
BotRaisedBeforeFlop | True if we raised preflop, can also be used preflop |
BotRaisedOnFlop | True if we bet or raised on the flop, can also be used on the flop |
BotRaisedOnTurn | True if we bet or raised on the turn, can also be used on the turn |
BotsActionsOnFlop | Number of actions where we put money in the pot on the Flop |
BotsActionsOnThisRound | Number of actions this betting round where we put money in the pot |
BotsActionsOnThisRoundIncludingChecks | Number of checks + number of actions where we put money in the pot |
BotsActionsPreflop | Number of actions where we put money in the pot preflop, all-ins are not counted as the game would then be over |
BotCheckedPreflop | True if bot checked preflop |
BotCheckedOnFlop | True if bot checked on the flop |
BotCheckedOnTurn | True if bot checked on the turn |
BotCheckedOnRiver | True if bot checked on the river |
BotsLastAction | Bot’s last action, can be one of the following: None, Beep, Raise, Bet, Call, or Check |
BotsLastPreflopAction | Bot’s last preflop action, can be one of the following: None, Beep, Raise, Bet, Call, or Check |
Calls | The number of calls by opponents on this betting round |
CallsSinceLastRaise | The number of calls by all opponents since the last raise by an opponent on the current betting round |
Checks | The number of checks made by opponents this betting round |
Folds | The number of folds this betting round |
MissingSmallBlind | True, if there is no small blind in this hand, e.g. the player who would have been SB did bust in the previous hand. |
NoBettingOnFlop | True if no bets/raises were made on the Flop, may also be used on the Flop. Bets by hero are also counted |
NoBettingOnTurn | True if no bets/raises were made on the Turn, may also be used on the Turn, p. Bets by hero are also counted |
NoVillainBetOrRaisedOnFlop | No villan bet or raised on Flop. Bets by hero are not counted |
NoVillainBetOrRaisedOnTurn | No villan bet or raised on Turn. p. Bets by hero are not counted |
NumberOfOpponentsAllin | Number of opponents who raised or called allin. Range: 0..9. If the amount to call is equal to our stack size and we are headsUp we consider the villan as being allin. |
NumberOfRaisesBeforeFlop | The number of raises before the Flop made by opponents |
NumberOfRaisesOnFlop | The number of raises on the Flop made by opponents. Bets don’t count |
NumberOfRaisesOnTurn | The number of raises on the Turn made by opponents. Bets don’t count. |
OpponentCalledOnFlop | An opponent called on Flop, and did not raise or bet |
OpponentCalledOnTurn | An opponent called on Turn, and did not raise or bet |
OpponentIsAllin | An opponent is all in, there may still be other players in the hand. If the amount to call is equal to our stack size and we are headsUp we consider the villan as being allin. |
Raises | The number of raises made by opponents this betting round. Bets don’t count. |
RaisesBeforeFlop | True if any opponent raised before the flop |
RaisesOnFlop | True if any opponent raised on the flop. Bets don’t count. |
RaisesOnTurn | True if any opponent raised on the turn. Bets don’t count. |
RaisesSinceLastPlay | The number of raises since our last action. Bets don’t count |
SmallBlindSittingOut | True, if the big small is sitting out. This symbol is especially meant for use in tournaments |
Betsizes And Stacksizes
Standard PPL is a bit restrictive: betsizes, stacksizes and potsizes may appear only on the left or on the right side of comparison operators — please don’t ask us about the exact rules, we forgot them. In OpenPPL you can put them anywhere you like.
WHEN (AmountToCall < Pi * R * R) DANCE FORCE
Name | Meaning | Limitations |
AmountToCall | The amount to call, counted in bigblinds | None |
BetSize | The number of big blinds bet by the last aggressor | None |
BigBlindSize | The size of the bigblind, usually in dollars | None |
MaxStacksizeOfActiveOpponents | The biggest stack size (expressed in bblind and not dollars) of all opponents currently playing the hand. | Could be bigger than your balance. Use EffectiveMaxStacksizeOfActiveOpponents to know exactly the balance at risk. |
EffectiveMaxStacksizeOfActiveOpponents | The biggest effective stack size (expressed in bblind and not dollars) of all opponents currently playing the hand. | You some opponents have more chips/money than you the symbol will return the amout of your balance to reflect how much bot is risking in a specified hand. |
MaxOpponentStackSize | The biggest stack of all opponents (playing and not playing). measured in big blinds at the beginning of the hand | None
Depends on game-history (game-state on your first action)
|
MaxStillToActStackSize | The number of big blinds in the stack of the opponent with the largest stack who has not acted yet | First action preflop only |
MinOpponentStackSize | The smallest stack of all opponents. (playing and not playing) measured in big blinds at the beginning of the hand | None
Depends on game-history (game-state on your first action)
|
MinStillToActStackSize | The biggest stack of the opponents behind you (including SB and BB), measured in big blinds | First action preflop only |
OpponentStacksizeHeadsUp | Stack size of opponent when headsup. Please read Limitations | OpponentStacksizeHeadsUp return -1 when not valid. When using this symbol you have to check if the result is > -1 and then make your comparison. |
PotSize | The current pot, including all players bets, counted in big blinds. PotSize returns effective pot size you are participating in. | None |
StackSize | Our current balance, counted in big blinds | None |
StackSizeAtBeginningOfCurrentRound | Our Stack Size at the beginning of current betting round ( StackSize + TotalInvestedThisRound ) | Valid on every betting round |
StartingChips | Our balance at the start of a session, counted in “dollars” This symbol is especially meant for MTTs. | None. |
StartingStackSize | Our balance at the start of a session, counted in big blinds | None
Depends on game-history (game-state on your first action)
|
TotalInvested | The money put into the pot in this hand, counted in big blinds | None |
TotalInvestedThisRound | Amount Invested in current betting round | None |
Board Symbols
If a set is on board, “PairOnBoard” is also true; full houses do also count as sets and pairs, made flushes as flushdraws, etc. One of many reasons why you should code strong hands first.
Name | Meaning |
SecondTopFlopCardPairedOnRiver | Synonym for SecondTopFlopCardPairedOnRiver |
SecondTopFlopCardPairedOnTurn | Synonym for SecondTopFlopCardPairedOnTurn |
AcePresentOnFlop | An ace is present on Flop |
FlushOnBoard | The entire board are the same suit |
FlushPossible | A flush is possible on the current board (3 or more of 1 suit) |
FlushPossibleOnFlop | The entire Flop is one suit |
FlushPossibleOnTurn | A flush is possible on the Turn |
FourCardsToWheelOnBoard | True if a wheel can be made by using only one hole card, i.e. if 4 cards of A2345 are on the board |
FourOfOneSuitOnTurn | True if only 1 suit is/was present on the board on the Turn |
FullHouseOnBoard | There is a full house on the board |
HighCardOfCommonStraigh | Returns the value of the highest card of a shared straight. Especially meant to decide if we have the shared nuts (Ace) or if we can beat the board |
KingPresentOnFlop | True, if at least one of the Flop-cards is a king |
LowCardsOnBoard | The number of cards with the rank of 8 or lower (ace is counted as low). Duplicates of one rank are not counted |
MoreThanOneStraightPossibleOnFlop | More than one straight is possible on the Flop |
MoreThanOneStraightPossibleOnTurn | There is/was more than one way to make a straight on the Turn |
NutsOnBoard | True if the best possible hand is on the onboard |
OneCardFlushPossible | The board contains 4 or 5 cards of the same colour |
OneCardStraightFlushPossible | Only one holecard is needed to make a straightflush |
OneCardStraightPossible | Only one hole card is needed to make a straight |
OneCardStraightPossibleOnTurn | A one card straight is/was possible on the Turn |
Only1OneCardStraightPossible | only one straight can be made using only one hole card with the current board cards |
OnlyOneStraightPossible | Only one straight possible |
OvercardsOnBoard | The number of common cards that are higher than the highest card in our hand |
PairOnBoard | There are at least 2 cards of the same rank on the board |
PairOnFlop | A pair is present on the Flop |
PairOnTurn | The board has a pair on the Turn or on the Flop) |
QuadsOnBoard | There are quads on the board |
QueenPresentOnFlop | A queen is present on the Flop |
RiverCardIsOvercardToBoard | The River card is the highest ranked common card |
RunnerRunnerFlushPossibleAtRiver | True if a Runner Runner Flush is possible at the River |
SecondTopFlopCardPairedOnRiver | True, if the 2nd highest Flop card paired on the River. If the Flop is paired it will be the lowest card. If all ranks are equal quads at the River will make this function true. |
SecondTopFlopCardPairedOnTurn | True, if the 2nd highest Flop card paired on the Turn. If the Flop is paired it will be the lowest card. If all ranks are equal quads at the Turn will make this function true. |
StraightFlushOnBoard | Straight flush is on board |
StraightFlushPossible | Straight flush is possible |
StraightFlushPossibleByOthers | A straight flush can be made by an opponent with regards to our cards |
StraightOnBoard | The board contains a straight |
StraightPossible | Straight is possible |
StraightPossibleOnFlop | A stright is possible on the Flop |
StraightPossibleOnTurn | A stright is possible on the Turn |
SuitsOnBoard | The number of different suits on board. Always 0 Preflop. |
SuitsOnFlop | The number of different suits on the Flop. Always 0 Preflop. |
SuitsOnRiver | The number of different suits on the River. Always 0 Preflop, at the Flop and the Turn. |
SuitsOnTurn | The number of different suits on the Turn. Always 0 Preflop and at the Flop. |
ThreeCardStraightOnBoard | There are at least three connected cards on the board |
TopFlopCardPairedonRiver | The card with the highest rank on the Flop paired on the River |
TopFlopCardPairedonTurn | The card with the highest rank on the Flop paired on the Turn |
TripsOnBoard | At least three cards of the same rank are present on the board |
TripsOnBoardOnTurn | At least three cards of the same rank is present on the Turn |
TurnCardIsOvercardToBoard | The Turn card is the highest ranked common card |
TurnCardPaired | The card that was dealt on the Turn paired on the River |
TwoOfOneSuitPresentOnFlop | True, if the Flop has / had at least 2 cards of the same suit. |
TwoPairOnBoard | True, if the board contains two pairs |
TwoPairOnBoardOnTurn | True, if the board contained two pairs on Turn |
UncoordinatedFlop | True, if the Flop contains/contained no pair on board, no possible flush, three different suits, no possible straight and no opponent could have 7 or more outs to a straight |
WheelPossible | True, if a straight with A2345 is possible |
HandStrength Symbols
If a set is on board, “PairOnBoard” is also true; full houses do also count as sets and pairs, made flushes as flushdraws, etc. Therefore it is a strongly recommended to code made hands first (and strong made hands at the very beginning), then weaker holding with positive potential and weaker draws at the very last.
Name | Meaning |
HadOverpairOnFlop | Our pocketpair is/was of higher rank than the highest ranked flop card |
HadOverPairOnTurn | Our pocketpair is/was of higher rank than the highest ranked turn card |
HadPairOnFlop | We had a pair on the flop |
HadPairOnTurn | We had a pair on the turn |
HadSetOnFlop | We had a Set on flop |
HadSetOnTurn | We had a Set on turn |
HadTopPairOnFlop | Have/had top pair on flop |
HadTopPairOnTurn | Have/had top pair on turn |
HadTwoPairOnFlop | We had two pair on the flop |
HadSecondOverPairOnFlop | We had 2nd over pair on flop |
HadSecondOverPairOnTurn | We had 2nd over pair on flop |
HadSecondTopPairOnFlop | We had 2nd top pair on flop |
HaveSecondBestKicker | There is only one card that is better than our current kicker |
HaveSecondBestKickerOrBetter | We have the best or second best kicker |
HaveSecondBestOverPairOrBetter | We have the second best overpair (KK) or a stronger hand |
HaveSecondNutFlush | We have the second best flush possible |
HaveSecondNutFlushDraw | We have the second best flush draw |
HaveSecondNutStraight | We have the second best straight possible |
HaveSecondOverPair | We have a hole pair which is between the highest board card and the 2nd highest card rank on board |
HaveSecondTopPair | We have the second highest pair |
HaveSecondTopSet | We have the second best set |
HaveThirdBestKicker | We have the third best kicker |
HaveThirdBestKickerOrBetter | We have the third best kicker or better |
HaveThirdBestOverPairOrBetter | We have the third best overpair (QQ) or a better hand |
HaveThirdNutFlush | We have the Third best flush |
HaveThirdNutFlushDraw | We have the Third best flushdraw |
HaveThirdOverPair | We have a hole pair which is between the 2nd highest board card and the 3rd highest card rank on board |
HaveThirdTopPair | we have the Third highest pair |
HaveThirdTopSet | We have the Third highest set |
HaveFourthNutFlush | We have the Fourth highest flush |
HaveFourthNutFlushDraw | We have the Fourth highest flushdraw |
HaveFourthOverPair | We have a hole pair which is between the 3rd highest board card and the 4tf highest card rank on board |
HaveFourthTopPair | We have the Fourth highest pair |
HaveFourthTopSet | We Have the Fourth highest set |
HaveFifthNutFlush | We have the Fifth highest flush |
HaveFifthNutFlushDraw | We have the Fifth highest flushdraw |
HaveFifthOverPair | We have a hole pair which is between the 4th highest board card and the 5th highest card rank on board |
HaveFifthTopPair | We have the Fifth pair |
HaveBackdoorSecondNutFlushDraw | We have the 2nd highest backdoor nut flush draw |
HaveBackdoorThirdNutFlushDraw | We have the Third highest backdoor nut flush draw |
HaveBackdoorFlushDraw | We have a flush, flushdraw or a backdoor flushdraw. Have BackdoorFlushdraw is only true, if
|
HaveBackdoorNutFlushDraw | We have a backdoor nut flush draw |
HaveBackdoorStraightDraw | True, if we need 2 cards to complete a straight |
HaveBestKicker | We have the best kicker |
HaveBestKickerOrBetter | We have the best kickeBestOvr or a better hand |
HaveBestOverPairOrBetter | Have the best overpair (AA) or a better hand |
HaveBottomPair | We have a hole card that is paired with the lowest card on board |
HaveBottomSet | We have a set with the lowest board card |
HaveBottomTrips | We have a trips with the lowest board card |
HaveBottomTwoPair | We have bottom two pair |
HaveDoubleGutshotDraw | We have a double gut shot draw |
HaveFlush | We have a flush |
HaveFlushDraw | We have a flushdraw |
HaveFullHouse | We have a full house |
HaveInsideNutStraightDraw | True if the bot has an inside nut straight draw. An inside nut straight draw is defined as a hand with at least 4 ‘outs’ to a nut straight. Unlike NutStraightDraw, outs that make a flush possible are not excluded |
HaveInsideStraightDraw | We have an inside straight draw |
HaveNothing | We have nothing (no pair, overcards, flushdraw or straightdraw) |
HaveNutFlush | We have the nut flush |
HaveNutFlushCard | We have the nut flush card |
HaveNutFlushDraw | We have the nut flush draw |
HaveNuts | We have the best hand possible at this time |
HaveNutStraight | We have the best possible straight |
HaveNutStraightDraw | True, if we have a draw to the best straight; this means: if we hit, no better straight is possible. E.g.87 at a board of 653. A nut straight draw requires “at least 7 outs” according to Shankys definition. Therefore straight draws get discounted if there is a flush draw possible. Use HaveUnDiscountedNutStraightDraw if you don’t worry about possible flushes. |
HaveNutStraightFlush | We have the nut straight flush |
HaveOpenEndedStraightDraw | We have an open ended straight draw |
HaveOverPair | We have a pocketpair higher than any card on the board |
HavePair | We have a pair, a paired board doesen’t count |
HavePocketPair | We have a pocket-pair like AA or 55 |
HaveQuads | We have quads |
HaveRunnerRunnerFlushAtRiver | We have Flush and we made it with Turn and River card |
HaveSet | We have a set, i.e. three of a kind with a pair in the hand |
HaveStraight | We have a straight |
HaveStraightDraw | We have a straightdraw |
HaveStraightFlush | We have a straight flush |
HaveTopNonBoardPairedPair | One of our hole cards is the same value as the highest non-paired card on board |
HaveTopPair | One of our hole cards is paired with the highest ranked card on the board |
HaveTopSet | True, if we have a set with the highest board card |
HaveTopTwoPair | The two highest cards on the board are paired with our hole cards |
HaveTopTrips | True if we have the best possible trips |
HaveTrips | We have trips, i.e. three of a kind with a pair on the board |
HaveTwoPair | We have two pair, pair on board does not count |
HaveUnderPair | We have a pocketpair lower than the lowest ranked card on board |
HaveUnderStraight | We have the lower part of a straight |
KingPresentOnFlop | A king is present on the flop |
NutFullHouseOrFourOfAKind | This symbol evaluates the strength of quads and full houses. Top quads are always rated as 1, bottom quads or best-full house as 2, next best hand as 3 and so on. This symbol does not take straight flushes into account. So it could return 1 even if our hand can be beaten by a straight flush.
Standard PPL returns 0 if we don’t have any quads / FH at all. However we think this is counterintuitive and causes problems, as a smaller number means a better hand. OpenPPL returns 999 for that case.
|
Overcards | The number of hole cards that are overcards to the board |
PairInHand | True, if we have a pocketpair |
SuitsInHand | The number if unique suits in our hand |
TopPairRank | Rank of the hole card giving you Top Pair (2-14 where 14 is Ace) |
SecondTopPairRank | Rank of our second Top Pair |
ThirdTopPairRank | Rank of our third Top Pair |
ForthTopPairRank | Rank of our forth Top Pair |
FifthTopPairRank | Rank of our fifth Top Pair |
TopPairKickerRank | Rank of the hole kicker card when you have Top Pair (2-14 where 14 is Ace) |
TripsRank | Rank of our Trips |
TripsKickerRank | Rank of the kicker of our Trips |
Name | Meaning |
|
|
IsFinalTable | We are at the final table of a tournament | Works only with OpenHoldem 2.2.0.+ and at casinos where the final table and normal tables can be visually distinguised. See the tablemap-symbol s$isfinaltable. | |
Others | Always true – mainly used for When Others Fold Force | None | |
Random |
|
Gets evaluated new each time it gets used. So be careful if you code sequences of random actions. If you need a random function that stays constant for some time you could use the Poker bot symbols
But be careful: Poker bot random symbols are in the range [0..1] |
Player- and OpponentSymbols
Name | Meaning | Limitations |
HandIsHeadsup | True if two people compete for this pot. the hand might have been more-handed before. | None |
LastAggressorActsAfterUs | True (returns 1) if the last aggressor acts after us | None |
Opponents | The number of opponents that are currently in the hand. Does also count players that are allin (contrary to Shanky who count players that went allin in this betting round, but not players allin from previous rounds). | REMARK. To know the number of Opponents with balance above zero you should use the formula “Opponents – NumberOfOpponentsAllin” |
OpponentsAtTable | The number of opponents that were dealt cards this hand | None |
OpponentsLeft | Same meaning as Opponents but better naming. | None |
OpponentsOnFlop | The number of opponents that saw the Flop | None |
OpponentsWithHigherStack | The number of opponents that are seated and have higher balance than yourself | None |
OpponentsWithLowerStack | The number of opponents that are seated and have less balance than yourself | None |
TableIsHeadsup | True if only two people have been dealt (cash-game) and only two people are seated (tournaments, where players who sitout also get dealt). This symbol is especially meant to detect the latest stage of a tournament, contrary to HandIsHeadsup for cash-games. | None |
g.
Name | Meaning | Limitations |
FirstCallerPosition |
The position of the first caller
(big blind = 0 (although this can not happen), small blind = 1, then counter-clockwise till UTG = 9) |
First orbit preflop only |
FirstRaiserPosition |
The position of the first raiser
(big blind = 0, small blind = 1, then counter-clockwise till UTG = 9) |
First orbit preflop only |
InBigBlind | True, if you are big blind. OpenPPL is smart enpugh to detect a missing small blind (e.g. he busted in a tournament). In this case the player to the left of the dealer will be big blind. | None |
InButton | True if you are button (last to act postflop) | None |
InCutOff | True, if you are CutOff (right to the button; this position exists only, if the game is at least 4-handed, otherwise the symbol will always be false) | None |
InEarlyPosition | True, if you are in one of the early positions | None |
InEarlyPosition1 | True, if you are in EP1 (left to the big blind, right to EP2; this position exists only, if the game is at least 10-handed, otherwise the symbol will always be false) | None |
InEarlyPosition2 | True, if you are in EP2 (this position exists only, if the game is at least 9-handed, otherwise the symbol will always be false) | None |
InEarlyPosition3 | True, if you are in EP3 (this position exists only, if the game is at least 8-handed, otherwise the symbol will always be false) | None |
InLatePosition | True, if you are either CutOff or Button | None |
InMiddlePosition | True, if you are in one of the middle positions | None |
InMiddlePosition1 | True, if you are in MP1 (this position exists only, if the game is at least 7-handed, otherwise the symbol will always be false) | None |
InMiddlePosition2 | True, if you are in MP2 (this position exists only, if the game is at least 6-handed, otherwise the symbol will always be false) | None |
InMiddlePosition3 | True, if you are in MP3 (this position exists only, if the game is at least 5-handed, otherwise the symbol will always be false) | None |
InSmallBlind | True, if you are small blind | None |
InTheBlinds | True, if you are either small blind or big blind | None |
InUTG | True, if you are under the gun (left to the big blind), independent of the number of players at the table. This symbols is escpecially useful to sitout after the last hand of a session (before the next blind), but should not be used for positional play. Better use symbols like InEarlyPosition1 for selection of your starting hands. | None |
LastCallerPosition |
The position of the last caller
(big blind = 0, small blind = 1, then counter-clockwise till UTG = 9) |
First orbit preflop only |
LastRaiserPosition |
The position of the last raiser
(big blind = 0, small blind = 1, then counter-clockwise till UTG = 9) |
First orbit preflop only |
Position |
Our position relative to the other player, meant especially for postflop play. There are 3 positions at the table:
Position = First
Position = Middle
Position = Last
Middle is everything, that is neither first nor last.
|
None |
StillToAct | The number of opponents that have not yet acted in the hand when it is your turn, i.e. the players behind, including the blinds.
The Shanky-way to determine your preflop-position, but there are better symbols, e.g. InButton, etc., which can also be used in later orbits and in any betting-round.
|
While building the OpenPPL library the developers had to create lots of internal supporting functions. Most of them are so technical that they are of no use for the end-user. However some of them might be helpful for people who want to extent the OpenPPL library with their own symbols. A function like SmallBlindChair might for example be useful for the development of PokerTracker symbols like PT_SmallBlind_VPIP.
Symbol | Explanation | Remarks |
Chair0StartingStackSize … Chair9StartingStackSize | Starting stacksize of Chair N at the beginning of the hand (balance + currentbet). Measured in bets, not in dollars. | Mainly for preflop. In other betting rounds it returns the starting stack at the beginning of that round. |
BigBlindCurrentBet, SmallBlindCurrentBet | Current bets of the blind posters, measured in dollars | Mainly used to detect, if the blinds are truely raising or if they are “blind raisers”. |
ConstCardTwo … ConstCardAce | Named card constants to improve readability and maintenability. Useful if you want to access OpenHoldem’s card symbols $$pr0, $$pr1, $$cr0 … $$cr4. | None |
ConstBetRoundPreflop, ConstBetRoundFlop, ConstBetRoundTurn, ConstBetRoundRiver | Named constants for the four betting rounds. To be used with OpenHoldem’s “betround” symbol | None |
CommonCard0Paired … CommonCard4Paired | True, if the rank of common card N is equal to the rank of another common card. | Postflop only |
MaximumPossibleBetsizeIndollars | Maximum Possible bet size in dollars considering our current bet and balance | None |
PT_LastCaller_Chair | Last Caller Chair number | None |
RankOfSetOnBoard | Rank of the set on board | Valid only, if there are 3 or 4 cards of the same rank, undefined otherwise |
\strikeout off\uuline off\uwave offRankOfSpareCardWhenTwoPairOnBoard | \strikeout off\uuline off\uwave offreturns rank of the spare card when two pair on board on the river | River only |
RankOfTopPairOnBoard | returns rank of the highest pair on board (true also if set or twopair or fullhouse on board) | Postflop only |
SidePot | Pot size (in number of blinds) we are not participating in due to opponent’s bet being bigger than the sum of our balance plus currentbet. PotSize returns effective pot size because SidePot amount is subtracted from it. | None |
SidePotInDollars | Pot size (in dollars) we are not partecipating in due to opponent’s bet being bigger than the sum of our balance plus currentbet | None |
EarlyPosition1Chair … MiddlePosition3Chair, CutOffChair, ButtonChair, SmallBlindChair, BigBlindChair | Chair numbers of the specific players. Could be used e.g. for symbols like PT_SmallBlind_VPIP | None |
AggressorChair | Same meaning as ac_aggressor, but more reliable. ac_aggressor alone is somewhat unreliable, as it gets scraped (by bets). But if we raise and there are super-fast calls behind us (e.g. at PokerAcademy), then we don’t have stable frames and soon we will switch to the next betting round, so OpenHoldem might miss the aggressor. This symbol also considers our last action and the amount to call to overcome this problem. | None |
SmallBlindRaising … ButtonRaising | True, if the chair in question is betting or raising. Contrary to OpenHoldem’s conventions “blind raisers” are not counted preflop; only if they truely raise. | Meant for preflop, also working postflop, though it counts betters too. |
The sale of the program has been suspended indefinitely. The bot can be purchased here: https://t.me/pokerbot_Inhuman Dismiss
Recent Comments