Open BSalita opened 2 years ago
Agreed, this should be included in the evaluate
module. I think your approach for shortage points is good, and then in the evaluate
namespace there can be various definitions for different standard ways of calculating distribution, e.g something like:
dp_shortage = [3,2,1] + [0]*10 # Counting shortages
dp_length = [0]*4 + list(range(9)) # Counting long suits
dp_mixed = [s+l for s,l in zip(dp_shortage, dp_length)] # For calculating total points
def dist_points(o: Union[SuitHolding, Hand], scale):
if isinstance(o, SuitHolding):
return scale[len(o)]
else:
return sum(dist_points(o[s]) for s in Denom.suits())
def total_points(hand: Hand, hcp_scale, dist_scale):
return hcp(hand, hcp_scale) + dist_points(hand, dist_scale)
Thoughts?
Issues:
shortage_points_trump
and shortage_points_notrump
scale?exclude
parameter which accepts a suit/list of suits would be good as this is common enoughendplay.evaluate.cccc
function which is based on the original Kaplan evaluation (without the Rubens modification) method which takes into account all of these sorts of things and a myriad of other consideration too and in my opinion provides the most accurate calculation of hand strength, so perhaps the total_points
function is not actually necessary over a simple estimation of how the high card points and distribution combine. shortage_points_notrump
perhaps should be named shortage_points_trump_fit
?I'll make the names nice and unambiguous. I think for now, I will add in the dist_points
function and a few common scales but definitely with the optional parameter so that a custom one can be defined. I'll put in the 'naïve' total points function for now but I'd like to keep the issue open to discuss a few different implementations as hand evaluation methods are definitely useful. I have a flight tomorrow so I'll put it together then and push it in the afternoon.
All good. Bon voyage.
Implementation is pushed adding dist_points and total_points. Actions is running the test suite now and then (assuming all green) will push to pypi.
The compromise I have come up with for now is a protect_honours
flag for total_points
, which discounts honours which would drop if the opponents played a suit from the top, so any K
, Qx
, Jxx
. This also includes the queen in e.g. KQ
which is not ideal but is simpler to implement.
Another option is to have a exclude_holding
parameter which contains a list of holdings which shouldn't count towards total points. The trouble with this is twofold: (a) some holdings may just be worth less, not 0 and (b) this requires some way to represent a generic small card. Its possible to add a Rank.Rx
entry to the enum --- internally each suit holding is represented by a 16-bit integer where each bit represents a different rank, so there are three spare bits to play around with. However, this might cause some unintuitive behaviour. Another option would be to have an extra parameter smallest_significant_card
or something like that, and the function would treat all cards below this as equal.
Either way, it might just be easier to define ones own my_total_points
function on a per-usecase basis rather than have a standard total_points
function which tries to solve every possible situation. I am happy to expand the evaluate
module with more functions if you come up with any evaluation methods you think might be useful.
I'd like to count points for a hand's distribution. Default would use the traditional system (1,2,3 for doubleton, singleton, void). I don't see any existing method for doing so. Surely this is a common need. What am I missing? I created some functions as a work-around.
`