A texas holdem simulator build with WebAssembly and web workers
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Build Status

holdem is a heads-up (2 player) Texas Hold'em simulator for hand ranges. It allows you to quickly calculate the total equity of your hand vs. a range of opponent hands. The simulations are calculated using C++ via WebAssembly using up to 8 web workers in parallel. This is pretty bare bones as far as range evaluators go, and there are many improvements I would like to make if I hade more time, see below.





make wasm

Calling make will place the compiled wasm and a javascript "glue" file into the /build directory. You can then include those files on a webserver and just open the index.html page to get up and running.


  • Why did you make this?

    I put this together as a weekend project to learn more about WebAssembly.

  • What's a simulation?

    A simulation plays a hand out as if the players are all in and no action is left. For example, if the board only has 3 cards (flop) and you run the simulation, the board will complete (turn and river) for every possible combination of hands in the oppoopenet range vs. the hero hand.

  • What does this use to compile to wasm?


  • Why don't you use the --proxy-to-worker option from emscripten?

    I tried using this flag, but the .js file it produced was quite large and I could not get the message passing to work to the main thread.

  • Why doesn't this use a faster library for hand comparisons?

    There are many great options for an extrememly fast 7-card hand evaluator, but they all come with a large pre-computed table. Using a pre-computed table of values requires a large download (~100mb) before the app can be run, is not a great option for a web facing product. The speed difference between the library used in this app and other more well known libraries is not significant enough to justify the huge table downloads.

  • How many simulations can this run?

    Depends on the system architecture, but with 8 workers it should run about 20 million simulations a second.

  • What browsers does this work on?

    So far, I've tested on the following browsers

    • FireFox 57 (Mac OS 10, Ubuntu 16.04, Windows 10)
    • Chrome 61 (Mac OS 10, Windows 10, Android 6)
    • Safari 11 (Mac OS 10)
    • Microsoft Edge 16 (Windows 10)


make tests


This was a weekend project for me, and as such a lot of corners were cut. If I had more time I would go back and improve a lot of things.

  • Faster card selector (remove select drop downs)

  • Better way to select multiple ranges (click & drag to highlight multiple cells)

  • Would like to add a lib like react to handle the state changes, and remove all the event listeners everywhere

  • Use SIDE_MODULE to load wasm as side module

  • Loading the wasm is currently not optimal, a much better apprach would be to compile the wasmm and pass the bytes into the worker, something like this

       fetch('go.wasm').then(response =>
       ).then(bytes =>
       ).then(mod => {
  • As far as I know, WASM does not support pthreads (although there seem to be some emccflgas realted to it) but it would be nice if theC++` futures async library could be used as a possible replacement for web workers. The simulation code could then be changed to something like this:

      std::vector<std::future<int>> futures;
      for (int i = 0; i < COMBOS; i+=1) {
        futures.push_back (std::async([]() {
          // Run the simulation loop in new thread for each hand combination
        } , heroCards[0], ...));
      for(auto &e : futures) std::cout << e.get() << std::endl;
  • better data transfering between workers, use of sharedArray