diff --git a/install/assemble.cmd b/install/assemble.cmd index 5761d121..e389269e 100644 --- a/install/assemble.cmd +++ b/install/assemble.cmd @@ -19,4 +19,6 @@ robocopy dist\BENGUI "BENAll" /E robocopy dist\BEN "BENAll" /E robocopy dist\table_manager_client "BENAll" /E robocopy ..\src\nn "BENAll\nn" *tf2.py* -robocopy ..\bin "BENAll\bin" /E \ No newline at end of file +robocopy ..\bin "BENAll\bin" /E +copy ..\src\ben.ico "BENAll" +copy ..\src\logo.png "BENAll" \ No newline at end of file diff --git a/src/bba/BBA.py b/src/bba/BBA.py index eb13627f..b4f949f9 100644 --- a/src/bba/BBA.py +++ b/src/bba/BBA.py @@ -2,7 +2,7 @@ import sys import os import util - +from threading import Lock # Get the directory of the current script script_dir = os.path.dirname(os.path.abspath(__file__)) # Calculate the parent directory @@ -34,6 +34,34 @@ class BBABotBid: + _dll_loaded = None # Class-level attribute to store the DLL singleton + _lock = Lock() # Lock to ensure thread-safe initialization + + @classmethod + def get_dll(cls, verbose = False): + """Access the loaded DLL classes.""" + if cls._dll_loaded is None: + with cls._lock: # Ensure only one thread can enter this block at a time + if cls._dll_loaded is None: # Double-checked locking + try: + util.load_dotnet_framework_assembly(EPBot_PATH, verbose) + from EPBot86 import EPBot + # Load the .NET assembly and import the types and classes from the assembly + if verbose: + print(f"EPBot Version (DLL): {EPBot().version()}") + cls._dll_loaded = { + "EPBot": EPBot, + } + except Exception as ex: + # Provide a message to the user if the assembly is not found + print(f"{Fore.RED}Error: Unable to load EPBot86.dll. Make sure the DLL is in the ./bin directory") + print("Make sure the dll is not blocked by OS (Select properties and click unblock)") + print(f"Make sure the dll is not writeprotected{Fore.RESET}") + print('Error:', ex) + sys.exit(1) + return cls._dll_loaded + + # Define constants for system types and conventions C_NS = 0 C_WE = 1 @@ -45,21 +73,10 @@ class BBABotBid: def __init__(self, ns_system, ew_system, position, hand, vuln, dealer, scoring_matchpoint, verbose): + dll = BBABotBid.get_dll(verbose) # Retrieve the loaded DLL classes through the singleton + EPBot = dll["EPBot"] self.verbose = verbose # Load the .NET assembly - try: - util.load_dotnet_framework_assembly(EPBot_PATH, verbose) - from EPBot86 import EPBot - # Load the .NET assembly and import the types and classes from the assembly - if self.verbose: - print(f"EPBot Version (DLL): {EPBot().version()}") - except Exception as ex: - # Provide a message to the user if the assembly is not found - print(f"{Fore.RED}Error: Unable to load EPBot86.dll. Make sure the DLL is in the ./bin directory") - print("Make sure the dll is not blocked by OS (Select properties and click unblock)") - print(f"Make sure the dll is not writeprotected{Fore.RESET}") - print('Error:', ex) - sys.exit(1) if ew_system == None and ns_system == None: return if ew_system == '-1' or ns_system == '-1': diff --git a/src/bots.py b/src/bots.py index 360606eb..335f1464 100644 --- a/src/bots.py +++ b/src/bots.py @@ -97,9 +97,8 @@ def get_binary_contract(self, position, vuln, hand_str, dummy_str, n_cards=32): def evaluate_rescue_bid(self, auction, passout, samples, candidate_bid, quality, my_bid_no ): # check configuration if self.verbose: - print("Checking if we should evaluate rescue bid", self.models.check_final_contract, len(samples)) - print("Auction",auction, passout) - print("Candidate", candidate_bid, quality) + print("Checking if we should evaluate rescue bid", self.models.check_final_contract, "Samples:",len(samples)) + print("Auction",auction, "Passout?" ,passout,"Candidate bid", candidate_bid.bid, "Sample quality: ",quality) if not self.models.check_final_contract: return False @@ -138,7 +137,7 @@ def evaluate_rescue_bid(self, auction, passout, samples, candidate_bid, quality, return True if candidate_bid.expected_score is None: - # We will prepare data for calculating recue bid + # We will prepare data for calculating rescue bid return True # We only evaluate if the score is below a certain value, so if simulation give a score above this we do not try to rescue @@ -231,7 +230,7 @@ def bid(self, auction): hands_np_as_pbn = self.translate_hands(hands_np, self.hand_str, sample_count) for candidate in candidates: if self.verbose: - print(f" {candidate.bid.ljust(4)} {candidate.insta_score:.3f} Samples: {len(hands_np)}") + print(f"Bid: {candidate.bid.ljust(4)} {candidate.insta_score:.3f}") auctions_np = self.bidding_rollout(auction, candidate.bid, hands_np) t_start = time.time() @@ -269,9 +268,9 @@ def bid(self, auction): # Format the average tricks string average_tricks_str = ", ".join(map(str, average_tricks)) - samples[idx] += f" \n {auc} ({average_tricks_str}) " + samples[idx] += f" | {auc} ({average_tricks_str}) " else: - samples[idx] += f" \n {auc}" + samples[idx] += f" | {auc}" if self.verbose: print("tricks", np.mean(decoded_tricks)) @@ -499,7 +498,7 @@ def bid(self, auction): result = {} for i in range(len(contracts[0])): # We should make calculations on this, so 4H, %h or even 6H is added, if tricks are fin - if contracts[0][i] > 0.3: + if contracts[0][i] > 0.2: y = np.zeros(5) suit = bidding.ID2BID[i][1] strain_i = 'NSHDC'.index(suit) @@ -532,15 +531,19 @@ def bid(self, auction): contract = bidding.ID2BID[contract_id] - if self.verbose: - print(result) if score < self.models.min_bidding_trust_for_sample_when_rescue: - if self.verbose: - print(self.hand_str, [sample[(self.seat + 2) % 4]]) - print(f"Skipping sample below level{self.models.min_bidding_trust_for_sample_when_rescue} {contract}-{tricks} score {score:.3f}") + #if self.verbose: + # print(self.hand_str, [sample[(self.seat + 2) % 4]]) + # if score == 0: + # print(f"No obvious rescue contract") + # else: + # print(f"Skipping sample below level: {self.models.min_bidding_trust_for_sample_when_rescue} {contract} {tricks} score {score:.3f}") continue + if self.verbose: + print(result) + while not bidding.can_bid(contract, auction) and contract_id < 35: contract_id += 5 contract = bidding.ID2BID[contract_id] @@ -587,8 +590,8 @@ def bid(self, auction): # If we go down we assume we are doubled doubled = tricks < level + 6 score = scoring.score(contract + ("X" if doubled else ""), self.vuln, tricks) - if self.verbose: - print(result, score) + #if self.verbose: + # print(result, score) if contract not in alternatives: alternatives[contract] = [] alternatives[contract].append({"score": score, "tricks": tricks}) @@ -1283,7 +1286,7 @@ def find_opening_lead(self, auction): opening_lead = candidate_cards[0].card.code() if self.verbose: - print("Samples quality:", quality) + print(f"Samples quality: {quality:.3f}") for card in candidate_cards: print(card) if opening_lead % 8 == 7: @@ -1427,7 +1430,7 @@ def double_dummy_estimates(self, lead_card_indexes, contract, accepted_samples): if (k != 3): hand_str += '.' if self.verbose: - print("Opening lead being examined: ", Card.from_code(opening_lead52), n_accepted) + print("Opening lead being examined: ", Card.from_code(opening_lead52), n_accepted, end="") t_start = time.time() hands_pbn = [] for i in range(n_accepted): @@ -1702,7 +1705,7 @@ def play_card(self, trick_i, leader_i, current_trick52, tricks52, players_states pimc_resp_cards = self.pimc.nextplay(self.player_i, shown_out_suits, self.missing_cards) if self.verbose: print("PIMCDef result:") - print("\n".join(f"{Card.from_code(k)}:\n{v}" for k, v in pimc_resp_cards.items())) + print("\n".join(f"{Card.from_code(k)}: {v}" for k, v in pimc_resp_cards.items())) assert pimc_resp_cards is not None, "PIMCDef result is None" if self.models.pimc_ben_dd_defending: @@ -1938,7 +1941,6 @@ def pick_card_after_pimc_eval(self, trick_i, leader_i, current_trick, tricks52, msg=msg + (f"|trump adjust={trump_adjust}" if trump_adjust != 0 and (card32 // 8) + 1 == self.strain_i else "") )) - if self.models.use_real_imp_or_mp: if self.models.matchpoint: candidate_cards = sorted(enumerate(candidate_cards), key=lambda x: (x[1].expected_score_mp, x[1].expected_tricks_dd, x[1].insta_score, -x[0]), reverse=True) @@ -1954,7 +1956,7 @@ def pick_card_after_pimc_eval(self, trick_i, leader_i, current_trick, tricks52, if self.verbose: for i in range(len(candidate_cards)): - print(candidate_cards[i].card, f"{candidate_cards[i].insta_score}:.3f", candidate_cards[i].expected_tricks_dd, round(5*candidate_cards[i].p_make_contract, 1), candidate_cards[i].expected_score_dd, int(candidate_cards[i].expected_tricks_dd * 10) / 10) + print(candidate_cards[i].card, f"{candidate_cards[i].insta_score:.3f}", candidate_cards[i].expected_tricks_dd, round(5 * candidate_cards[i].p_make_contract, 1), int(candidate_cards[i].expected_tricks_dd * 10) / 10) if self.models.matchpoint: if self.models.pimc_ben_dd_declaring or self.models.pimc_ben_dd_defending: diff --git a/src/carding.py b/src/carding.py index 8648da16..3a022ddf 100644 --- a/src/carding.py +++ b/src/carding.py @@ -165,7 +165,8 @@ def select_right_card_for_play(candidate_cards, rng, contract, models, hand_str, #print("Tricks", play['Plays'][0]['Tricks'], " Max: ",max(len(suits_north),len(suits_south))) if play['Plays'][0]['Tricks'] == max(len(suits_north),len(suits_south)): if play['Plays'][0]['Percentage'] == 100: - print(f"SuitC dropped as we can take all tricks {current_count} {original_count} ") + if verbose: + print(f"SuitC dropped as we can take all tricks {current_count} {original_count} ") return candidate_cards[0].card, who # We can have more than one play for MAX # So currently we are then selecting lowest card. Should that be different diff --git a/src/config/default.conf b/src/config/default.conf index 91602335..7c53cae6 100644 --- a/src/config/default.conf +++ b/src/config/default.conf @@ -1,5 +1,5 @@ [models] -name = GIB as on BBO +name = BEN Sayc # Model version 1 drops state for bidding, and introduce different system for NS and EW # Model version 2 includes 4 bids when making the lookup model_version = 3 @@ -19,8 +19,8 @@ use_bba = False # Instead of the neural network, check BBA if it is RKC and get the correct bid from BBA use_bba_to_count_aces = True # Use 2/1 in BBA -bba_ns = BBA/CC/GIB-BBO.bbsa -bba_ew = BBA/CC/GIB-BBO.bbsa +bba_ns = BBA/CC/BEN-SAYC.bbsa +bba_ew = BBA/CC/BEN-SAYC.bbsa # Playing matchpoint? Otherwise it is teams matchpoint = False # Do not print warnings about bad models, training etc in the output @@ -31,10 +31,10 @@ contract = models/TF2models/Contract_2024-12-09-E50.keras trick = models/TF2models/Tricks_2024-12-09-E50.keras [bidding] -bidder = models/TF2models/GIB-BBO-8712_2024-12-01-E44.keras +bidder = models/TF2models/BEN-Sayc-8712_2024-11-29-E49.keras # only used for sampling -opponent = models/TF2models/GIB-BBO-8712_2024-12-01-E44.keras -info = models/TF2models/GIB-BBOInfo-8712_2024-11-30-E50.keras +opponent = models/TF2models/BEN-Sayc-8712_2024-11-29-E49.keras +info = models/TF2models/BEN-SaycInfo-8712_2024-11-29-E71.keras # If there are multiple bids over this threshold make a simulation for the bids, using an array we can lower the trust the more we bid search_threshold = [0.10, 0.07, 0.06, 0.05, 0.04, 0.03, 0.03] # If there is bid above this threshold, make that bid ignoring other bids @@ -189,7 +189,7 @@ pimc_constraints_each_trick = True # Stop evaluation after finding the number of playouts unless pimc_wait expires before pimc_max_playouts = 200 # Max number of threads PIMC is allowed to use -pimc_max_threads = 6 +pimc_max_threads = 12 # If singleton, just play it without evaluating it autoplaysingleton = True # PIMC trust NN. We can filter away play, that is not suggested by the neural network diff --git a/src/config/default_tf2.conf b/src/config/default_tf2.conf index 3460888b..b1ac49f6 100644 --- a/src/config/default_tf2.conf +++ b/src/config/default_tf2.conf @@ -1,41 +1,53 @@ [models] -name = default (GIB) +name = BEN Sayc # Model version 1 drops state for bidding, and introduce different system for NS and EW # Model version 2 includes 4 bids when making the lookup model_version = 3 +# Small cards (pips) are grouped, so when bidding we have AKQJTx +n_cards_bidding = 24 +# During play we have AKQJT98x +n_cards_play = 32 + # Version of tensorflow to use tf_version = 2 -# Same model for both sides +# Same system for both sides NS = 1 EW = 1 # If using BBA the following NS and EW must match BBA's systems (0 =2/1, 1=SAYC, 2=WJ, 3=PC, 4=Acol) use_bba = False +# Instead of the neural network, check BBA if it is RKC and get the correct bid from BBA +use_bba_to_count_aces = True # Use 2/1 in BBA bba_ns = BBA/CC/BEN-21GF.bbsa bba_ew = BBA/CC/BEN-21GF.bbsa # Playing matchpoint? Otherwise it is teams matchpoint = False +# Do not print warnings about bad models, training etc in the output +suppress_warnings = True [contract] contract = models/TF2models/Contract_2024-12-09-E50.keras trick = models/TF2models/Tricks_2024-12-09-E50.keras - [bidding] -bidder = models/TF2models/GIB_2024-08-26-E50.keras -opponent = models/TF2models/GIB_2024-08-26-E50.keras -info = models/TF2models/GIB-Info_2024-07-18-E50.keras -# If there are multiple bids over this threshold make a simulation for the bids -search_threshold = 0.07 +bidder = models/TF2models/BEN-21GF-8712_2024-11-29-E48.keras +# only used for sampling +opponent = models/TF2models/BEN-21GF-8712_2024-11-29-E48.keras +info = models/TF2models/BEN-21GFInfo-8712_2024-11-29-E71.keras +# If there are multiple bids over this threshold make a simulation for the bids, using an array we can lower the trust the more we bid +search_threshold = [0.10, 0.07, 0.06, 0.05, 0.04, 0.03, 0.03] # If there is bid above this threshold, make that bid ignoring other bids no_search_threshold = 1 # Evaluate min_passout_candidates bids if auction longer than this. Setting to -1 will disable -eval_after_bid_count = 12 +# Disabled with a descending search_threshold +eval_after_bid_count = -1 # If False the opening bid will be without simulation, even with multiple candidates -eval_opening_bid = False +# With relatively high trust for first bid, this should be OK +eval_opening_bid = True # Add Pass as a bid to evaluate after this number of bids -eval_pass_after_bid_count = 12 +# Disabled when we have rescue bid activated +eval_pass_after_bid_count = -1 # Minimum number of candidates examined in the passout situation min_passout_candidates = 2 # Use bidding quality in evaluation (if not good just use neural network) @@ -52,15 +64,19 @@ max_samples_checked = 20 min_rescue_reward = 250 # Max expected score to evaluate rescue bid max_estimated_score = 300 +# If samples has bidding below this we will not use it for rescue bid +min_bidding_trust_for_sample_when_rescue = 0.55 # Alert implemented in bidding model -alert_supported = True +alert_supported = False +# We only alert if we are pretty sure +alert_threshold = 0.8 [adjustments] # Are adjustments enabled use_adjustment = True # Add extra weigth on scores from neural network # The score from NN is multiplied to this and added to expected score -adjust_NN = 50 +adjust_NN = 60 # If it was difficult to find samples we increase the trust in the NN adjust_NN_Few_Samples = 100 # subtract this from expected score before XX (Double if vulnerable) @@ -68,6 +84,8 @@ adjust_XX = 200 # Subtract this from expected score before double in passout situation # If not going 2 down, the adjustment is doubled adjust_X = 100 +# When doubling in passout situation remove xx% the best boards, due to bad samples +adjust_X_remove = 25 # When bidding in the passout situation, we change the expected score adjust_passout = -100 # When bidding in the passout and going negative, assume we are being doubled, so multiply the score by this @@ -78,6 +96,9 @@ adjust_min1 = 0.002 adjust_min2 = 0.0002 adjust_min1_by = 200 adjust_min2_by = 200 +# Adjustment above is in points, so we need to translate it to some kind of MP or Imp +factor_to_translate_to_mp = 10 +factor_to_translate_to_imp = 25 [lead] # Neural network for suggesting opening lead @@ -94,16 +115,20 @@ min_opening_leads = 4 # Opening lead agreement (random, attitude, 135 or 24) lead_from_pips_nt = 24 lead_from_pips_suit = 135 +# use real calcualtion or just tricks +use_real_imp_or_mp_opening_lead = True [eval] # Model for finding single dummy estimates provided an opening lead single_dummy_estimator = models/TF2models/SD_2024-07-08-E20.keras # Model for finding single dummy estimates without opening lead double_dummy_estimator = models/TF2models/RPDD_2024-07-08-E02.keras -# use the following estimator, sde, dde or both -estimator = dde -# Use double dummy when estimating tricks during bidding - to slow if 200 samples +# use the following estimator, sde, dde, both or none. If both dde will be preferred +estimator = none +# Use double dummy when estimating tricks during bidding - to slow if 200 samples - higher priority than the above estimators double_dummy_calculator = True +# use real calculation or just tricks - this is only working for double dummy calculator due to performance +use_real_imp_or_mp_bidding = True [cardplay] # This is telling if opening lead is included in the neural net for lefty @@ -119,87 +144,134 @@ decl_suit = models/TF2models/decl_suit_2024-07-08-E20.keras # Number of samples when playing the hand sample_hands_play = 200 # Minimum number of boards we want returned for sampling during play -min_sample_hands_play = 10 +min_sample_hands_play = 20 # Minimum number of boards we want returned for sampling during play min_sample_hands_play_bad = 12 # Number of samples we will generate to find sample_hands_play sample_boards_for_play = 5000 # Should possible claim be calculated claim = True -# Use bidding info during play +# Use bidding info for sampling during play and bidding +# Setting this to false will require a higher number of generated deals use_biddinginfo = True # Use bidding quality in evaluation, if bad samples, just use neural network use_biddingquality_in_eval = True # Use SuitC to find the card for single suit combinations use_suitc = True # Only check trump in suit contracts (and all suits in NT) -suitc_sidesuit_check = False +suitc_sidesuit_check = True +# Use real IMP or MP when finding the play - original version used average tricks +use_real_imp_or_mp = True # Drawing trump, reward is given if opponents has trump, penalty if not # The reward is low as it is only useable if more cards with the same score draw_trump_reward = 0.05 draw_trump_penalty = 0.1 +# We can filter away play, that is not suggested by the neural network. +trust_NN = 0.0 [pimc] -# Are we using PIMC as declarer or defender? +# Setting this to false will suppress output from PIMC, if true it will follow the global defintion of verbose +pimc_verbose = False +# Are we using PIMC as declarer and/or defender? pimc_use_declaring = True +pimc_use_fusion_strategy = False pimc_use_defending = True # Max wait time for results from PIMC in seconds pimc_wait = 3 -# When should PIMC kick in -pimc_start_trick_declarer = 3 -pimc_start_trick_defender = 6 +# When should PIMC kick in. PIMC is best with few cards unknown, but is used as a second opinion to BENs Double dummy +pimc_start_trick_declarer = 1 +pimc_start_trick_defender = 1 # Extract hcp from samples and use as input to PIMC pimc_constraints = True # On every trick create new constraints based on samples. If false only do it, when PIMC kicks in # The API is stateless and will establish constraints at each trick -pimc_constraints_each_trick = False +pimc_constraints_each_trick = True # Stop evaluation after finding the number of playouts unless pimc_wait expires before -pimc_max_playouts = 400 +pimc_max_playouts = 200 # Max number of threads PIMC is allowed to use -pimc_max_threads = 6 +pimc_max_threads = 12 # If singleton, just play it without evaluating it autoplaysingleton = True -# PIMC trust NN +# PIMC trust NN. We can filter away play, that is not suggested by the neural network pimc_trust_NN = 0.00 # Combine with BEN double dummy -pimc_ben_dd_declaring = False -pimc_ben_dd_defending = False +pimc_ben_dd_declaring = True +pimc_ben_dd_defending = True +# When merging results we can trust one side more. Default is 0.5. The weight is for PIMC, so the higher the more trust in PIMC +# If bidding quality is below the threshold, we will switch trust between BEN and PIMC, as BENs samples do not match the bidding. + +pimc_bidding_quality = 0.1 +pimc_ben_dd_declaring_weight = 0.3 +pimc_ben_dd_defending_weight = 0.3 # Use a priori probabilities -pimc_apriori_probability = True +# Setting this to true will send all played card to PIMC. that will give weight to each sample, when creating average tricks +# and when calculating chance for making/defeating the contract +pimc_apriori_probability = False +# These margins are added before calling OIMC to be sure we get some deals, that does not match the bidding entirely +pimc_margin_suit = 1 +pimc_margin_hcp = 3 +pimc_margin_suit_bad_samples = 2 +pimc_margin_hcp_bad_samples = 5 + [sampling] # When sampling we use bidding_info as a guide, and these control how to adjust bidding_info after a card given to a hand -# Multiplied to the hcp-value of the card +# Multiplied to the hcp-value of the card, the higher value there more the samples will have the average hcp's +# This can be disable by setting use_biddinginfo to false hcp_reduction_factor = 0.83 # when a card is given subtract this from the shape, to reduce odds it get more in that suit -shp_reduction_factor = 0.5 +shp_reduction_factor = 0.3 # If bid selected directly by Neural net, then save time dropping generating samples -no_samples_when_no_search = False +no_samples_when_no_search = True # Filter to remove hands, where the opening lead was not suggested by the neural network -# Can be disabled by setting it to zero -lead_accept_threshold = 0.03 -# If we play with our normal partner we can add som trust to the lead +# setting the following to false is the default behavior from a 32 card deck +# lead_accept_threshold_suit will sum all lead, including honors, for each suit and check the suit lead, adding up the score +lead_accept_threshold_suit = False +# lead_accept_threshold_honors will switch to the 24 deck suit, when validating the lead +# if following lead conventions like 2nd from 3 this should be enabled +lead_accept_threshold_honors = True +# Can be disabled by setting it to zero. This is a filter, so we keep ot low, as any lead can be possible +lead_accept_threshold = 0.10 +# Alternative is +# if following lead conventions like 2nd from 3 this should be enabled +# lead_accept_threshold_honors = False +# Can be disabled by setting it to zero. This is a filter, so we keep ot low, as any lead can be possible +# lead_accept_threshold = 0.01 + +# If we play with our normal partner we can add some trust to the lead # Setting it to high will reduce the samples and thus getting bad samples -lead_accept_threshold_partner_trust = 0.05 +lead_accept_threshold_partner_trust = 0.10 + # Filter to remove hands, where we do not trust the bidding. Used when sampling hands during bidding #use_distance = False #bidding_threshold_sampling = 0.25 #bid_accept_threshold_bidding = 0.20 +#bid_accept_play_threshold = 0.4 # This is calculated using euclidian distance, so 0.33 could be one of the 3 bids in a bidding round matching use_distance = True bidding_threshold_sampling = 0.70 +# If not finding enough samples above bidding_threshold_sampling we extend to this, until we get min_sample_hands_auction bid_accept_threshold_bidding = 0.40 # Filter to remove hands not consistent with the bidding. Used during play -bid_accept_play_threshold = 0.04 +bid_accept_play_threshold = 0.40 -# Filter to remove hands, where the play is inconsistent with the sample +# Filter to remove hands, where the play is inconsistent with the sample. Setting it to zero will remove the validation +# This is difficult, as setting it to low will include boards where BEN not will repeat a finesse, but setting it to high might reduce useable samples +# Also important to notice, this is not used for PIMC as defender or declarer play_accept_threshold = 0.02 +min_play_accept_threshold_samples = 10 # If we dont find enough samples, then include down to this threshold. Used during play bid_extend_play_threshold = 0.10 # Number hands where we will calculate scores for when bidding sample_hands_auction = 200 -# The number of hands we will generate to find sample_hands_auction -sample_boards_for_auction = 5000 +# The number of hands we will generate to find sample_hands_auction. Estimated cost pr. sample is 4ms +# This is now a max as we generate blocks of sample_boards_for_auction_step hands +sample_boards_for_auction = 20000 +sample_boards_for_auction_step = 1000 +# After each real bid we add 50% to the max samples. setting to zero disables +increase_for_bid_count = 6 +# If samples below this threshold print a warning in the log +warn_to_few_samples = 10 # Minimum number of hands when caclulating scores in the bidding min_sample_hands_auction = 10 # If we dont find enough samples, then include down to this threshold. Used during bidding @@ -211,4 +283,6 @@ sample_hands_opening_lead = 200 # Max number of samples to include when reviewing a board sample_hands_for_review = 20 # If probability for a bid is below this, then drop the sample -exclude_samples = 0.01 +exclude_samples = 0.005 +# Skip last bidding round to find samples, if we did not find the minimum needed. We will only try to find 25% samples +sample_previous_round_if_needed = True diff --git a/src/config/default_tf2_nosearch.conf b/src/config/default_tf2_nosearch.conf new file mode 100644 index 00000000..1d0f6b67 --- /dev/null +++ b/src/config/default_tf2_nosearch.conf @@ -0,0 +1,288 @@ +[models] +name = BEN Sayc +# Model version 1 drops state for bidding, and introduce different system for NS and EW +# Model version 2 includes 4 bids when making the lookup +model_version = 3 + +# Small cards (pips) are grouped, so when bidding we have AKQJTx +n_cards_bidding = 24 +# During play we have AKQJT98x +n_cards_play = 32 + +# Version of tensorflow to use +tf_version = 2 +# Same system for both sides +NS = 1 +EW = 1 +# If using BBA the following NS and EW must match BBA's systems (0 =2/1, 1=SAYC, 2=WJ, 3=PC, 4=Acol) +use_bba = False +# Instead of the neural network, check BBA if it is RKC and get the correct bid from BBA +use_bba_to_count_aces = False +# Use 2/1 in BBA +bba_ns = BBA/CC/BEN-21GF.bbsa +bba_ew = BBA/CC/BEN-21GF.bbsa +# Playing matchpoint? Otherwise it is teams +matchpoint = False +# Do not print warnings about bad models, training etc in the output +suppress_warnings = True + +[contract] +contract = models/TF2models/Contract_2024-12-09-E50.keras +trick = models/TF2models/Tricks_2024-12-09-E50.keras + +[bidding] +bidder = models/TF2models/BEN-21GF-8712_2024-11-29-E48.keras +# only used for sampling +opponent = models/TF2models/BEN-21GF-8712_2024-11-29-E48.keras +info = models/TF2models/BEN-21GFInfo-8712_2024-11-29-E71.keras +# If there are multiple bids over this threshold make a simulation for the bids, using an array we can lower the trust the more we bid +search_threshold = -1 +# If there is bid above this threshold, make that bid ignoring other bids +no_search_threshold = 1 +# Evaluate min_passout_candidates bids if auction longer than this. Setting to -1 will disable +# Disabled with a descending search_threshold +eval_after_bid_count = -1 +# If False the opening bid will be without simulation, even with multiple candidates +# With relatively high trust for first bid, this should be OK +eval_opening_bid = True +# Add Pass as a bid to evaluate after this number of bids +# Disabled when we have rescue bid activated +eval_pass_after_bid_count = -1 +# Minimum number of candidates examined in the passout situation +min_passout_candidates = 2 +# Use bidding quality in evaluation (if not good just use neural network) +use_biddingquality = True +# For very long bidding sequnces we can't find decent samples, so do not make quality check +no_biddingquality_after_bid_count = 12 +# Upvote the samples that matches the bidding best - used when double dummy results are calculated during play +use_probability = True +# Before the final pass validate the contract with a neural network +check_final_contract = False +# How many samples checked +max_samples_checked = 20 +# Minimum gain for making a rescue bid +min_rescue_reward = 250 +# Max expected score to evaluate rescue bid +max_estimated_score = 300 +# If samples has bidding below this we will not use it for rescue bid +min_bidding_trust_for_sample_when_rescue = 0.55 +# Alert implemented in bidding model +alert_supported = False +# We only alert if we are pretty sure +alert_threshold = 0.8 + +[adjustments] +# Are adjustments enabled +use_adjustment = True +# Add extra weigth on scores from neural network +# The score from NN is multiplied to this and added to expected score +adjust_NN = 60 +# If it was difficult to find samples we increase the trust in the NN +adjust_NN_Few_Samples = 100 +# subtract this from expected score before XX (Double if vulnerable) +adjust_XX = 200 +# Subtract this from expected score before double in passout situation +# If not going 2 down, the adjustment is doubled +adjust_X = 100 +# When doubling in passout situation remove xx% the best boards, due to bad samples +adjust_X_remove = 25 +# When bidding in the passout situation, we change the expected score +adjust_passout = -100 +# When bidding in the passout and going negative, assume we are being doubled, so multiply the score by this +adjust_passout_negative = 3 +# If we get some very low scores from the NN, then adjust by this +# Both will be tested, so a very low score will get both adjustments +adjust_min1 = 0.002 +adjust_min2 = 0.0002 +adjust_min1_by = 200 +adjust_min2_by = 200 +# Adjustment above is in points, so we need to translate it to some kind of MP or Imp +factor_to_translate_to_mp = 10 +factor_to_translate_to_imp = 25 + +[lead] +# Neural network for suggesting opening lead +lead_suit = models/TF2models/Lead-Suit_2024-11-04-E200.keras +lead_nt = models/TF2models/Lead-NT_2024-11-04-E200.keras +# Ignore cards as opening lead below this value from the neural network +lead_threshold = 0.20 +# Lead this card suggested by neural network if prediction is over this value +lead_accept_nn = 0.999 +# Use double dummy statistics when evaluating the opening lead - default is single dummy +double_dummy = True +# Force a minimum number of leads to consider - overrides lead_threshold +min_opening_leads = 4 +# Opening lead agreement (random, attitude, 135 or 24) +lead_from_pips_nt = 24 +lead_from_pips_suit = 135 +# use real calcualtion or just tricks +use_real_imp_or_mp_opening_lead = True + +[eval] +# Model for finding single dummy estimates provided an opening lead +single_dummy_estimator = models/TF2models/SD_2024-07-08-E20.keras +# Model for finding single dummy estimates without opening lead +double_dummy_estimator = models/TF2models/RPDD_2024-07-08-E02.keras +# use the following estimator, sde, dde, both or none. If both dde will be preferred +estimator = none +# Use double dummy when estimating tricks during bidding - to slow if 200 samples - higher priority than the above estimators +double_dummy_calculator = True +# use real calculation or just tricks - this is only working for double dummy calculator due to performance +use_real_imp_or_mp_bidding = True + +[cardplay] +# This is telling if opening lead is included in the neural net for lefty +opening_lead_included = True +lefty_nt = models/TF2models/lefty_nt_2024-07-08-E20.keras +dummy_nt = models/TF2models/dummy_nt_2024-07-08-E20.keras +righty_nt = models/TF2models/righty_nt_2024-07-16-E20.keras +decl_nt = models/TF2models/decl_nt_2024-07-08-E20.keras +lefty_suit = models/TF2models/lefty_suit_2024-07-08-E20.keras +dummy_suit = models/TF2models/dummy_suit_2024-07-08-E20.keras +righty_suit = models/TF2models/righty_suit_2024-07-16-E20.keras +decl_suit = models/TF2models/decl_suit_2024-07-08-E20.keras +# Number of samples when playing the hand +sample_hands_play = 200 +# Minimum number of boards we want returned for sampling during play +min_sample_hands_play = 20 +# Minimum number of boards we want returned for sampling during play +min_sample_hands_play_bad = 12 +# Number of samples we will generate to find sample_hands_play +sample_boards_for_play = 5000 +# Should possible claim be calculated +claim = True +# Use bidding info for sampling during play and bidding +# Setting this to false will require a higher number of generated deals +use_biddinginfo = True +# Use bidding quality in evaluation, if bad samples, just use neural network +use_biddingquality_in_eval = True +# Use SuitC to find the card for single suit combinations +use_suitc = True +# Only check trump in suit contracts (and all suits in NT) +suitc_sidesuit_check = True +# Use real IMP or MP when finding the play - original version used average tricks +use_real_imp_or_mp = True +# Drawing trump, reward is given if opponents has trump, penalty if not +# The reward is low as it is only useable if more cards with the same score +draw_trump_reward = 0.05 +draw_trump_penalty = 0.1 +# We can filter away play, that is not suggested by the neural network. +trust_NN = 0.0 + +[pimc] +# Setting this to false will suppress output from PIMC, if true it will follow the global defintion of verbose +pimc_verbose = False +# Are we using PIMC as declarer and/or defender? +pimc_use_declaring = True +pimc_use_fusion_strategy = False +pimc_use_defending = True +# Max wait time for results from PIMC in seconds +pimc_wait = 3 +# When should PIMC kick in. PIMC is best with few cards unknown, but is used as a second opinion to BENs Double dummy +pimc_start_trick_declarer = 1 +pimc_start_trick_defender = 1 +# Extract hcp from samples and use as input to PIMC +pimc_constraints = True +# On every trick create new constraints based on samples. If false only do it, when PIMC kicks in +# The API is stateless and will establish constraints at each trick +pimc_constraints_each_trick = True +# Stop evaluation after finding the number of playouts unless pimc_wait expires before +pimc_max_playouts = 200 +# Max number of threads PIMC is allowed to use +pimc_max_threads = 12 +# If singleton, just play it without evaluating it +autoplaysingleton = True +# PIMC trust NN. We can filter away play, that is not suggested by the neural network +pimc_trust_NN = 0.00 +# Combine with BEN double dummy +pimc_ben_dd_declaring = True +pimc_ben_dd_defending = True +# When merging results we can trust one side more. Default is 0.5. The weight is for PIMC, so the higher the more trust in PIMC +# If bidding quality is below the threshold, we will switch trust between BEN and PIMC, as BENs samples do not match the bidding. + +pimc_bidding_quality = 0.1 +pimc_ben_dd_declaring_weight = 0.3 +pimc_ben_dd_defending_weight = 0.3 +# Use a priori probabilities +# Setting this to true will send all played card to PIMC. that will give weight to each sample, when creating average tricks +# and when calculating chance for making/defeating the contract +pimc_apriori_probability = False +# These margins are added before calling OIMC to be sure we get some deals, that does not match the bidding entirely +pimc_margin_suit = 1 +pimc_margin_hcp = 3 +pimc_margin_suit_bad_samples = 2 +pimc_margin_hcp_bad_samples = 5 + + +[sampling] +# When sampling we use bidding_info as a guide, and these control how to adjust bidding_info after a card given to a hand +# Multiplied to the hcp-value of the card, the higher value there more the samples will have the average hcp's +# This can be disable by setting use_biddinginfo to false +hcp_reduction_factor = 0.83 +# when a card is given subtract this from the shape, to reduce odds it get more in that suit +shp_reduction_factor = 0.3 +# If bid selected directly by Neural net, then save time dropping generating samples +no_samples_when_no_search = True +# Filter to remove hands, where the opening lead was not suggested by the neural network +# setting the following to false is the default behavior from a 32 card deck +# lead_accept_threshold_suit will sum all lead, including honors, for each suit and check the suit lead, adding up the score +lead_accept_threshold_suit = False +# lead_accept_threshold_honors will switch to the 24 deck suit, when validating the lead +# if following lead conventions like 2nd from 3 this should be enabled +lead_accept_threshold_honors = True +# Can be disabled by setting it to zero. This is a filter, so we keep ot low, as any lead can be possible +lead_accept_threshold = 0.10 +# Alternative is +# if following lead conventions like 2nd from 3 this should be enabled +# lead_accept_threshold_honors = False +# Can be disabled by setting it to zero. This is a filter, so we keep ot low, as any lead can be possible +# lead_accept_threshold = 0.01 + +# If we play with our normal partner we can add some trust to the lead +# Setting it to high will reduce the samples and thus getting bad samples +lead_accept_threshold_partner_trust = 0.10 + +# Filter to remove hands, where we do not trust the bidding. Used when sampling hands during bidding +#use_distance = False +#bidding_threshold_sampling = 0.25 +#bid_accept_threshold_bidding = 0.20 +#bid_accept_play_threshold = 0.4 +# This is calculated using euclidian distance, so 0.33 could be one of the 3 bids in a bidding round matching +use_distance = True +bidding_threshold_sampling = 0.70 +# If not finding enough samples above bidding_threshold_sampling we extend to this, until we get min_sample_hands_auction +bid_accept_threshold_bidding = 0.40 +# Filter to remove hands not consistent with the bidding. Used during play +bid_accept_play_threshold = 0.40 + +# Filter to remove hands, where the play is inconsistent with the sample. Setting it to zero will remove the validation +# This is difficult, as setting it to low will include boards where BEN not will repeat a finesse, but setting it to high might reduce useable samples +# Also important to notice, this is not used for PIMC as defender or declarer +play_accept_threshold = 0.02 +min_play_accept_threshold_samples = 10 +# If we dont find enough samples, then include down to this threshold. Used during play +bid_extend_play_threshold = 0.10 +# Number hands where we will calculate scores for when bidding +sample_hands_auction = 200 +# The number of hands we will generate to find sample_hands_auction. Estimated cost pr. sample is 4ms +# This is now a max as we generate blocks of sample_boards_for_auction_step hands +sample_boards_for_auction = 20000 +sample_boards_for_auction_step = 1000 +# After each real bid we add 50% to the max samples. setting to zero disables +increase_for_bid_count = 6 +# If samples below this threshold print a warning in the log +warn_to_few_samples = 10 +# Minimum number of hands when caclulating scores in the bidding +min_sample_hands_auction = 10 +# If we dont find enough samples, then include down to this threshold. Used during bidding +bid_extend_bid_threshold = 0.01 +# How many boards should we sample to find the number of samples below +sample_boards_for_auction_opening_lead = 20000 +# Number of samples made, when finding the opening lead +sample_hands_opening_lead = 200 +# Max number of samples to include when reviewing a board +sample_hands_for_review = 20 +# If probability for a bid is below this, then drop the sample +exclude_samples = 0.005 +# Skip last bidding round to find samples, if we did not find the minimum needed. We will only try to find 25% samples +sample_previous_round_if_needed = True diff --git a/src/frontend/views/api.tpl b/src/frontend/views/api.tpl index 54c0674d..8110f4af 100644 --- a/src/frontend/views/api.tpl +++ b/src/frontend/views/api.tpl @@ -629,7 +629,7 @@ html += `