Why do I think that merging Win/Tie isn't (ever) the solution
Hi mate,
I am always me. I will try to explain my issue and why I edited a piece of your code, and how and why so if you need it for your AI you can reuse it.
First of all, I edited equity.pyx (I added the bold to the changes):
cdef tuple hand_vs_range_monte_carlo(unsigned long long hand, ...): cdef unsigned int wins = 0 cdef unsigned int tie = 0
if hero > villain:
**wins += 1**
elif hero == villain:
**tie += 1**
**return <double>wins / <double>iterations, <double>tie / <double>iterations**
Let me explain, I encountered a lot of problems trying to clustering rivers combinations (hand + 5 cards) and I have tried many different solutions (your equity, machine learning tequines like k-mean, manually and a combination of all these mentioned above). The first solution was simply creating 1002 clusters (from equity 0, ..., 0.342, 0.343, ..., 0.5, ..., 0.789, ... to 1.0) but the problem was a missing of board informations. For him a board like "sssss" (a flush on the board) with no flushes in the cards of the hand was good as a middle pair. And of course that's not good. You can't cluster these two type of hands because are too different (AI was really weak with that type of clustering), but if you offer him the percentage of tie he can detect better a lot of board patterns.
My post isn't a issue, it was only a discussion to have a comparison and get more ideas.
And thank you for all
I think you're probably right that exposing the tie percentage is valuable.
I do think having a function that just returns raw equity is valuable though, and I'm a little concerned that tuple creation might come with overhead that hurts performance meaningfully for someone calling the function in a hot loop.
The right thing to do here is to create a new function that returns the tuple, then try calling that from hand_vs_range_monte_carlo, and benchmarking the performance to see if the cost is substantial. If it is, there's surely a way to have a Cython function return a pair of values without all the PyObject overhead, and write a function that does that, then write two functions that call it - one that returns just equity, and the other that returns the (win, tie) tuple.
I might get around to doing that at some point, but I don't see myself getting to it any time soon, so if you're interested in having a go, PRs are welcome!
I do think having a function that just returns raw equity is valuable though
Yes of coure, I have the same opinion. Any variable that can do some sort of information can be valuable.
import time
import eval7 as e7
import eval8 as e8
from eval7 import py_hand_vs_range_monte_carlo as rmc7
from eval8 import py_hand_vs_range_monte_carlo as rmc8
from nlh import ranges
FULL_RANGE = e7.HandRange(ranges.FULL_RANGE)
def benchmark(handle, hand, board):
t = time.time()
handle(hand, FULL_RANGE, board, 10000)
return time.time() - t
bench7 = bench8 = 0
for i in range(1000000):
deck = e7.Deck()
deck.shuffle()
hand = deck.deal(2)
board = deck.deal(5)
bench7 += benchmark(rmc7, hand, board)
bench8 += benchmark(rmc8, hand, board)
print("bench7:", bench7)
print("bench8:", bench8)
bench7: 904.8087770938873 bench8: 902.0578112602234
Bench8 uses the tuple. There are no differences. When I have a little bit of time I will try to reimplement elegantly the code (I'm not really good with cython) for two different functions.