7 ms·
Show HN: Allocate poker chips optimally with mixed-integer nonlinear programming
Every time I play a casual cash poker game with friends, we spend the first several minutes struggling to figure out chip denominations. I built this to automate that process.
Try it out here (the submitted link goes to the GitHub repo): https://jstrieb.github.io/poker-chipper/ https://jstrieb.github.io/poker-chipper/
It turns out that picking chip denominations optimally—such that as many chips are distributed as possible, and such that the denominations are nice—is hard (in the computational complexity sense). Upon reflection, the problem seemed to be a perfect fit for constrained optimization.
I first got a CLI prototype working with Z3 (an SMT solver with optimization capabilities https://github.com/Z3Prover/z3 https://github.com/Z3Prover/z3) in Python. Then, I cross-compiled SCIP (https://www.scipopt.org/ https://www.scipopt.org/) to web assembly, and ported my code to use SCIP instead of Z3 so it could run in the browser.
The web interface is designed to be fast and easy to use on desktop and mobile.
I would love to answer questions and discuss design choices. I'm also open to feedback and bug reports. Thanks for taking a look!
- ramon156 2y agoWe had this problem last weekend haha, very cool that someone made a tool!
- ngruhn 2y agoVery cool
- sneak 2y agoAs a professional poker player, using weirdo denominations for cash games is not something anyone ever wants. The denominations are $1, $5, $25, $100, or $5, $25, $100, $500, or $5, $25, $100, $1000. In Vegas, the $5s are almost always red, the $25s are almost always green, and the $100s are almost always black. Even the $10 chips in use for the 5/10 games at the Wynn and Resorts World throw off a lot of players. Casinos frequently have $2 chips simply because it makes dropping the rake take less volume and allows them to change the boxes less frequently. You don’t need them in a home game. This might be an interesting math problem, but let’s not pretend that it has any applications in actual poker games.
- deleted 2y ago[deleted]
- philomath_mn 2y agoI think you missed the point: OP is playing with friends and made a tool for such situations. Nobody suggested using this in a casino.
- sneak 2y agoI’m saying that poker players don’t ever want to play with nonstandard denominations, even in a home game. It’s just not done. It also makes no sense: it’s confusing and slows down the game for no reason.
- navels 2y ago[flagged]
- scarby2 2y agoin a standard casual home game i feel like we'd be playing with denominations you never see in casinos anymore anyway (5c,10c,25c,50c,$1) etc.
- memco 2y agoI’ve mostly seen chips treated as a unit-less or self referential unit: white is 1, red is 5, etc. 1 or 5 <whats> is irrelevant if you’re playing tournament style play. At the end the top x% of players get a scaling percentage of the actual monetary pool. Now if you’re playing where you can cash in and out at face value at any point then using chips in a 1:1 mapping to currency would make sense, but it should still probably be fixed rather than each chip being able to change value based on number of players or the size of the pool.
- system33- 2y agoIt would also be very annoying at home games. It would take a special group of friends to tolerate or even get a kick out of how optimally you’ve solved a self-imposed problem. It’s a fun mental exercise and programming problem, but that’s it IMO.
- opwieurposiu 2y agoSometimes when I am at the gym I wonder if there could be a better set of weight denominations. I feel like 1,3,9,27,81 could be an optimal set; but I am not sure how to prove it.
- ChadNauseam 2y agoSince every positive even integer is the sum of two primes (at least, within the range of weights you're likely to be lifting), maybe [5, ...the list of primes times 5]? So if the list of primes is 2, 3, 5, 7, 11, etc, you could have weights of 5, 25, 35, 55, 75, 11*5, etc. for 5, 10, 15, 25, 35, 55, etc.
- gpm 2y ago> So if the list of primes is 2, 3, 5, 7, 11, etc, you could have weights of 5, 2*5, 3*5, 5*5, 7*5, 11*5, etc. for 5, 10, 15, 25, 35, 55, etc. Fixed the formatting for you. You need to put a \ before * symbols to have them reliably render in HN
- latexr 2y ago> You need to put a \ before * symbols to have them reliably render in HN Alternatively, write two sequential *, like so: **
- contravariant 2y agoOptimal in what sense? If you want to have each whole number using each number at most twice then sure. If you want to get within x% using at most k weights the some kind of logarithmic distribution is also a good bet. Both you and OP could benefit from being a bit clearer about what you find optimal.
- jstrieb 2y agoSee this comment for a more in-depth explanation of what I meant by "optimal" for poker chip denominations. Hopefully that clarifies. That comment has a link to the code if it's still not clear enough. https://news.ycombinator.com/item?id=40576198 https://news.ycombinator.com/item?id=40576198
- mijoharas 2y ago> such that as many chips are distributed as possible, and such that the denominations are nice Could you expand on what the optimisation criteria are? you want each person to have the maximum number of chips for some set of "nice" denominations where the total number of chips and players are constrained? What does a "nice" set of denominations mean in this case? Why do you want to distribute a maximal number of chips?
- jstrieb 2y agoThe first constraints are the required ones: - The sum of (color value * color quantity) for all colors must equal the buy-in - For each color, (color quantity * number of players) must be less than the total number of chips of that color Theoretically any combination adhering to these constraints would be valid, but it wouldn't necessarily be "nice." The main idea behind the "niceness" constraints are to choose denominations that are easy to remember and easy to work with. To that end, there are a number of requirements and soft constraints that nudge the optimizer towards better denominations if it can. For example, a few are: - One chip value should be the small blind, and try to minimize the number of chips required to make the big blind - Chip values should try to be multiples of a set number ($0.25 by default, tunable in the UI) - Chips above $1 should be multiples of $1 - Chip values should try and be multiples of smaller chip values so that change can be made in as many ways as possible - Distribute as many chips as possible so that people have big stacks to play with The code for all of the constraints is here, and is commented in English for readability: https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0c49d074716271727564c1457f1/src/solve.js#L82 https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0...
- ramses0 2y agoThis project is great, but I'm by far not a poker nerd and seems like the answer would be something like "print out a few tables of common options / player-counts, and just pick the closest". Something like a dive-table planner (which is actually really cool if you know how to read it!): https://www.baliocean.com/blog/what-is-a-dive-table/ https://www.baliocean.com/blog/what-is-a-dive-table/ http://www.scubadiverinfo.com/images/Dive_tables_NAUI.jpg http://www.scubadiverinfo.com/images/Dive_tables_NAUI.jpg
- jvanderbot 2y ago> The SCIP solver is designed to run natively, so Poker Chipper bundles it for the browser by compiling SCIP to WebAssembly (WASM) This is amazing. I wanted to do something similar for a web-based optimization. I ended up just putting a C++ Lambda up to serve the requests. I wonder how the performance compares? I feel like optimization frameworks make use of a lot of CPU-based heuristics.
- jstrieb 2y agoSo far, even on underpowered Android phones I've tested on, the performance has been really good. It's more of a testament to how fast SCIP is than anything else! Specifically, I haven't been able to find a reasonable set of parameters that cause the optimization to take longer than ~20 seconds on the slowest device I tried. To get things to be smooth, though, I had to do debouncing and also run optimization in a web worker (separate, non-blocking thread) so the UI doesn't hang. Doing that was its own challenge since web workers don't use the HTTP cache for security reasons (they're supposed to be an isolated context), and it was re-requesting the ~5MB WASM files every time any of the numbers was adjusted. To solve this I used a service worker with a local cache. Slow performance of web-based Z3 for optimization was one of the main reasons I switched to SCIP. I originally had a version working using a WASM port of Z3, but it just wasn't fast enough to be usable.
- jvanderbot 2y agoMakes sense. SCIP has been really fast for me. Good to hear it's working for you! Did you do some local-vs-phone tests? I'm really curious how 20s on android compares to laptop.
- jstrieb 2y agoMost optimization calls on my laptop happen nearly instantaneously, whereas they can take a few seconds on average on phones. Didn't test super comprehensively. If you end up wanting to use the version of SCIP compiled to WASM, I have it pre-compiled in the repo here: https://github.com/jstrieb/poker-chipper/tree/fab41bbe8821d0c49d074716271727564c1457f1/src/compiled https://github.com/jstrieb/poker-chipper/tree/fab41bbe8821d0... To interact with WASM SCIP, I use the CLI with an Emscripten virtual filesystem (as opposed to the C API/FFI): https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0c49d074716271727564c1457f1/src/solve.js#L222-L247 https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0... If you want to compile it yourself, the code and compiler flags I used to do that are documented in a Dockerfile in the repo: https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0c49d074716271727564c1457f1/experiments/Dockerfile https://github.com/jstrieb/poker-chipper/blob/fab41bbe8821d0...
- Taghkanic 2y agoThis is bonkers. No need to overthink it. FWIW, I belong to a forum comprised mostly of game hosts who collect playable sets for their games. This group has gotten optimal breakdowns for various games (from 5¢/10¢ up to nosebleed stakes) down to a science, through actual hosting experience. The collective number of hours hosted by these members is astronomical. A standard notion is that you rarely need more than 4-6 denoms for most games, with really only 3 of those in any quantity of 100 or more for a one-table cash game. Also, that the jump between chip denominations functionally should be 4-5x the next lowest denom. So for example, a typical cash set meant to work for games ranging from 50¢/$1, $1/$2, and $2/$5 could make do with denoms of 50/1/5/25/100. For any given stakes, there is a “workhorse” denomination, and that’s the chip type you need the most of (e.g. $5 chips on 1/2 games). The only real divide among this group is those who like to use the fewest possible chips which is still comfortable, without change having to be made too often, vs. those who think poker is more fun with lots and lots of chips on the table, even if many are unnecessary. The idea of assigning non-denoms (i.e. chips with no value printed on them) all sorts of unstandard but “optimal” amounts is I suppose an interesting intellectual exercise, but in practice seems nuts. … Especially considering that chips are typically sold with existing amounts printed on them. To host with non-standard denoms requires undenominated chips used with some sort of printed or displayed key to remind players of the weird values.
- eru 2y ago> This is bonkers. No need to overthink it. Oh, overthinking can be fun!
- blackle 2y agoI've noticed that adding a colour can make it go from having a solution to not having a solution. Maybe it should try to come up with a solution using fewer colours in that case, since it's not obvious that manually removing a colour will lead to a solution.
- jstrieb 2y agoThat's a good observation - the UI is a very thin wrapper around the optimizer. One fix would be changing the minimum number of chips per color under "advanced options > requirements" to 0.
- deleted 2y ago[deleted]
- ShaggyPE 2y agoYou've solved the problem with an incorrect assumption. You have assumed that the ideal situation is to use all of the chips in your collection. A better solution is to ask, what is the most playable breakdown for the poker games I am playing. If I am playing 25c/50c no limit hold'em with 8 players... and a typical buy-in of $20 per player... as an experienced poker host at these limits, I maintain that the ideal breakdown is: 12x 25c 12x $1 1x $5 If you have a set with 100x of white, blue, red, green, etc... your total number of chips used for 8 players is: 96x white (25c) 96x blue ($1) 8x red ($5) If players lose all of their chips... they can re-buy with $5 (red) chips and make change from the players that have all of the lower denomination chips. What I have proposed above is a proper solution if you want to play poker.
- audiodude 2y agoThis comment is correct. This seems like it might have been programmed by someone who has never played poker, or not in a home game. You don't want people to have 112 white chips, no matter how many are in the box.
- Raidion 2y agoAlso an experienced poker player, and this is 100% correct. Ideally you want to use common casino chip colors (though these are somewhat fungible) and just shift orders of magnitudes. If 1BI is 20 bucks, you can make it equivalent to a $200 BI at the casino, which really only uses 2 colors 95% of the time: whites for 1 dollar, reds for $5. Deeper games might need a $25 (green) or even $100 (black chip). So whites in your home game are 10c, reds are 50c, greens are $2.50, blacks $10.
- ryandrake 2y agoAs someone who has run many, many home games, including cash and tournaments, also consider how easy it is to stack a fresh buy-in. Having 6 of one color, 5 of another, 3 of another, 8 of the next... Yuck. Many ways to make a mistake. If I'm doing a tournament where the starting small blind is 25, then I'm going to ALWAYS use: 8 qty 25 chips = 200 8 qty 100 chips = 800 4 qty 500 chips = 2000 N qty 1000 chips = N000, where N controls how much the starting stack is. When I'm preparing a bunch of new stacks, I mostly just have to deal with stacks 4 or 8 high, which can be measured next to each other in under a second. Also, the first two colors add up to 1000 exactly, and the first three colors add up to 3000 exactly, simplifying the math. Also, standard chip racks hold stacks of 20 chips, so the first three colors can be pre-built and stored in the racks. If I'm doing a cash game, with $0.25/$0.50 blinds, I use the same formula as above, but divide by 100. Just as easy. For a $1/$2 cash game, I'm going to ALWAYS use: 20 qty $1 chips = $20, for blinds N qty $5 chips for the rest of the buy-in And that's it. Since again, standard chip racks hold stacks of 20 chips, these can be set up in seconds. Later in the game, we can break out the $25 chips. Also +1 to using "standard" casino chip colors. In the US, $1 is almost always white, $5 is almost always red, $25 is almost always green, $100 is almost always black, and so on. Don't confuse people. Buy your chip set based on how you allocate your chips when playing, don't allocate your chips based on whatever chip set you happen to have.
- annoyingnoob 2y agoIn friendly poker games that I play we just make all the chips have the same value. We do a $40 buy in and you get 50 chips, each worth 80 cents. Since all of the chips have the same value we just mix all of the colors together. No one ever has to think about how the chips break down.
- shmeeed 2y agoI can't decide whether to be impressed or horrified.
- annoyingnoob 2y agoMy spreadsheet was really unpopular.
- latexr 2y agoWhat do you do when there are few players and the blinds are high? Does every player count massive amounts of chips every time?
- shmeeed 2y agoThis is nicely made, but as other people have pointed out, it appears to be optimizing in a kind of weird way for a real poker game. It seems to me that the underlying problem is that cheap pre-mixed chip cases usually have terrible denominations (if printed) and/or too few of each (sometimes only 50), which just doesn't make any sense. Nobody ever needs denominations that differ by a factor of 2, and you need way more than 50 of any one type to play with more than 6 people. For our 0.05/0.1 10$ cash games with 8-10 people, one day about 15 years ago we just went and filled a 500 chip case with nice ceramics (Old Havana Poker Club, they're still around): 150x 5 200x 25 120x 100 30x 500 (just for good measure) Obviously we take the numbers printed on the chips to be cents. This system has worked perfectly ever since and still offers sufficient flexibility for the occasional tournament; I can only recommend solving the problem this way once and for all. (Of course you need to adjust for the kind of game you play.)
- cheeze 2y agoI bought a custom set from Apache Poker Chips. We have .25, 1.00, 5.00, 25.00, 50.00, and 100.00 Covers all of our use cases. We usually do a 20 dollar buyin and do 12 .25, 12 1.00, and 1 5.00 Works well and we eventually move rebuys to 4 5.00, with players making change off of someone with lots of chips. Sometimes we flood the game with as many .25 as possible because it's fun to have a massive chip stack, but pain to count at the end. This has worked well for us in games up to 14 people (2 tables) Worth the initial investment in the chips, especially because they are thonky ceramic chips which just feel _so nice_
- pmarreck 2y agoYou should be able to pick the order of colors in terms of increasing value. White chips should always be the lowest value.
- jstrieb 2y agoThe only color reordering that happens is to assign the color with the largest quantity of chips to have the lowest chip value. Once the optimization has happened, you can edit the colors, and the order will be preserved. So if you want to swap it so that white is the lowest valued chip, just edit the color of the lowest valued chip to white.
- hot_gril 2y agoThere was a time I tried to convince everyone we should use powers of 2 as chip denominations, partially because that made it easy to handle blinds doubling. In hindsight, not a good idea.
- hot_gril 2y agoHm. Maybe powers of 4 would be fine.
- sebra 2y agoNice one! Had this problem last time we ran a tournament. I also did some constraint programming to solve my poker problems. We play mostly cash games so I did a MiniZinc model for computing the least amount of transactions after the game: https://github.com/SRautila/poker-home-game-calculator https://github.com/SRautila/poker-home-game-calculator
- ponco 2y agoCan anyone explain why this isn’t a discrete optimisation problem? I don’t understand what aspects of problem would require a non convex approach
- Dirtkingy 2y agoWould this also help new poker dealers with starting and doing games with tips and tricks that help them become a better poker dealer or is this purily for the price and buy ins of Poker games
- kyleblarson 2y agoIs there an old man coffee variable?