From 4cf24b54c94752755b64530da87de1f86cd262eb Mon Sep 17 00:00:00 2001 From: Bo Haglund Date: Sat, 22 Oct 2011 19:19:54 -0400 Subject: [PATCH] historical commit dds 1.1.12 --- DDS_alg_descr-revE3.txt | 702 ------- ...descr-revE3.rtf => DDS_alg_descr-revE4.rtf | 265 +-- DLL-dds_1112_m.rtf | 123 ++ DLL-dds_11_h.rtf | 108 -- DLL-dds_11_h.txt | 112 -- dds.cpp | 1696 +++++++++++------ dll.h | 68 +- readme.txt | 32 +- release_notes.txt | 71 + 9 files changed, 1504 insertions(+), 1673 deletions(-) delete mode 100644 DDS_alg_descr-revE3.txt rename DDS_alg_descr-revE3.rtf => DDS_alg_descr-revE4.rtf (93%) create mode 100644 DLL-dds_1112_m.rtf delete mode 100644 DLL-dds_11_h.rtf delete mode 100644 DLL-dds_11_h.txt diff --git a/DDS_alg_descr-revE3.txt b/DDS_alg_descr-revE3.txt deleted file mode 100644 index 463a76d5..00000000 --- a/DDS_alg_descr-revE3.txt +++ /dev/null @@ -1,702 +0,0 @@ -Bo Haglund -Rev. E3, 2008-09-07 - - -Search Algorithms for a Bridge Double Dummy Solver - -This description is intended for anyone interested in the inner workings of a bridge double dummy solver (DDS). It describes my solver implemented in the Win32 environment as a DLL. - -DDS algorithm descriptions already exist, see reference list at the end. However, to my knowledge, no document exists that gives an in depth description of all algorithms covered in this document. - - - - -1.The basic search algorithm - - The search is based on the zero window search [Pearl 1980]. - Pseudo code for its application on DD solver search is given. - Cards searched are described as ”moves” in contrast to cards that are really played. - - int Search(posPoint, target, depth) { - if (depth==0) { - tricks=Evaluate; - if (tricks >= target) - value=TRUE; - else - value=FALSE; - return value; - } - else { - GenerateMoves; - if (player_side_to_move) { - value=FALSE; moveExists=TRUE; - while (moveExists) { - Make; - value=Search(posPoint, target, depth-1); - Undo; - if (value==TRUE) - goto searchExit; /* Cutoff, current move recorded as ”best move” */ - moveExists=NextMove; - } - } /* Opponents to move */ - else { - value=TRUE; moveExists=TRUE; - while (moveExists) { - Make; - value=Search(posPoint, target, depth-1); - Undo; - if (value==FALSE) - goto searchExit; /* Cutoff, current move recorded as ”best move” */ - moveExists=NextMove; - } - } - } - - searchExit: - return value; -} - - -The Search parameters are: -posPoint - a pointer to a structure containing state information for the position (deal) to be searched, e.g. leading hand, hand-to-play, cards yet to play etc. -target - the number of tricks the player must take. -depth - the current search depth. - -Search returns TRUE if the target is reached, otherwise FALSE. - -When Search is called, depth is set to the number of cards left to play minus 4. -GenerateMoves generates a list of alternative moves (=cards) that can be played in the initial position whose state data is pointed to by posPoint. For cards that are equivalent (e.g. AK) only the card with highest rank is generated. Card equivalence is reanalyzed after each trick. -E.g. if the hand-to-play has AQ in a suit where K was played in a previous trick, then A and Q become equivalents. - -If the side of the player has the move, Search tries to find a move that meets the target, i.e that evaluates to TRUE. If such a move is found, search returns TRUE, and saves the move as ”best”. -If the other side has the move, Search tries to find a move that defies meeting the target, i.e. that evaluates to FALSE. If such a move is found, search returns FALSE, and saves the move as ”best”. - -Each move in the generated move list is handled by first calling Make, which removes the card from the position state information. Search is then recursively called with a position state that now has excluded the played card, depth has been decremented by one. For each new recursive call to Search, a card is removed from the position state information and depth is decremented. This goes on until depth equals 0 in which case only one trick remains. The outcome of this trick is calculated by Evaluate. If the total number of tricks won by the side of the player then reaches target, Search returns TRUE, otherwise FALSE. This result propagates upwards as Search returns for each level, Undo is called which reinstalls the searched card on this level. -Finally, Search returns for the top level. - -This basic search algorithm is not powerful enough to terminate the search of a typical 52 cards deal in a reasonable time. To accomplish this, a number of search algorithm enhancements are required, which will be described in the following chapters. - -The described search algorithm only tells if a predefined target can be reached. It does not tell how many tricks that the side of the player can get. This is accomplished by repeated calls to Search: - -g = guessed number of tricks for side of the player -iniDepth = number of cards to play minus 4 -upperbound = 13; -lowerbound = 0; -do { - if (g==lowerbound) - tricks=g+1; - else - tricks=g; - if ((Search(posPoint, tricks, iniDepth)==FALSE) { - upperbound=tricks-1; - g=upperbound; - } - else { - lowerbound=tricks; - g=lowerbound; - } -} -while (lowerbound < upperbound); -g=maximum tricks to be won by side of player. - - - -2.Overview of the search algorithms used in the DD solver - -The additional functions in the pseudo code for supporting the search speed enhancements are given in italics. - -int Search(posPoint, target, depth) { - if (no_move_yet_in_trick) { - TargetTooLowOrHigh; - if (target_already_obtained) - return TRUE; - else if (target_can_no_longer_be_obtained) - return FALSE; - QuickTricks; - LaterTricks; - if (cutoff_for_player_side) - return TRUE; - else if (cutoff_for_opponent_side) - return FALSE; - RetrieveTTresult; - if (transposition_table_entry_match) { - if (target_reached) - return TRUE; - else - return FALSE; - } - } - - if (depth==0) { - evalRes=Evaluate; - if (evalRes.tricks >= target) - value=TRUE; - else - value=FALSE; - return value; - } - else { - GenerateMoves; - MoveOrdering; - CheckMovesForCutoff; /* For pseudo-code, see chapter 6 */ - if (player_side_to_move) { - value=FALSE; moveExists=TRUE; - while (moveExists) { - Make; - value=Search(posPoint, target, depth-1); - Undo; - if (value==TRUE) { - MergeMoveData; - goto searchExit; /* Cutoff, current move recorded as ”best move” */ - } - MergeAllMovesData; - moveExists=NextMove; - } - } /* Opponents to move */ - else { - value=TRUE; moveExists=TRUE; - while (moveExists) { - Make; - value=Search(posPoint, target, depth-1); - Undo; - if (value==FALSE) { - MergeMoveData; - goto searchExit; /* Cutoff, current move recorded as ”best move” */ - } - MergeAllMovesData; - moveExists=NextMove; - } - } - } - searchExit: - AddNewTTentry; - return value; - } - - -TargetTooLowOrHigh checks the target value against the number of tricks currently won by side of the player and against number of tricks left to play. -It is executed at the beginning of each trick, before any card has been played. -If number of currently won tricks by player’s side equals or exceeds target, Search returns TRUE. -If number of currently won tricks by player’s side plus tricks left to play is less than target Search returns FALSE. -Since possible winning cards for the remaining tricks are irrelevant, no winning cards are backed up at cutoff termination. - -TargetTooLowOrHigh search enhancement is described e.g. in [Chang]. - -QuickTricks determines if the side to move can take one or more sure tricks. E.g. if the hand to move has an Ace in an NT contract, at least one sure trick can be taken. -It is executed at the beginning of each trick, before any card has been played. A simple quick trick is also executed after the leading card of the trick is played. -Assuming that the sure tricks are won by the side to move, then the conditions for search cutoff in TargetTooLowOrHigh are again tested to produce further search cutoffs. -The detailed conditions for determination of sure tricks are described in Chapter 3. -When quicktricks win by rank, they are backed up at cutoff termination. - -The idea of QuickTricks is described e.g. in [Chang]. - -LaterTricks determines if the opponents of the side to move can take one or more tricks at their turn or later in the play. It is also executed at the beginning of each trick and uses similar criteria for search cutoff as Quicktricks. -When quicktricks win by rank, they are backed up at cutoff termination. -For a detailed description, see Chapter 4. - -RetrieveTTresult scans the set of positions in the transposition table to see if there is a match against the current position. -It is executed at the beginning of each trick, before any card has been played. After detection of a transposition table entry match, the winning ranks necessary in the remaining cards are backed up. -For details, see Chapter 7. - -Evaluate returns evalResult which updates the position state information. evalResult contains: -evalResult.tricks, the number of tricks won by the side of the player, and -evalResult.winRank which includes the card in the last trick that won by rank. -E.g. if the last trick includes the spades A, Q, 9 and 3, evalResult.winRank returns spade A. But -if the last trick was won without a win by rank as for spade 5 (leading and winning card), heart A, heart Q, heart 5, no winning rank is returned. - -Keeping record of cards that win by ranks and subsequently using this information to ignore ranks for other cards is discussed in the Partition Search concept invented by Matthew Ginsberg and described in his paper [Ginsberg]. - -MoveOrdering. The alternative cards created by MoveGenerate are sorted, with the cards most likely to terminate the search fastest being sorted first in the move list.The allocation of card weights are described in detail in Chapter 5. - -CheckMovesForCutoff checks if any of the moves just generated will lead to a position that can be found in the transposition table. If so, an immediate Search return can be done, saving unnecessary search effort. This is further described in Chapter 6. - -To my knowledge this is not described anywhere for usage in a DDS. It is described in [Plaat et al.] and named Enhanced Transposition Cutoffs. - -At move search cutoff, MergeMoveData collects the union of the backed up accumulated winning ranks and the rank of the made move, assuming it did win by rank. The state data of the position is updated with the collected information. - -MergeAllMovesData collects the union of the backed up accumulated winning ranks, the previous accumulated winning ranks of the alternative moves generated on this depth, and the rank of the made move, assuming it did win by rank. When all alternative moves have been searched without a cutoff, the state data of the position is updated with the collected information. - -The information from MergeMoveData and MergeAllMovesData is later stored in the transposition table and determines which ranks that are essential when RetrieveTTresult scans the set of positions in the transposition table. A match of ranks with the current position is only needed for winning ranks. See Chapter 7. - -AddNewTTentry adds the evaluated position as a new entry in the transposition table. See Chapter 7. - -NextMove filters out all ”small” cards except one per hand/suit combination. A ”small” card is a backed up card that is shown to never win by rank. The rest of the ”small” card moves for the hand/suit combination are never searched, leading to a smaller search tree. -This search enhancement was suggested by Hans Kuijf [Kuijf]. - - - -3.The Quick Tricks cutoff algorithm - -The number of tricks that can immediately be taken by the side to play the leading card of the trick consists of: -a)The number of tricks that can be taken by the hand-to-play, and -b)The number of tricks that can be taken by the partner of the hand-to-play -At return by QuickTricks, the position state information is updated with the winning ranks found. - -Of course, in order to add b), there must be an entry from the hand-to-play to the partner’s hand. - -For each ”s” (suit) the following is calculated: - -If the hand-to-play is the only hand having cards in s, and the opponents have no trumps (when s is not trumps), the number of quick tricks for s is the suit length of the hand-to-play. - -If the opponents have no trumps, a check is made to see if quick tricks equal to the maximum of the trumps length for leading hand and the partner causes a search cutoff. - -If the hand-to-play has a card in a suit where the partner has a winning rank, and partner is the only hand having cards in s: -The number of quick tricks for s is the suit length of partner. - -Else: -If the winning rank is in hand-to-play, and the opponents cannot ruff, the number of quick tricks is incremented by one. Further, if the second best rank is also in hand-to-play, and the opponents cannot still ruff, the quick tricks is again incremented by one. - -Else: -If the winning rank is in partner and partner has winning rank as entry, the same applies for the partner as for the hand-to-play described above. - -If it is a trump contract, the first suit to be investigated is the trump suit. Then if there are trump suit quick tricks for the side to play, those are cashed and quick tricks incremented accordingly. - -When the other suits are investigated for quick tricks, only the remaining opponent trump cards need to be considered. - -The quick tricks are then summarized from each suit, and the total calculated. - -A simple Quick Tricks algorithm is also executed after the leading card of the trick has been played: - -A quick trick is gained either if the hand-to-play or the partner can win the current trick with the card having the highest rank of the suit played, or if hand-to-play or the partner can win the trick by ruffing. - -The idea to also execute Quick Tricks after the leading card has been played was given by Hans Kuijf [Kuijf]. - - - -4.The Later Tricks cutoff algorithm - -Check for search cutoff if the opponents to the trick leading hand have at least a sure trick later. - -If not trump contract: - -1)The opponents have at least a sure trick if for all suits where the trick leading hand has a card, the side of the leading hand does not have the highest rank. -More than one sure trick can be taken by the opponents if they possess the winning rank for more than one suit, or - -2)Assume that all suits where the side of the trick leading hand has the winning rank give maximum possible number of tricks, i.e. that the sure trick number is the sum of the -maximum lengths of these suits. -If this still cannot cause a cutoff for the trick leading side, allocate one sure trick for the opponents side. - -If trump contract: - -Quick tricks for the opponents of the leading hand are added when the opponents have one or more winning trumps. This idea was given by Pedja Stanojevic [Stanojevic]. - -1) If the opponent side have all the trumps, the number of sure tricks is the maximum suit length - length, or - -2) If the opponent side has the highest trump, they have 1 sure trick. If they also have the second - highest trump, they have 2 sure tricks, or - -3) If the opponent side has the second highest trump plus at least one trump more behind the - hand with the highest trump, the opponent side has 1 sure trick. - -5.The Move Ordering algorithm - -The weight of a card in the move list is affected by the suit and the rank of the card and by the other cards in the same trick. -The weights of the cards in the move list are used to sort them, with the cards having the highest weight being sorted first in the list. - -If the hand-to-play is trick leading hand or void in the suit played by leading hand, the card with the highest weight for each present suit will get a high additional bonus weight. After list resorting, those cards will occupy the first positions in the move list. - -A "best move" is maintained for each searched depth. At a search (alpha-beta) cutoff, the move causing the cutoff overwrites the present "best move" for the current depth. When a Transposition Table entry is created, the current best move is stored in that entry if: -The target is met and the leading hand belongs to the player’s side, or target is not met and the leading hand belongs to the other side. Otherwise the best move is not stored in the Transposition Table entry. -At a Transposition Table entry match, its stored best move will be best move for the current search depth. - -By ”card move” in the following pseudo code is meant the card by the hand-to-play that is getting a weight in the move list. The ”card rank” is a value in the range 2-14, corresponding to the card ranks 2 to the Ace. - -For the determination of the weight, it is calculated whether or not the current card move is a card that wins the current trick for the side of the hand-to-play, assuming that both sides play their optimum cards. - - -Hand-to-play is trick leading hand - -The contribution of the suit to the weight: - -suitWeightDelta = suitBonus - (countLH+countRH) * 2 - -If trump contract, and the suit is not trump, then there is a (negative) suitBonus of –12 if -LHO is void and LHO has trump card(s), or -RHO is void and RHO has trump card(s) - -Otherwise, suitBonus = 0. - -countLH = (suit length of LHO) * 4, if LHO is not void in the suit, -countLH = (depth + 4), if LHO is void in the suit - -countRH = (suit length of RHO) * 4, if RHO is not void in the suit, -countRH = (depth + 4), if RHO is void in the suit - -Suits are thus favoured where the opponents have as few move alternatives as possible. - - -if (trick winning card move) { - if (one of the opponents has a singleton highest rank in the suit) - weight = suitWeightDelta + 40 – (rank of card move) - else if (hand-to-play has highest rank in suit) { - if (partner has second highest rank in suit) - weight = suitWeightDelta + 50 – (rank of card move) - else if (the card move is the card with highest rank in the suit) - weight = suitWeightDelta + 31 - else - weight = suitWeightDelta + 19 – (rank of card move) - } - else if (partner has highest rank in suit) { - if (hand-to-play has second highest rank in suit) - weight = suitWeightDelta + 50 – (rank of card move) - else - weight = suitWeightDelta + 35 – (rank of card move) - } - else if (card move include equivalent card(s) in the suit) - weight = suitWeightDelta + 40 – (rank of card move) - else - weight = suitWeightDelta + 30 – (rank of card move) - if (the card move is ”best move” as obtained at search cutoff) - weight = weight + 50; -} -else { /* Not a trick winning move */ - if (either LHO or RHO has singleton in suit which has highest rank) - weight = suitWeightDelta + 20 – (rank of card move) - else if (hand-to-play has highest rank in suit) { - if (partner has second highest rank in suit) - weight = suitWeightDelta + 35 – (rank of card move) - else if (the card move is the card with highest rank in the suit) - weight = suitWeightDelta + 16 - else - weight = suitWeightDelta + 4 – (rank of card move) - } - else if (partner has highest rank in suit) { - if (hand-to-play has second highest rank in suit) - weight = suitWeightDelta + 35 – (rank of card move) - else - weight = suitWeightDelta + 20 – (rank of card move) - } - else if (hand-to-play has second highest rank together with equivalent card(s) in suit) - weight = suitWeightDelta + 20 – (rank of card move) - else - weight = suitWeightDelta + 4 – (rank of card move) - if (the card move is ”best move” as obtained at search cutoff) - weight = weight + 30; -} - - - Hand-to-play is left hand opponent (LHO) to leading hand - -if (trick winning card move) { - if (hand-to-play void in the suit played by the leading hand) { - if (trump contract and trump is equal to card move suit) - weight = 30 - (rank of card move) + 2 * (suit length for card move suit) - else - weight = 60 - (rank of card move) + 2 * (suit length for card move suit) - } - else if (lowest card for partner to leading hand is higher than LHO played card) - weight = 45 - (rank of card move) - else if (RHO has a card in the leading suit that is higher than the trick leading card - but lower than the highest rank of the leading hand) - weight = 60 - (rank of card move) - else if (LHO played card is higher than card played by the leading hand) { - if (played card by LHO is lower than any card for RHO in the same suit) - weight = 75 - (rank of card move) - else if (played card by LHO is higher than any card in the same suit for the leading hand) - weight = 70 - (rank of card move) - else { - if (LHO move card has at least one equivalent card) { - weight = 60 - (rank of card move) - else - weight = 45 - (rank of card move) - } - } - else if (RHO is not void in the suit played by the leading hand) { - if (LHO move card has at least one equivalent card) - weight = 50 - (rank of card move) - else - weight = 45 - (rank of card move) - } - else - weight = 45 - (rank of card move) -} -else { /* card move is not trick winning */ - if (hand-to-play void in the suit played by the leading hand) { - if (trump contract and trump is equal to card move suit) - weight = 15 - (rank of card move) + 2 * (suit length for card move suit) - else - weight = - (rank of card move) + 2 * (suit length for card move suit) - } - else if (lowest card for partner to leading hand or for RHO in the suit played is higher - than played card for LHO) - weight = - (rank of card move) - else if (LHO played card is higher than card played by the leading hand) { - if (LHO move card has at least one equivalent card) - weight = 20 - (rank of card move) - else - weight = 10 - (rank of card move) - } - else - weight = - (rank of card move) -} - - - -Hand-to-play is partner to trick leading hand - -if (trick winning card move) { - if (hand-to-play void in the suit played by the leading hand) { - if (card played by the leading hand is highest so far) { - if (card by hand-to-play is trump and the suit played by the leading hand is not trump) - weight = 30 - (rank of card move) + 2 * (suit length for card move suit) - else - weight = 60 - (rank of card move) + 2 * (suit length for card move suit) - } - else if (hand-to-play is on top by ruffing) - weight = 70 - (rank of card move) + 2 * (suit length for card move suit) - else if (hand-to-play discards a trump but still loses) - weight = 15 - (rank of card move) + 2 * (suit length for card move suit) - else - weight = 30 - (rank of card move) + 2 * (suit length for card move suit) - } - else - weight = 60 - (rank of card move) -} -else { /* card move is not trick winning */ - if (hand-to-play void in the suit played by the leading hand) { - if (hand-to-play is on top by ruffing) - weight = 40 - (rank of card move) + 2 * (suit length for card move suit) - else if (hand-to-play underruffs */ - weight = -15 - (rank of card move) + 2 * (suit length for card move suit) - else - weight = - (rank of card move) + 2 * (suit length for card move suit) - } - else { - if (the card by hand-to-play is highest so far) { - if (rank of played card is second highest in the suit) - weight = 25 - else if (hand-to-play card has at least one equivalent card) - weight = 20 - (rank of card move) - else - weight = 10 - (rank of card move) - } - else - weight = -10 - (rank of card move) - } -} - -Hand-to-play is right hand opponent (RHO) to leading hand - -if (hand-to-play is void in leading suit) { - if (LHO has current highest rank of the trick) { - if (card move ruffs) - weight = 14- (rank of card move) + 2 * (suit length for card move) - else - weight = 30- (rank of card move) + 2 * (suit length for card move) - } - else if (hand-to-play ruffs and wins) - weight = 30- (rank of card move) + 2 * (suit length for card move) - else if (card move suit is trump, but not winning) - weight = - (rank of card move) - else - weight = 14- (rank of card move) + 2 * (suit length for card move) -} -else if (LHO has current winning move) { - if (RHO ruffs LHO’s winner) - weight = 24 - (rank of card move) - else - weight = 30- (rank of card move) -} -else if (card move superior to present winning move not by LHO) { - weight = 30- (rank of card move) -else { - if (card move ruffs but still losing) - weight = - (rank of card move) - else - weight = 14- (rank of card move) -} - - - -6.Algorithm to try early cutoff for generated moves - -After generating moves at the end of a trick, they are each checked to see if one of them will lead to a position that already is stored in the Transposition Table. -Due to the processing overhead, this check is only made if the depth is 29 or more (i.e there are at least 33 cards in the position). -Pseudo code: - -moveExists = TRUE; -while (moveExists) { - Make; - depth = depth –1; - RetrieveTTresult; - if (hit in the transposition table) { - Search returnsTRUE if value of the position is TRUE and player side to move, or - FALSE if value of the position is FALSE and opponents side to move. - Else: Increment weight of move with 100. - } - depth = depth +1; - Undo; - moveExists = NextMove; -} - -The performance improvement for this enhancement is less than for the other enhancements. The number of generated nodes is roughly decreased by 10% and the search time is slighly decreased. - - - -7.Storage and retrieval of position state data in the Transposition Table - -Positions stored in the Transposition Table always consist of completed tricks. Positions stored start at depth=4, then 8,12, and so on. The information stored is information on won cards, the suit lengths of the hands, the hand to play the leading card in the position and upper and lower bounds for the number of future tricks to be taken by the side of the player. - -Starting from issue 1.1.8, each ”winning cards node” contain all winning cards for one suit after an idea by Joël Bradmetz. This new solution is faster. - -7.1 Transposition Table storing winning card ranks - -For the outcome of played tricks, only card ranks that are winning due to their ranks matter: -Assume that the last two tricks of a deal without trumps looks like the following: -Trick 12: Leading hand North plays heart A, East, South and West follow by hearts Q, 9 and 7 respectively. -Trick 13: North then leads spade A, the other hands plays diamonds J, 8,3 in that order. - -In trick 12, heart A wins by rank. In trick 13, spade A wins but not by rank. -The sequence of cards could have been the following without changing the outcome: -Trick 12: heart A, heart x, heart x, heart x -Trick 13: spade x, diamond x, diamond x, diamond x -where x is any rank below lowest winning rank. - -The cards that win by rank are recorded during the search and backed up similarly to the search value. If a card wins by rank and there are equivalent cards, e.g. only spade A is searched from a sequence of AKQ, then also the other cards K and Q must be recorded as having won by rank. - -The cards winning by rank are stored in the Transposition Table as relative ranks, however any rank larger than the lowest winning rank in the suit are also stored as ”winning ranks”. Using relative ranks rather than absolute ranks considerably increases the number of positions that match this Transposition Table entry: -As an example, assume that there are only 4 cards left in a suit, A, Q, 9, 7 where each hand has one card in the suit. Then any combination of ranks, e.g. 8, 6, 3, 2 that preserves the relative order of ranks between hands will cause a match. - -In the state position information absolute ranks are used, it is only in the Transposition Table where the ranks are stored as relatives. - - -7.2 Backing up the winning ranks - -At the search termination, either at the last trick or at a cutoff, the cards that have won by rank are backed up in the search tree together with the search value. -As this information propagates upwards, it is aggregated with backed up information from other tree branches. -At a search cutoff, MergeMoveData merges the information (V is a union): - -(winning ranks of all suits for current depth) = (winning ranks of all suits for depth - 1) V (possible winning rank for the current move causing the cutoff) - -For each new move not causing cutoff, MergeAllMovesData merges: - -(winning ranks of all suits for current depth) = (winning ranks of all suits for current depth) V (winning ranks of all suits for depth - 1) V (possible winning rank for the current move) - - -7.3 Checking the current position for a Transposition Table entry match - -The "Transposition Table" has a tree structure rather than a table, consisting of 2 interconnected trees. -For deciding if there is a match, input is the position state data, including the cards left to play and the current leading hand. -There are ”root pointers” per number of tricks left and per leading hand which each points to the root of a tree of ”suit lengths combination” nodes. Each such node includes a 64-bit code that uniquely defines one combination of suit lengths for the hands. The nodes are ordered such that the value of the 64-bit code in a parent node is higher than the 64-bit code of its left child but lower than the 64-bit code of its right child. So to find the node with the suit lengths combination for the actual position, a binary search is made. The basic binary search algorithm is described in [Knuth]. -Each ”suit length combination node” points to the root of a tree consisting of ”winning cards nodes”, ie. cards that win by rank. (So the Transposition Table is really a number of trees, a forest.) -When a position is checked for a possible Transposition Table match, a tree branch is selected consisting of 4 subsequent ”winning cards nodes”, each ”winning cards node” includes an aggregate of all winning cards for one suit. This branch is followed as long as the ”winning cards” also can be found in the current position. (Note that the ranks of the ”winning card nodes” are relative, so the ranks of the current position must first be translated from absolute to relative ranks.) When the ”winning cards node” no longer matches with the current position and there is no other alternative ”winning cards node” that fits, then the search backs up and tries an alternative ”winning cards node” on a higher level. - -When the last of the 4 subsequent ”winning cards nodes” containing clubs is reached, it points to a ”set of positions node”. Its stored upper and lower value bounds are checked against the number of tricks won so far by the player’s side and the target value. The following conditions are then checked, assuming that it is the North/South side that is the player’s side: - -If the sum of the stored lower value bound and the number of tricks won so far for the player’s side is equal or larger than target, then target can be reached for the player’s side in the current position. Search on this depth is terminated and TRUE is returned. - -If the sum of the stored upper value bound and the number of tricks won so far for the player’s side is less than target, then reaching target can be prevented by the opponents to the player’s side in the current position. Search on this depth is terminated and FALSE is returned. - -If instead it is East/West that is the player’s side, the following conditions apply: - -If the sum of number of tricks remaining and the number of tricks won so far for the player’s side minus the upper value bound is equal or larger than target, then target can be reached for the player’s side in the current position. Search on this depth is terminated and TRUE is returned. - -If the sum of number of tricks remaining and the number of tricks won so far for the player’s side minus the lower value bound is less than target, then reaching target can be prevented by the opponents to the player’s side in the current position. Search on this depth is terminated and FALSE is returned. - -For all other cases, the search continues for the current depth. - -For example, take the previous example with 2 tricks remaining with spade rank order 1 at North. (Rank order 1 is highest rank.) The hearts have rank orders 1 at North, 2 at East, 3 at South and 4 at West. The diamond rank orders are orders 1 at East, 2 at South and 3 at West. North is leading hand. -The ”root pointer” is now defined by the number of tricks remaining (=2) and North as leading hand. -The ”root pointer” points to the root node of its ”suit lengths combination” tree. The 64-bit integer coded from the suit lengths for all suits and hands is now searched within the tree. When the node is found with matching 64-bit suit lengths code, this node will point to the root of its ”winning card” tree. -This pointer points to a "winning cards node" containing spade rank order 1 at North which fits with the current position. This ”winning cards node” points to another "winning cards node" containing hearts rank orders 1 at North and 2 at East which also fits the current position. Next ”winning cards node” pointed to contains diamonds order 1 at South, which does not match the current position. However, there is an alternative ”winning cards node” that has diamonds order 1 at East, which fits. (If there had been no alternative ”winning cards node” which fitted, the search had backed up to the previous ”winning cards node” to see if there was an alternative ”winning cards node” on this level which also fitted.) The next ”winning cards node” pointed to is for clubs. This node is empty, which fits the current position which have no clubs. -This ”winning cards node” points to a "set of positions node” which have upper and lower value bounds defined. The conditions for these bounds are assumed to be fulfilled causing search termination on this depth, as described earlier. - -The usage of upper and lower value bounds in transposition tables is described in [Chang] and [Kupferschmid, Helmert]. - - - -The ”suit lengths combination” node includes: - The suit lengths combination as a 64-bit integer. - A pointer to the top ”winning cards node”. - A pointer to next left ”suit lengths combination node” in the binary tree. - A pointer to next right ”suit lengths combination node” in the binary tree. - - -The ”winning cards node” includes: -The hands of the relative ranks for each winning card of the actual suit. -A pointer to the next winning cards node required to achieve a Transposition Table match for this branch of the tree. -A pointer to the previous winning cards node. -A pointer to the next alternative winning cards node that leads to a Transposition Table match in an alternative tree branch. - A pointer to the "set of positions node". - - -The "set of positions node” includes: -An upper and a lower bound for the winning tricks of the North/South side. These values -are used to determine whether or not a search cutoff can be done. -The lowest winning rank per suit, expressed as relative rank. -The suit and rank for the currently best move. - - -After a Transposition Table match, the current position may later be part of a position that will be stored in the Transposition Table. Therefore, the stored winning ranks in the Transposition Table must be included in the state information of the current position. However, the winning ranks cannot be taken as is, because they are stored as relative ranks which now must be converted to absolute ranks in the current position. -This is done using the lowest winning relative rank for each suit that is stored in the ”set of positions” node that gave the Transposition Table match: -The aggregated set of (absolute) ranks for each suit in the current position is filtered using the stored information on the lowest winning relative rank. The winning ranks for each suit is then the aggregated set with only the number of highest ranks implied by the stored lowest winning relative rank in the ”set of positions” node. -E.g. if the aggregated rank set for spades is A J 9 4 2 and lowest winning relative rank is order=2, then winning ranks are A J. - - -7.4 Building a new entry in the Transposition Table - -When the value of the current position is known and it is the end of a trick (except the last), position state information is collected for storage in the Transposition Table. -The ranks of the backed up winning cards are converted from absolute to relative. -For each suit, it is determined which winning rank that is lowest. The relative ranks then stored in the new Transposition Table entry are all ranks above and including the lowest rank, filling out any ”holes” in the ranks that might have been present. -The trees of the Transposition Table are searched starting from the ”root pointer” and additional nodes are inserted corresponding to the current position. -First, the suit lengths of the current position are used to find a ”suit lengths combination node” or to create a new such node if it does not exist already. -The next step is to search for a ”winning card node” that has the ”suit length combination node” as parent. This ”winning card node” has then winning cards for spades. -If no such node yet exists, ”winning card nodes”, one for each suit, are created using the winning cards of the current position. Each such node includes all winning cards for one of the suits. Then, a ”set of positions” node is created. This node is pointed to from the last created ”winning card node” created for the winning cards of clubs. -Otherwise, if there already exists a matching ”winning card node” with the ”suit length combination node” as parent, it is checked whether or not the ”winning card nodes” in a subsequent tree branch already created for hearts, diamonds and clubs also are matched with the current position. -If such a sequence of nodes can be found, the upper or lower bound in the connected ”set of positions node” may be updated to allow for an increased number of cutoffs: - -If the current position upper value bound is less than the stored upper value bound, the stored value is updated with the current position value. -If the current position lower value bound is larger than the stored lower value bound, the stored value is updated with the current position value. - -In case a matching ”winning card node” cannot be found, a new ”winning card node” is created and linked to the last matching node. E.g. if existing ”winning card nodes” for spades and hearts match the current position, but no node match for diamonds, then a ”winning cards node” for diamonds is created and linked to the previous ”winning cards node” for hearts. Then a clubs ”winning cards node” and a ”set of positions node” are created. - - - - - -References - -James Dow Allen: -Source code for a simple DDS. -http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm - -Matthias Brill: -DDS algorithms description (in German) and DDS source code. - http://linux.softpedia.com/get/Science-and-Engineering/Artificial-Intelligence/cddsolve-20055.shtml - -Ming-Sheng Chang: -DDS algorithms description. -cs.nyu.edu/web/Research/TechReports/TR1996-725/TR1996-725.ps.gz - - -Ed Colley: -DDS source code and DDS executable. -http://freefinesse.sourceforge.net/ - -Matthew L. Ginsberg: -DDS algorithms description. -http://www.cs.cmu.edu/afs/cs/project/jair/pub/volume14/ginsberg01a.pdf - -Dan Hirschberg: -DDS algorithms description and DDS executable (MS DOS, cannot run in XP?) -http://www.ics.uci.edu/~dan/bridge/index.html - -Alexey Slovesnov: -DDS source code and DDS executable. - -Judea Pearl: Asymptotic properties of minimax trees and game search precedures. - Artificial Intelligence 14(2):113-138. [Pearl 1980] - -Aske Plaat, Jonathan Schaeffer, Wim Pijls and Arie de Bruin: Exploiting graph properties of game trees. In Proceedings of the Thirteenth National Conference on Artificial Intelligence, pages 234-239, 1996 [Plaat et al.] - -Hans Kuijf, personal communication. - -Pedja Stanojevic, personal communication. - -Knuth: The art of computer programming, Vol. 3, Searching and Sorting, chapter 6.2.2, Algorithm T. - -Sebastian Kupferschmid, Malte Helmert: A Skat Player Based on Monte Carlo Simulation. - -Joël Bradmetz, personal communication. -http://jibe-bridge.perso.cegetel.net/ diff --git a/DDS_alg_descr-revE3.rtf b/DDS_alg_descr-revE4.rtf similarity index 93% rename from DDS_alg_descr-revE3.rtf rename to DDS_alg_descr-revE4.rtf index 324fcfbc..76387bde 100644 --- a/DDS_alg_descr-revE3.rtf +++ b/DDS_alg_descr-revE4.rtf @@ -53,14 +53,14 @@ FollowedHyperlink;}}{\*\listtable{\list\listtemplateid-1\listsimple{\listlevel\l \'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 }}\ls4}{\listoverride\listid1686666904\listoverridecount0\ls5}{\listoverride\listid1135560398\listoverridecount0\ls6}{\listoverride\listid1459645526\listoverridecount0\ls7}{\listoverride\listid1938564357 \listoverridecount0\ls8}{\listoverride\listid1968315024\listoverridecount0\ls9}{\listoverride\listid402485625\listoverridecount0\ls10}{\listoverride\listid1944025331\listoverridecount0\ls11}{\listoverride\listid1611858212\listoverridecount0\ls12} {\listoverride\listid1883008225\listoverridecount0\ls13}{\listoverride\listid1220364652\listoverridecount0\ls14}{\listoverride\listid1180581588\listoverridecount0\ls15}{\listoverride\listid1506170630\listoverridecount0\ls16}{\listoverride\listid1424648690 -\listoverridecount0\ls17}}{\info{\title Bo Haglund}{\author Bo Haglund}{\operator Bo Haglund}{\creatim\yr2008\mo9\dy7\hr11\min21}{\revtim\yr2008\mo9\dy7\hr11\min52}{\version6}{\edmins32}{\nofpages22}{\nofwords5962}{\nofchars-32766}{\*\company } +\listoverridecount0\ls17}}{\info{\title Bo Haglund}{\author Bo Haglund}{\operator Bo Haglund}{\creatim\yr2008\mo9\dy7\hr11\min21}{\revtim\yr2010\mo4\dy10\hr9\min55}{\version17}{\edmins115}{\nofpages23}{\nofwords6036}{\nofchars-32766}{\*\company } {\nofcharsws0}{\vern89}}\margl1417\margr1417\margt1417\margb1417 \deftab1304\widowctrl\ftnbj\aenddoc\hyphhotz425\hyphcaps0\viewkind1\viewscale100 \fet0\sectd \linex0\headery709\footery709\colsx709\sectdefaultcl {\footer \pard\plain \s16\nowidctlpar -\tqc\tx4536\tqr\tx9072\pvpara\phmrg\posxr\posy0\adjustright \lang2057 {\field{\*\fldinst {\cs17 PAGE }}{\fldrslt {\cs17\lang1024 10}}}{\cs17 +\tqc\tx4536\tqr\tx9072\pvpara\phmrg\posxr\posy0\adjustright \lang2057 {\field{\*\fldinst {\cs17 PAGE }}{\fldrslt {\cs17\lang1024 12}}}{\cs17 \par }\pard \s16\ri360\nowidctlpar\tqc\tx4536\tqr\tx9072\adjustright { \par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}} {\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8 \pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\lang1053 Bo Haglund -\par }\pard\plain \nowidctlpar\adjustright \lang2057 {Rev. E3}{\lang1053 , 2008-09-07}{ +\par }\pard\plain \nowidctlpar\adjustright \lang2057 {Rev. E4}{\lang1053 , 2010-04-09}{ \par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\b\fs28\lang1053 \par \par Search Algorithms for a Bridge Double Dummy Solver @@ -128,18 +128,18 @@ FollowedHyperlink;}}{\*\listtable{\list\listtemplateid-1\listsimple{\listlevel\l \par Search returns TRUE if the target is reached, otherwise FALSE. \par }{\lang1053 \par When Search is called, depth is set to the number of cards left to play minus 4. -\par GenerateMoves generates a list of alternative moves (=cards) that can be played in the initial positi -on whose state data is pointed to by posPoint. For cards that are equivalent (e.g. AK) only the card with highest rank is generated. Card equivalence is reanalyzed after each trick. +\par GenerateMoves generates a list of alternative moves (=cards) that can be played in the initial position whose state da +ta is pointed to by posPoint. For cards that are equivalent (e.g. AK) only the card with highest rank is generated. Card equivalence is reanalyzed after each trick. \par }{E.g. if the hand-to-play has AQ in a suit where K was played in a previous trick, then A and Q become equivalents.}{\lang1053 \par \par If the side of the player has the move, Search tries to find a move that meets the target, i.e that evaluates to TRUE. If such a move is found, search returns TRUE, and saves the move as \'94best\'94. \par If the other side has the move, Search tries to find a move that defies meeting the target, i.e. that evaluates to FALSE. If such a move is found, search returns FALSE, and saves the move as \'94best\'94. \par -\par Each move in the generated move list is handled by first calling Make, whi -ch removes the card from the position state information. Search is then recursively called with a position state that now has excluded the played card, depth has been decremented by one. For each new recursive call to Search, a card is removed from the po -s -ition state information and depth is decremented. This goes on until depth equals 0 in which case only one trick remains. The outcome of this trick is calculated by Evaluate. If the total number of tricks won by the side of the player then reaches target, - Search returns TRUE, otherwise FALSE. This result propagates upwards as Search returns for each level, Undo is called which reinstalls the searched card on this level.\line Finally, Search returns for the top level. +\par Each move in the generated move list is handled by first calling Make, which removes the ca +rd from the position state information. Search is then recursively called with a position state that now has excluded the played card, depth has been decremented by one. For each new recursive call to Search, a card is removed from the position state info +r +mation and depth is decremented. This goes on until depth equals 0 in which case only one trick remains. The outcome of this trick is calculated by Evaluate. If the total number of tricks won by the side of the player then reaches target, Search returns T +RUE, otherwise FALSE. This result propagates upwards as Search returns for each level, Undo is called which reinstalls the searched card on this level.\line Finally, Search returns for the top level. \par \par This basic search algorithm is not powerful enough to terminate the search of a typical 52 cards deal in a reasonable time. To accomplish this, a number of search algorithm enhancements are required, which will be described in the following chapters. @@ -249,8 +249,8 @@ ition state information and depth is decremented. This goes on until depth equal \par }\pard\plain \s16\nowidctlpar\adjustright \lang2057 {\lang1053 \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\i\lang1053 TargetTooLowOrHigh }{\lang1053 search enhancement is described e.g. in [Chang]. \par -\par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\i QuickTricks}{ determines if the side to move can take one or more sure tricks. }{\lang1053 E.g. if the hand to move has an Ace in an NT contract, at least one sure trick can -be taken. +\par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\i QuickTricks}{ determines if the side to move can take one or more sure tricks. }{\lang1053 +E.g. if the hand to move has an Ace in an NT contract, at least one sure trick can be taken. \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 It is executed at the beginning of each trick, before any card has been played. A simple quick trick is also executed after the leading card of the trick is played.}{ \par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\lang1053 Assuming that the sure tricks are won by the side to move, then the conditions for search cutoff in }{\i\lang1053 TargetTooLowOrHigh}{\lang1053 are again tested to produce further search cutoffs. @@ -277,32 +277,33 @@ be taken. \par }{\i MoveOrdering. }{The alternative cards created by MoveGenerate are sorted, with the cards most likely to terminate the search fastest being sorted first in the move list.The allocation of card weights are described in detail in Chapter 5.}{\lang1053 \par -\par }{\i\lang1053 CheckMovesForCutoff }{\lang1053 checks if any of the moves just generated will -lead to a position that can be found in the transposition table. If so, an immediate Search return can be done, saving unnecessary search effort. This is further described in Chapter 6. +\par }{\i\lang1053 CheckMovesForCutoff }{\lang1053 checks if any of the moves just generated will lead to a position that can be found in the transposition table. If so, an immediate S +earch return can be done, saving unnecessary search effort. This is further described in Chapter 6. \par \par To my knowledge this is not described anywhere for usage in a DDS. It is described in [Plaat et al.] and named Enhanced Transposition Cutoffs. \par -\par At move search cutoff,}{\i\lang1053 MergeMoveData }{\lang1053 collects the union of the backed up accumulated winning ranks and the rank of the made move, assuming it did win by rank. The state data of the -position is updated with the collected information. +\par At move search cutoff,}{\i\lang1053 MergeMoveData }{\lang1053 +collects the union of the backed up accumulated winning ranks and the rank of the made move, assuming it did win by rank. The state data of the position is updated with the collected information. \par -\par }{\i\lang1053 MergeAllMovesData }{\lang1053 collects the union of the backed up accumulated winning ranks, the previous accumulated winning ranks of the alternative moves generated on this depth, and the rank of the made move, as -suming it did win by rank. When all alternative moves have been searched without a cutoff, the state data of the position is updated with the collected information. +\par }{\i\lang1053 MergeAllMovesData }{\lang1053 collects the un +ion of the backed up accumulated winning ranks, the previous accumulated winning ranks of the alternative moves generated on this depth, and the rank of the made move, assuming it did win by rank. When all alternative moves have been searched without a cu +toff, the state data of the position is updated with the collected information. \par -\par The information from }{\i\lang1053 MergeMoveData}{\lang1053 and }{\i\lang1053 MergeAllMovesData}{\lang1053 is later stored in the transposition table and determines which ranks that are essential when }{\i\lang1053 RetrieveTTresult}{\lang1053 - scans the set of positions in the transposition table. A match of ranks with the current position is only needed for winning ranks. See Chapter 7.}{\strike\cf6\lang1053 +\par The information from }{\i\lang1053 MergeMoveData}{\lang1053 and }{\i\lang1053 MergeAllMovesData}{\lang1053 is later stored in the transposition table and determines which ranks that are essential when }{\i\lang1053 RetrieveTTresult}{\lang1053 scans th +e set of positions in the transposition table. A match of ranks with the current position is only needed for winning ranks. See Chapter 7.}{\strike\cf6\lang1053 \par }{\lang1053 \par }{\i\lang1053 AddNewTTentry }{\lang1053 adds the evaluated position as a new entry in the transposition table. See Chapter 7. \par -\par }{\i\lang1053 NextMove }{\lang1053 filters out all \'94small\'94 cards except one per hand/suit combination. A \'94small\'94 card is a backed up card that is shown to never win by rank. The rest of the \'94small\'94 card moves fo -r the hand/suit combination are never searched, leading to a smaller search tree.\line This search enhancement was suggested by Hans Kuijf [Kuijf]. +\par }{\i\lang1053 NextMove }{\lang1053 filters out all \'94small\'94 cards except one per hand/suit combination. A \'94small\'94 card is a backed up card that is shown to never win by rank. The rest of the \'94small\'94 + card moves for the hand/suit combination are never searched, leading to a smaller search tree.\line This search enhancement was suggested by Hans Kuijf [Kuijf]. \par \par \par \par {\listtext\pard\plain\b \hich\af0\dbch\af0\loch\f0 3.\tab}}\pard \nowidctlpar\jclisttab\tx0\ls16\adjustright {\b\lang1053 The Quick Tricks cutoff algorithm \par }\pard \nowidctlpar\adjustright {\b\lang1053 \par }{\lang1053 The number of tricks that can immediately be taken by the side to play the leading card of the trick consists of: -\par {\pntext\pard\plain\hich\af0\dbch\af0\loch\f0 a)\tab}}\pard \fi-360\li360\nowidctlpar\tx360{\*\pn \pnlvlbody\ilvl0\ls3\pnrnot0\pnlcltr\pnstart1\pnindent360 {\pntxta )}}\ls3\adjustright {\lang1053 -The number of tricks that can be taken by the hand-to-play, and +\par {\pntext\pard\plain\hich\af0\dbch\af0\loch\f0 a)\tab}}\pard \fi-360\li360\nowidctlpar\tx360{\*\pn \pnlvlbody\ilvl0\ls3\pnrnot0\pnlcltr\pnstart1\pnindent360 {\pntxta )}}\ls3\adjustright {\lang1053 The number of tricks that can be taken +by the hand-to-play, and \par {\pntext\pard\plain\hich\af0\dbch\af0\loch\f0 b)\tab}}\pard \fi-360\li360\nowidctlpar\tx360{\*\pn \pnlvlbody\ilvl0\ls3\pnrnot0\pnlcltr\pnstart1\pnindent360 {\pntxta )}}\ls3\adjustright {\lang1053 The number of tricks that can be taken by the partner of the hand-to-play \par }\pard \nowidctlpar\adjustright {\lang1053 At return by }{\i\lang1053 QuickTricks}{\lang1053 , the position state information is updated with the winning ranks found. @@ -319,8 +320,8 @@ The number of tricks that can be taken by the partner of the hand-to-play \par The number of quick tricks for s is the suit length of partner. \par \par Else: -\par If the winning rank is in hand-to-play, - and the opponents cannot ruff, the number of quick tricks is incremented by one. Further, if the second best rank is also in hand-to-play, and the opponents cannot still ruff, the quick tricks is again incremented by one. +\par If the winning rank is in hand-to-play, and the opponents can +not ruff, the number of quick tricks is incremented by one. Further, if the second best rank is also in hand-to-play, and the opponents cannot still ruff, the quick tricks is again incremented by one. \par \par Else: \par If the winning rank is in partner and partner has winning rank as entry, the same applies for the partner as for the hand-to-play described above. @@ -353,39 +354,49 @@ If this still cannot cause a cutoff for the trick leading side, allocate one sur \par }{\lang1053 \par Quick tricks for the opponents of the leading hand are added when the opponents have one or more winning trumps. This idea was given by Pedja Stanojevic [Stanojevic].\line \line 1) If the opponent side have all the trumps, the number of sure tricks is the maximum suit length\line length, or\line -\par 2) If the opponent side has the highest trump, they have 1 sure trick. If they also have the second\line highest trump, they have 2 sure tricks, or\line \line -3) If the opponent side has the second highest trump plus at least one trump more behind the \line hand with the highest trump, the opponent side has 1 sure trick. +\par 2) If the opponent side has the highest trump, they have 1 sure trick. If they also have the second\line highest trump, they have 2 sure tricks, or\line \line 3) If the opponent side has the second highest trump plus at least one tr +ump more behind the \line hand with the highest trump, the opponent side has 1 sure trick. \par \page \par {\listtext\pard\plain\s3 \b \hich\af0\dbch\af0\loch\f0 5.\tab}}\pard\plain \s3\keepn\nowidctlpar\jclisttab\tx0\ls16\outlinelevel2\adjustright \b\lang1053 {The Move Ordering algorithm \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\b\lang1053 \par }{\lang1053 The weight of a card in the move list is affected by the suit and the rank of the card and by the other cards in the same trick. \par The weights of the cards in the move list are used to sort them, }{with the cards having the highest weight being sorted first in the list}{\lang1053 . \par -\par If the hand-to-play is trick leading hand or void in the suit played by leading hand, the card with the highest weight for each present suit will get a high additional bonus weight. After list resorting, those cards will -occupy the first positions in the move list. +\par If the hand-to-play is trick leading hand or void in the suit played by leading hand, the card with the highest weight + for each present suit will get a high additional bonus weight. After list resorting, those cards will occupy the first positions in the move list. \par -\par A "best move" is maintained for each searched depth. At a search (alpha-beta) cutoff, the move causing the cutoff overwrites the present "best move" for the current depth. - When a Transposition Table entry is created, the current best move is stored in that entry if: +\par Two "best moves" are maintained for each searched depth, one for an alpha-beta cutoff and one at a Transpos +ition Table entry match. At an alpha-beta cutoff, the move causing the cutoff overwrites the present "best move" for the current depth. When a Transposition Table entry is created, the current best move is stored in that entry if: \par The target is met and the leading hand belongs to the player\rquote s side, or target is not met and the leading hand belongs to the other side. Otherwise the best move is not stored in the Transposition Table entry. \par At a Transposition Table entry match, }{its stored best move will be best move for the current search depth.}{\lang1053 \par \par By \'94card move\'94 in the following pseudo code is meant the card by the hand-to-play that is getting a weight in the move list. }{\cf1\lang1053 The \'94card rank\'94 is a value in the range 2-14, corresponding to the card ranks 2 to the Ace. \par -\par }{\lang1053 For the determination of the weight, it is calculated whether or not the current card move is a card that wins the current trick for the side of the hand-to-play, assuming that both sides play their optimum cards. }{\cf1\lang1053 +\par }{\lang1053 For the determination of the weight, it is calculated whether or not the current card move is a card that wins the current trick for the side of the hand-to-play, assuming that both sides play their optimum cards. +\par +\par If the hand-to-play is void in the trick lead suit, the suit selected for the discard gets the following\line bonus: +\par +\par suitAdd = ((suit length) * 64)/36; +\par +\par If the suit length is 2, and the hand-to-play has the next highest rank of the suit, the bonus \line (suitAdd) is subtracted by 2. }{\cf1\lang1053 \par }{\fs20\lang1053 \par \par }\pard\plain \s2\keepn\nowidctlpar\outlinelevel1\adjustright \lang2057 {\ul\lang1053 Hand-to-play is trick leading hand \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 \par The contribution of the suit to the weight: \par -\par suitWeightDelta = suitBonus - (countLH+countRH) * 2 +\par }\pard\plain \s16\nowidctlpar\adjustright \lang2057 {\lang1053 suitWeightDelta = suitBonus \endash ((countLH+countRH) * 32)/15 +\par }\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 +\par suitBonus has the initial value 0, changed if conditions below apply: \par -\par If trump contract, and the suit is not trump, then there is a (negative) suitBonus of \endash 12 if +\par If trump contract, and the suit is not trump, then there is a (negative) suitBonus change of \endash 10 if \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\nowidctlpar\tx360{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360 {\pntxtb \'b7}}\ls2\adjustright {\lang1053 LHO is void and LHO has trump card(s), or \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\nowidctlpar\tx360{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360 {\pntxtb \'b7}}\ls2\adjustright {\lang1053 RHO is void and RHO has trump card(s) -\par }\pard \nowidctlpar\adjustright {\lang1053 -\par Otherwise, suitBonus = 0. +\par }\pard \nowidctlpar\tx360\adjustright {\lang1053 \line If RHO has either the highest rank of the suit played by hand-to-play or the next highest rank, +\par then there is a suitBonus change of \endash 18. \par +\par If it is a trump contract, the suit is not trump, own hand has a singleton, own hand has at least one trump, partner has the highest rank in the suit and at least a suit length of 2, then there is a suitBonus change of +16. +\par }\pard \nowidctlpar\adjustright {\lang1053 \par countLH = (suit length of LHO) * 4, if LHO is not void in the suit, \par countLH = (depth + 4), if LHO is void in the suit \par @@ -412,36 +423,40 @@ occupy the first positions in the move list. \par else \par weight = suitWeightDelta + 35 \endash (rank of card move) \par \} -\par else if (card move include equivalent card(s) in the suit) -\par weight = suitWeightDelta + 40 \endash (rank of card move) +\par else if (hand-to-play has second highest rank together with equivalent card(s) in suit) +\par weight = suitWeightDelta + 40 \par else \par weight = suitWeightDelta + 30 \endash (rank of card move) -\par if (the card move is \'94best move\'94 as obtained at search cutoff) -\par weight = weight + 50; +\par if (the card move is \'94best move\'94 as obtained at alpha-beta cutoff) +\par weight = weight + 52; +\par if (the card move is \'94best move\'94 as obtained from a Transposition Table entry match) +\par weight = weight + 11; \par \} \par else \{\tab /* Not a trick winning move */ \par if (either LHO or RHO has singleton in suit which has highest rank) -\par weight = suitWeightDelta + 20 \endash (rank of card move) +\par weight = suitWeightDelta + 29 \endash (rank of card move) \par else if (hand-to-play has highest rank in suit) \{ \par if (partner has second highest rank in suit) -\par weight = suitWeightDelta + 35 \endash (rank of card move) +\par weight = suitWeightDelta + 44 \endash (rank of card move) \par else if (the card move is the card with highest rank in the suit) -\par weight = suitWeightDelta + 16 +\par weight = suitWeightDelta + 25 \par else -\par weight = suitWeightDelta + 4 \endash (rank of card move) +\par weight = suitWeightDelta + 13 \endash (rank of card move) \par \} \par else if (partner has highest rank in suit) \{ \par if (hand-to-play has second highest rank in suit) -\par weight = suitWeightDelta + 35 \endash (rank of card move) +\par weight = suitWeightDelta + 44 \endash (rank of card move) \par else -\par weight = suitWeightDelta + 20 \endash (rank of card move) +\par weight = suitWeightDelta + 29 \endash (rank of card move) \par \} \par else if (hand-to-play has second highest rank together with equivalent card(s) in suit) -\par weight = suitWeightDelta + 20 \endash (rank of card move) +\par weight = suitWeightDelta + 29 \par else -\par weight = suitWeightDelta + 4 \endash (rank of card move) -\par if (the card move is \'94best move\'94 as obtained at search cutoff) -\par weight = weight + 30; +\par weight = suitWeightDelta + 13 \endash (rank of card move) +\par if (the card move is \'94best move\'94 as obtained at alpha-beta cutoff) +\par weight = weight + 20; +\par if (the card move is \'94best move\'94 as obtained from a Transposition Table entry match) +\par weight = weight + 9; \par \} \par \par @@ -450,9 +465,9 @@ occupy the first positions in the move list. \par if (trick winning card move) \{ \par if (hand-to-play void in the suit played by the leading hand) \{ \par if (trump contract and trump is equal to card move suit) -\par }{\cf1\lang1053 weight = 30 - (rank of card move) + 2 * (suit length for card move suit) +\par }{\cf1\lang1053 weight = 30 - (rank of card move) + suitAdd \par else -\par weight = 60 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = 60 - (rank of card move) + suitAdd \par \} \par else if (lowest card for partner to leading hand is higher than LHO played card) \par weight = 45 - (rank of card move) @@ -482,9 +497,9 @@ occupy the first positions in the move list. \par else \{\tab /* card move is not trick winning */ \par }{\lang1053 if (hand-to-play void in the suit played by the leading hand) \{ \par if (trump contract and trump is equal to card move suit)}{\cf1\lang1053 -\par }{\lang1053 }{\cf1\lang1053 weight = 15 - (rank of card move) + 2 * (suit length for card move suit) +\par }{\lang1053 }{\cf1\lang1053 weight = 15 - (rank of card move) + suitAdd \par else -\par weight = - (rank of card move) + 2 * (suit length for card move suit) +\par weight = - (rank of card move) + suitAdd \par \} \par else if (lowest card for partner to leading hand or for RHO in the suit played is higher \line than played card for LHO) \par weight = - (rank of card move) @@ -506,16 +521,16 @@ occupy the first positions in the move list. \par if (hand-to-play void in the suit played by the leading hand) \{ \par if (card played by the leading hand is highest so far) \{ \par if (card by hand-to-play is trump and the suit played by the leading hand is not trump) -\par }{\cf1\lang1053 weight = 30 - (rank of card move) + 2 * (suit length for card move suit) +\par }{\cf1\lang1053 weight = 30 - (rank of card move) + suitAdd \par else -\par weight = 60 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = 60 - (rank of card move) + suitAdd \par \} \par else if (hand-to-play is on top by ruffing) -\par weight = 70 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = 70 - (rank of card move) + suitAdd \par else if (hand-to-play discards a trump but still loses) -\par weight = 15 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = 15 - (rank of card move) + suitAdd \par else }{\lang1053 -\par }{\cf1\lang1053 weight = 30 - (rank of card move) + 2 * (suit length for card move suit) +\par }{\cf1\lang1053 weight = 30 - (rank of card move) + suitAdd \par \} \par else }{\lang1053 \par }{\cf1\lang1053 weight = 60 - (rank of card move) @@ -523,11 +538,11 @@ occupy the first positions in the move list. \par else \{ /* card move is not trick winning */ \par }{\lang1053 if (hand-to-play void in the suit played by the leading hand) \{ \par }{\cf1\lang1053 if (hand-to-play is on top by ruffing) -\par weight = 40 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = 40 - (rank of card move) + suitAdd \par else if (hand-to-play underruffs */ -\par weight = -15 - (rank of card move) + 2 * (suit length for card move suit) +\par weight = -15 - (rank of card move) + suitAdd \par else -\par weight = - (rank of card move) + 2 * (suit length for card move suit) +\par weight = - (rank of card move) + suitAdd \par \} \par else \{ \par if (the card by hand-to-play is highest so far) \{ @@ -548,16 +563,16 @@ occupy the first positions in the move list. \par }{\lang1053 if (hand-to-play is void in leading suit) \{ \par if (LHO has current highest rank of the trick) \{ \par if (card move ruffs) -\par weight = 14- (rank of card move) + 2 * (suit length for card move) +\par weight = 14- (rank of card move) + suitAdd \par else -\par weight = 30- (rank of card move) + 2 * (suit length for card move) +\par weight = 30- (rank of card move) + suitAdd \par }{\fs20\lang1053 \} \par }{\lang1053 else if (hand-to-play ruffs and wins) -\par }{\fs20\lang1053 }{\lang1053 weight = 30- (rank of card move) + 2 * (suit length for card move) +\par }{\fs20\lang1053 }{\lang1053 weight = 30- (rank of card move) + suitAdd \par else if (card move suit is trump, but not winning) \par weight = - (rank of card move) \par else -\par weight = 14- (rank of card move) + 2 * (suit length for card move) +\par weight = 14- (rank of card move) + suitAdd \par \} \par else if (LHO has current winning move) \{ \par if (RHO ruffs LHO\rquote s winner) @@ -579,7 +594,7 @@ occupy the first positions in the move list. \par {\listtext\pard\plain\b \hich\af0\dbch\af0\loch\f0 6.\tab}}\pard \nowidctlpar\jclisttab\tx0\ls16\adjustright {\b\lang1053 Algorithm to try early cutoff for generated moves \par }\pard \nowidctlpar\adjustright {\b\lang1053 \par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\lang1053 After generating moves at the end of a trick, they are each checked to see if one of them will lead to a position that already is stored in the Transposition Table. -\par Due to the processing overhead, this check is only made if the depth is 29 or more (i.e there are at least 33 cards in the position). +\par Due to the processing overhead, this check is only made if the depth is 33 or more (i.e there are at least 33 cards in the position). \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 Pseudo code: \par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \lang2057 {\lang1053 \par moveExists = TRUE; @@ -603,8 +618,8 @@ occupy the first positions in the move list. \par \par {\listtext\pard\plain\b \hich\af0\dbch\af0\loch\f0 7.\tab}}\pard \nowidctlpar\jclisttab\tx0\ls16\adjustright {\b\lang1053 Storage and retrieval of position state data in the Transposition Table \par }\pard\plain \s16\nowidctlpar\tx360\adjustright \lang2057 {\lang1053 }{\b\lang1053 \line }{\cf1\lang1053 -Positions stored in the Transposition Table always consist of completed tricks. Positions stored start at depth=4, then 8,12, and so on. The information stored is information on won cards, the suit lengths of t -he hands, the hand to play the leading card in the position and upper and lower bounds for the number of future tricks to be taken by the side of the player. +Positions stored in the Transposition Table always consist of completed tricks. Positions stored start at depth=4, then 8,12, and so on. The information stored is information on won cards, th +e suit lengths of the hands, the hand to play the leading card in the position and upper and lower bounds for the number of future tricks to be taken by the side of the player. \par \par Starting from issue 1.1.8, each \'94winning cards node\'94 contain all winning cards for one suit after an idea by Jo\'ebl Bradmetz. This new solution is faster.}{\b\cf1 \line }{\b\cf1\lang1053 \par }\pard\plain \nowidctlpar\adjustright \lang2057 {\b\lang1053 7.1 Transposition Table storing winning card ranks @@ -620,12 +635,12 @@ he hands, the hand to play the leading card in the position and upper and lower \par Trick 13: spade x, diamond x, diamond x, diamond x \par where x is any rank below lowest winning rank. \par -\par The cards that win by rank are recorded during the search and backed up similarly to the search value. If a card wins by rank and there are equivalent cards, e.g. only spade A is searched from a sequence of AKQ, then also the othe -r cards K and Q must be recorded as having won by rank. +\par The cards that win by rank are recorded during the search and backed up similarly to the search value. If a card wins by rank and there are equivalent cards, e.g. only spade A is searched from a sequence o +f AKQ, then also the other cards K and Q must be recorded as having won by rank. \par -\par The cards winning by rank are stored in the Transposition Table as relative ranks, however any rank larger than the lowest winning rank in the suit are also stored as \'94winning ranks\'94. Using relative -ranks rather than absolute ranks considerably increases the number of positions that match this Transposition Table entry:\line -As an example, assume that there are only 4 cards left in a suit, A, Q, 9, 7 where each hand has one card in the suit. Then any combination of ranks, e.g. 8, 6, 3, 2 that preserves the relative order of ranks between hands will cause a match. +\par The cards winning by rank are stored in the Transposition Table as relative ranks, however any rank larger than the lowest winning rank in the suit are also stored as \'94winning ranks\'94 +. Using relative ranks rather than absolute ranks considerably increases the number of positions that match this Transposition Table entry:\line As an example, assume that there are only 4 cards left in a suit, A, Q, 9, 7 where each hand has one card in + the suit. Then any combination of ranks, e.g. 8, 6, 3, 2 that preserves the relative order of ranks between hands will cause a match. \par \par In the state position information absolute ranks are used, it is only in the Transposition Table where the ranks are stored as relatives. \par @@ -647,13 +662,14 @@ As an example, assume that there are only 4 cards left in a suit, A, Q, 9, 7 whe \par \par }\pard \nowidctlpar\tx420\adjustright {\cf1\lang1053 The "Transposition Table" has a tree structure rather than a table, consisting of 2 interconnected trees. \par For deciding if there is a match, input is the position state data, including the cards left to play and the current leading hand. -\par There are \'94root pointers\'94 per number of tricks left and per leading hand which each points to the root of a tree of \'94suit lengths combination\'94 nodes. Each such -node includes a 64-bit code that uniquely defines one combination of suit lengths for the hands. The nodes are ordered such that the value of the 64-bit code in a parent node is higher than the 64-bit code of its left child but lower than the 64-bit code -of its right child. So to find the node with the suit lengths combination for the actual position, a binary search is made. The basic binary search algorithm is described in [Knuth]. +\par There are \'94root pointers\'94 per number of tricks left and per leading hand which each points to the root of a tree of \'94suit lengths combination\'94 + nodes. Each such node includes a 64-bit code that uniquely defines one combination of suit lengths for the hands. Th +e nodes are ordered such that the value of the 64-bit code in a parent node is higher than the 64-bit code of its left child but lower than the 64-bit code of its right child. So to find the node with the suit lengths combination for the actual position, +a binary search is made. The basic binary search algorithm is described in [Knuth]. \par Each \'94suit length combination node\'94 points to the root of a tree consisting of \'94winning cards nodes\'94, ie. cards that win by rank. (So the Transposition Table is really a number of trees, a forest.) -\par When a position is checked for a possible Transposition Table match, a tree branch is selected consisting of 4 subsequent \'94winning cards nodes\'94, each \'94winning cards node\'94 - includes an aggregate of all winning cards for one suit. This branch is followed as long as the \'94winning cards\'94 also can be found in the current position. (Note that the ranks of the \'94winning card nodes\'94 are relative -, so the ranks of the current position must first be translated from absolute to relative ranks.) When the \'94winning cards node\'94 no longer matches with the current position and there is no other alternative \'94winning cards node\'94 +\par When a position is checked for a possible Transposition Table match, a tree branch is selected consisting of 4 subsequent \'94winning cards nodes\'94, each \'94winning cards node\'94 includes an aggregate of all winning cards for one suit. Th +is branch is followed as long as the \'94winning cards\'94 also can be found in the current position. (Note that the ranks of the \'94winning card nodes\'94 + are relative, so the ranks of the current position must first be translated from absolute to relative ranks.) When the \'94winning cards node\'94 no longer matches with the current position and there is no other alternative \'94winning cards node\'94 that fits, then the search backs up and tries an alternative \'94winning cards node\'94 on a higher level. \par \line When the last of the 4 subsequent \'94winning cards nodes\'94 containing clubs is reached, it points to a \'94set of positions node\'94. Its stored upper and lower value bounds are checked against the number of tricks won so far by the player \rquote s side and the target value. The following conditions are then checked, assuming that it is the North/South side that is the player\rquote s side: @@ -674,16 +690,15 @@ s side in the current position. Search on this depth is terminated and FALSE is \par \par For all other cases, the search continues for the current depth. \par -\par For example, take the previous example with 2 - tricks remaining with spade rank order 1 at North. (Rank order 1 is highest rank.) The hearts have rank orders 1 at North, 2 at East, 3 at South and 4 at West. The diamond rank orders are orders 1 at East, 2 at South and 3 at West. North is leading han -d. +\par For example, take the previous example with 2 tricks remaining with spade rank order 1 at North. (Rank order 1 is highest rank.) The hearts have + rank orders 1 at North, 2 at East, 3 at South and 4 at West. The diamond rank orders are orders 1 at East, 2 at South and 3 at West. North is leading hand. \par The \'94root pointer\'94 is now defined by the number of tricks remaining (=2) and North as leading hand. -\par The \'94root pointer\'94 points to the root node of its \'94suit lengths combination\'94 tree. The 64-bit integer coded from the suit lengths for all suits and hands -is now searched within the tree. When the node is found with matching 64-bit suit lengths code, this node will point to the root of its \'94winning card\'94 tree. +\par The \'94root pointer\'94 points to the root node of its \'94suit lengths combination\'94 + tree. The 64-bit integer coded from the suit lengths for all suits and hands is now searched within the tree. When the node is found with matching 64-bit suit lengths code, this node will point to the root of its \'94winning card\'94 tree. \par This pointer points to a "winning cards node" containing spade rank order 1 at North which fits with the current position. This \'94winning cards node\'94 - points to another "winning cards node" containing hearts rank orders 1 at North and 2 at East which also fits the current position. Next \'94winning cards node\'94 pointed to contains diamonds order 1 at South, -which does not match the current position. However, there is an alternative \'94winning cards node\'94 that has diamonds order 1 at East, which fits. (If there had been no alternative \'94winning cards node\'94 - which fitted, the search had backed up to the previous \'94winning cards node\'94 to see if there was an alternative \'94winning cards node\'94 on this level which also fitted.) The next \'94winning cards node\'94 + points to another "winning cards node" containing hearts rank orders 1 at North and 2 at East which also fits the current position. Next \'94winning cards node\'94 + pointed to contains diamonds order 1 at South, which does not match the current position. However, there is an alternative \'94winning cards node\'94 that has diamonds order 1 at East, which fits. (If there had been no alternative \'94winning cards node +\'94 which fitted, the search had backed up to the previous \'94winning cards node\'94 to see if there was an alternative \'94winning cards node\'94 on this level which also fitted.) The next \'94winning cards node\'94 pointed to is for clubs. This node is empty, which fits the current position which have no clubs. \par This \'94winning cards node\'94 points to a "set of positions node\'94 which have upper and lower value bounds defined. The conditions for these bounds are assumed to be fulfilled causing search termination on this depth, as described earlier. \par @@ -699,19 +714,19 @@ fffffffffffffffffdffffff1b000000fefffffffeffffff05000000060000000700000008000000 00001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b000000fefffffffeffffff 3e0000003f0000004000000041000000420000004300000044000000450000004600000047000000feffffff490000004a0000004b0000004c0000004d0000004e0000004f000000feffffff51000000520000005300000054000000550000005600000057000000feffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff040000000709020000000000c000000000000046000000000000000000000000f025 -436acf10c90103000000400100000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff040000000709020000000000c00000000000004600000000000000000000000090b1 +f73983d8ca0103000000400100000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 0000000000000000000000001400000000000000440061007400610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0002010100000003000000ffffffff0000000000000000000000000000000000000000000000000000 0000000000000000000004000000001000000000000031005400610062006c006500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000201ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 0000000000000000000000000c0000001c1d000000000000feffffff02000000fefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000020000000000000000000000000000000048023400ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0100feff030a0000ffffffff0709020000000000c0000000000000460a00 -0000576f72642d62696c64000a0000004d53576f7264446f63000f000000576f72642e506963747572652e3800f439b271000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000300ffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000001000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16020000440064000000000000000200000000000000000000000000de024e023802380200000000000000000000000000000000000000000000000000000000000000000f0004f03c000000b2040af0080000003004 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000020000000000000000000000000000000038899303000000000000000000000000000000000000000000000000000000000000000000000000000000000100feff030a0000ffffffff0709020000000000c0000000000000460a00 +0000576f72642d62696c64000a0000004d53576f7264446f63000f000000576f72642e506963747572652e3800f439b27100000000000000000000000000000000000000000000000000000000000000000000000000cb3b0000422a00000000000000000300000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff3c0000003c00000060150c0660150c0600000000000000006015 +0c06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000716000000000000192b0180ffffffff00000000000000000000000000000000000000000000000098670000ffffffffffffffff0100000001000000 +18000000ffffffff1800000000000000010000000200000000000000006f000071000071f0dd030016020000440064000000000000000200000000000000000000000000de024e023802380200000000000000000000000000000000000000000000000000000000000000000f0004f03c000000b2040af0080000003004 0000000a000043000bf018000000044107000000810111000010bf0100001000ff0100000800000010f004000000000000c0320007f0860100000304bd0271d6ceffbe413ae425c4c635b470ff0062010000040000004400000000002f0160211bf05a010000bd0271d6ceffbe413ae425c4c635b470ec010000feff0000 ffff0000970001007a000100181d0700e8b705002801000000fe789c6d91bd4a034110c7ff3bb7d124063d35a451c26191548af8043e805aa8905af422575c0e72c1235adb585909f63e84858d2f213e8485205aa8b8cecc2646c181b99dcfdfccee195480e00d4009cb10a9b3b6a6e6d08463b1ea77b2fed12cb693c37e 9667dd41247e89e333e4dc9713ab4667b856c207859856d21dc9d710adec0df3419c025be5ee3950450b17467232e1f1691196ed55233b006424e5490f4e41b8d46abb8985fd248df368272ea2dd2c3de8e1f6e6a5b8678dd65f0ba17b92515245e74f98b2d527e954a16925a1cce73b47033f8a7c3cd0ea253bc495eef9 @@ -807,7 +822,7 @@ f0040000002400000000000df004000000000015000f0004f054000000a20c0af008000000e20400 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010043006f006d0070004f0062006a00000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000120002010200000006000000ffffffff000000000000000000000000000000000000000000000000000000000000000000000000010000005b0000000000000003004f0062006a0049006e0066006f0000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000012000201ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000300000004000000000000004f0062006a0065006300740050006f006f006c0000000000 -00000000000000000000000000000000000000000000000000000000000000000000000000000000160001010500000008000000ffffffff0000000000000000000000000000000000000000f025436acf10c901f025436acf10c90100000000000000000000000002004f006c0065005000720065007300300030003000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000160001010500000008000000ffffffff000000000000000000000000000000000000000090b1f73983d8ca0190b1f73983d8ca0100000000000000000000000002004f006c0065005000720065007300300030003000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000018000201ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000001c000000ee3e000000000000ffffffff030000000400000001000000ffffffff 00000000000000006d440000673a0000c63e0000010009000003631f000008003100000000001400000026060f001e00ffffffff040014000000576f72640e004d6963726f736f667420576f7264050000000b0200000000050000000c02cc0d2a101c000000fb021000070000000000bc02000000000102022253797374 656d0000640e666f00000a0022008a0100000000ffffffff48d41200040000002d010000050000000201010000001c000000fb02adff0000000000009001000000000440001254696d6573204e657720526f6d616e0030cb120010da1c76c0601f76640e666f040000002d01010005000000090200000000050000000201 @@ -936,9 +951,9 @@ f701000076070000e0030000c007000008000000fa0200000600000000000000040000002d010500 0400000000002a10cc0d6f6e65202a00290025001500050000002e01000000000500000014020000000005000000140294025f05050000002e010100000011000000320a94025f0504000400000000002a10cc0d737569742100290017001700050000002e01000000000500000014020000000005000000020101000000 05000000020101000000050000001402f6024a01050000002e010100000028000000320af6024a0113000400000000002a10cc0d6c656e6774687320636f6d62696e6174696f6e031700250029002a0017002a002000150025002b003f002a00180029002500170017002a002900050000002e0100000000050000001402 0000000005000000020101000000040000002701ffff1000000026060f001600ffffffff0000430100009a03000078020000cf04000008000000fa0200000600000000000000040000002d010500040000002d010600080000002503020073029e0373019e04040000002d01030004000000f001050007000000fc020000 -000000000000040000002d0105000a000000240303005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d0100000300000000001604490ac9049b091a0405000000020101000000040000002d01010005000000090200000000 -0500000014029e091a04050000002e010100000010000000320a9e091a0403000400000000002a10cc0d57696e034f0017002900050000002e01000000000500000014020902640e05000000020101000000040000002701ffff07000000fc020000ffffff000000040000002d01050008000000fa020000060000000000 -0002040000002d010600070000001b04130814082207e706040000002d01040004000000f0010500040000002d01020004000000f0010600030000001e00070000001604f107d5074307260705000000020101000000040000002d0101000500000009020000000005000000140257006f007200640044006f0063007500 +000000000000040000002d0105000a000000240303005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d0100000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057006f007200640044006f0063007500 6d0065006e007400000000000000000000000000000000000000000000000000000000000000000000000000000000001a000200070000000a000000ffffffff0000000000000000000000000000000000000000000000000000000000000000000000003d0000001e140000000000005200690063006800450064006900 740046006c0061006700730000000000000000000000000000000000000000000000000000000000000000000000000000001c000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000040000000c000000000000000500530075006d006d006100 7200790049006e0066006f0072006d006100740069006f006e00000000000000000000000000000000000000000000000000000028000201090000000b000000ffffffff000000000000000000000000000000000000000000000000000000000000000000000000480000000010000000000000050044006f0063007500 @@ -983,11 +998,11 @@ e5060000e60600001e0700001f070000200700000000000000000000000000000000000000000000 0000d9060000de060000df060000e4060000e5060000e60600001e0700001f0700002007000021070000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd0000000000 00000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd00 0000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd000000000000000000000000fd0000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000191c001fb0cc4e20b0c04e21b0001422b001142390d2162490d21625b00000000011000000320a9402d20404000400000000002a10cc0d -6f6e65202a00290025001500050000002e01000000000500000014020000000005000000140294025f05050000002e010100000011000000320a94025f0504000400000000002a10cc0d737569742100290017001700050000002e0100000000050000001402000000000500000002010100000005000000020101000000 -050000001402f6024a01050000002e010100000028000000320af6024a0113000400000000002a10cc0d6c656e6774687320636f6d62696e6174696f6e031700250029002a0017002a002000150025002b003f002a00180029002500170017002a002900050000002e010000000005000000140200000000050000000201 -01000000040000002701ffff1000000026060f001600ffffffff0000430100009a03000078020000cf04000008000000fa0200000600000000000000040000002d010500040000002d010600080000002503020073029e0373019e04040000002d01030004000000f001050007000000fc02000000000000000004000000 -2d0105000a000000240303005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d0100000300000000003a07feff0000060002000000000000000000000000000000000001000000e0859ff2f94f6810ab9108002b27b3d93000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000191c001fb0cc4e20b0c04e21b0001422b001142390d2162490d21625b00000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000feff0000060002000000000000000000000000000000000001000000e0859ff2f94f6810ab9108002b27b3d93000 0000580100001000000001000000880000000200000090000000030000009c00000004000000a800000005000000bc00000007000000c800000008000000d800000009000000ec00000012000000f80000000a000000140100000c000000200100000d0000002c0100000e000000380100000f0000004001000010000000 48010000130000005001000002000000e40400001e00000001000000000073001e00000001000000000073001e0000000b000000426f204861676c756e6400001e00000001000000006f20481e000000070000004e6f726d616c00751e0000000b000000426f204861676c756e6400001e00000002000000320020481e00 0000130000004d6963726f736f667420576f726420382e3000004000000000000000000000004000000000f475e11886c8014000000000f475e11886c80103000000010000000300000000000000030000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000 @@ -1183,7 +1198,7 @@ ffff1000000026060f001600ffffffff0000430100009a03000078020000cf04000008000000fa02 03005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d010000030000000000}{\result {\f1\fs20\lang1053 {\pict{\*\picprop\shplid1025{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}} {\sp{\sn fFlipV}{\sv 0}}{\sp{\sn pictureGray}{\sv 0}}{\sp{\sn pictureBiLevel}{\sv 0}}{\sp{\sn pictureActive}{\sv 0}}{\sp{\sn fillColor}{\sv 268435473}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fHitTestFill}{\sv 1}}{\sp{\sn fillShape}{\sv 1}} {\sp{\sn fillUseRect}{\sv 0}}{\sp{\sn fNoFillHitTest}{\sv 0}}{\sp{\sn fLine}{\sv 0}}}\picscalex98\picscaley98\piccropl0\piccropr0\piccropt0\piccropb0 -\picw17517\pich14951\picwgoal9931\pichgoal8476\wmetafile8\bliptag727381266\blipupi-134{\*\blipuid 2b5af512977e26a1359b4bd3c0edc104} +\picw17517\pich14951\picwgoal9931\pichgoal8476\wmetafile8\bliptag21317130\blipupi-134{\*\blipuid 0145460ab0e156603b98478d583ea052} 010009000003631f000008003100000000001400000026060f001e00ffffffff040014000000576f72640e004d6963726f736f667420576f7264050000000b02 00000000050000000c02cc0d2a101c000000fb021000070000000000bc02000000000102022253797374656d0000640e666f00000a0022008a0100000000ffff ffff48d41200040000002d010000050000000201010000001c000000fb02adff0000000000009001000000000440001254696d6573204e657720526f6d616e00 @@ -1434,7 +1449,7 @@ fc020000ffffff000000040000002d01050008000000fa0200000600000000000002040000002d01 2a0017002a002000150025002b003f002a00180029002500170017002a002900050000002e010000000005000000140200000000050000000201010000000400 00002701ffff1000000026060f001600ffffffff0000430100009a03000078020000cf04000008000000fa0200000600000000000000040000002d0105000400 00002d010600080000002503020073029e0373019e04040000002d01030004000000f001050007000000fc020000000000000000040000002d0105000a000000 -240303005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d01000003000000000000000000000000000000000000000000}}}}}{\lang1053 +240303005e0185044701ca048c01b304040000002d010200040000002d01040004000000f00105000800000026060f000600ffffffff0100040000002d0100000300000000000000000000000000000000000000000000000000}}}}}{\lang1053 \par The \'94suit lengths combination\'94 node includes: \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\nowidctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls14\adjustright {\lang1053 The suit lengths combination as a 64-bit integer. @@ -1451,8 +1466,8 @@ suit lengths combination node\'94 in the binary tree. \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-720\li720\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3 {\pntxtb \'b7}}\ls4\adjustright {\lang1053 A pointer to the next winning cards node required to achieve a Transposition Table match for this branch of the tree. \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-720\li720\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3 {\pntxtb \'b7}}\ls4\adjustright {\lang1053 A pointer to the previous winning cards node. -\par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-720\li720\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3 {\pntxtb \'b7}}\ls4\adjustright {\lang1053 A pointer to the next alternative winning cards node that leads to a T -ransposition Table match in an alternative tree branch. +\par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-720\li720\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3 {\pntxtb \'b7}}\ls4\adjustright {\lang1053 A pointer to the next alternative winning cards n +ode that leads to a Transposition Table match in an alternative tree branch. \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\nowidctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls10\adjustright {\lang1053 A pointer to the "set of positions node". \par }\pard \nowidctlpar\adjustright {\lang1053 @@ -1464,13 +1479,12 @@ An upper and a lower bound for the winning tricks of the North/South side. These \par {\pntext\pard\plain\f3 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-720\li720\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3 {\pntxtb \'b7}}\ls4\adjustright {\lang1053 The suit and rank for the currently best move. \par }\pard \nowidctlpar\adjustright {\lang1053 \par -\par }\pard \nowidctlpar\tx420\adjustright {\cf1\lang1053 After a Transposition Table match, the current position may later be part of a position that will be -stored in the Transposition Table. Therefore, the stored winning ranks in the Transposition Table must be included in the state information of the current position. However, the winning ranks cannot be taken as is, because they are stored as relative rank -s which now must be converted to absolute ranks in the current position. +\par }\pard \nowidctlpar\tx420\adjustright {\cf1\lang1053 +After a Transposition Table match, the current position may later be part of a position that will be stored in the Transposition Table. Therefore, the stored winning ranks in the Transposition Table must be included in the state information of the current + position. However, the winning ranks cannot be taken as is, because they are stored as relative ranks which now must be converted to absolute ranks in the current position. \par This is done using the lowest winning relative rank for each suit that is stored in the \'94set of positions\'94 node that gave the Transposition Table match: -\par The aggregated set of (absolute -) ranks for each suit in the current position is filtered using the stored information on the lowest winning relative rank. The winning ranks for each suit is then the aggregated set with only the number of highest ranks implied by the stored lowest winni -ng relative rank in the \'94set of positions\'94 node. +\par The aggregated set of (absolute) ranks for each suit in the current position is filtered using the stored information on the lowest winning relative rank. The winning ranks for each suit + is then the aggregated set with only the number of highest ranks implied by the stored lowest winning relative rank in the \'94set of positions\'94 node. \par E.g. if the aggregated rank set for spades is A J 9 4 2 and lowest winning relative rank is order=2, then winning ranks are A J. \par }\pard \nowidctlpar\adjustright {\lang1053 \par @@ -1485,15 +1499,16 @@ ng relative rank in the \'94set of positions\'94 node. \par The next step is to search for a \'94winning card node\'94 that has the \'94suit length combination node\'94 as parent. This \'94winning card node\'94 has then winning cards for spades. \par If no such node yet exists, \'94winning card nodes\'94, one for each suit, are created using the winning cards of the current position. Each such node includes all winning cards for one of the suits. Then, a \'94set of positions\'94 node is created. This node is pointed to from the last created \'94winning card node\'94 created for the winning cards of clubs. -\par Otherwise, if there already exists a matching \'94winning card node\'94 with the \'94suit length combination node\'94 as parent, it is checked whether or not the \'94winning card nodes\'94 in a subsequent tree branch already created for - hearts, diamonds and clubs also are matched with the current position. +\par Otherwise, if there already exists a matching \'94winning card node\'94 with the \'94suit length combination node\'94 as parent, it is checked whether or not the \'94winning card nodes\'94 + in a subsequent tree branch already created for hearts, diamonds and clubs also are matched with the current position. \par If such a sequence of nodes can be found, the upper or lower bound in the connected \'94set of positions node\'94 may be updated to allow for an increased number of cutoffs: \par \par If the current position upper value bound is less than the stored upper value bound, the stored value is updated with the current position value. \par If the current position lower value bound is larger than the stored lower value bound, the stored value is updated with the current position value. \par -\par In case a matching \'94winning card node\'94 cannot be found, a new \'94winning card node\'94 is created and linked to the last matching node. E.g. if existing \'94winning card nodes\'94 for spades and hearts match the current position, but no n -ode match for diamonds, then a \'94winning cards node\'94 for diamonds is created and linked to the previous \'94winning cards node\'94 for hearts. Then a clubs \'94winning cards node\'94 and a \'94set of positions node\'94 are created. +\par In case a matching \'94winning card node\'94 cannot be found, a new \'94winning card node\'94 is created and linked to the last matching node. E.g. if existing \'94winning card nodes\'94 + for spades and hearts match the current position, but no node match for diamonds, then a \'94winning cards node\'94 for diamonds is created and linked to the previous \'94winning cards node\'94 for hearts. Then a clubs \'94winning cards node\'94 and a +\'94set of positions node\'94 are created. \par \par \par }\pard \nowidctlpar\adjustright {\b\lang1053 @@ -1505,38 +1520,38 @@ ode match for diamonds, then a \'94winning cards node\'94 for diamonds is create \par Source code for a simple DDS. \par }{\field\fldedit{\*\fldinst {\lang1053 HYPERLINK \\l "_Hlk134153111" }{\fs20\lang1053 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0048006c006b00310033003400310035003300310031003100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -000000}}}{\fldrslt {\cs15\ul\cf2 http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm}}}{\lang1053 +00000000000000}}}{\fldrslt {\cs15\ul\cf2 http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm}}}{\lang1053 \par \par Matthias Brill: \par DDS algorithms description (in German) and DDS source code. \par }{\field\fldedit{\*\fldinst {\lang1053 HYPERLINK \\l "_Hlk134153080" }{\fs20\lang1053 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0048006c006b00310033003400310035003300300038003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -000000}}}{\fldrslt {\ul\cf2 http://linux.softpedia.com/get/Science-and-Engineering/Artificial-Intelligence/cddsolve-20055.shtml}{\lang1053 }}}{\lang1053 +00000000000000}}}{\fldrslt {\ul\cf2 http://linux.softpedia.com/get/Science-and-Engineering/Artificial-Intelligence/cddsolve-20055.shtml}{\lang1053 }}}{\lang1053 \par \par Ming-Sheng Chang: \par DDS algorithms description. \par {\*\bkmkstart _Hlt193293965}}{\field\fldedit{\*\fldinst {\lang1053 HYPERLINK "\\\\l "_Hlk132979785" "}{\fs20\lang1053 {\*\datafield 00d0c9ea79f9bace118c8200aa004ba90b02000000010000000303000000000000c0000000000000460000040000005c6c2000ffffadde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {cs.nyu.edu/web/Research/TechReports/TR1996-725/TR1996-725.ps.gz +000000000000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {cs.nyu.edu/web/Research/TechReports/TR1996-725/TR1996-725.ps.gz \par }}}\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 {\*\bkmkend _Hlt193293965} \par \par Ed Colley: \par DDS source code and DDS executable. \par }{\field\flddirty{\*\fldinst {\lang1053 HYPERLINK "\\\\l "_Hlk133040134" "}{\fs20\lang1053 {\*\datafield 00d0c9ea79f9bace118c8200aa004ba90b02000000010000000303000000000000c0000000000000460000040000005c6c2000ffffadde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {\ul\cf2\lang1053 http://freefinesse.sourceforge.net/}}}{\lang1053 +000000000000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {\ul\cf2\lang1053 http://freefinesse.sourceforge.net/}}}{\lang1053 \par \par Matthew L. Ginsberg: \par DDS algorithms description. \par }{\field\fldedit{\*\fldinst {\lang1053 HYPERLINK \\l "_Hlk134152954" }{\fs20\lang1053 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0048006c006b00310033003400310035003200390035003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -000000}}}{\fldrslt {\cs15\ul\cf2 http://www.cs.cmu.edu/afs/cs/project/jair/pub/volume14/ginsberg01a.pdf}}}{\lang1053 +00000000000000}}}{\fldrslt {\cs15\ul\cf2 http://www.cs.cmu.edu/afs/cs/project/jair/pub/volume14/ginsberg01a.pdf}}}{\lang1053 \par \par Dan Hirschberg: \par DDS algorithms description and DDS executable (MS DOS, cannot run in XP?) \par }{\field\flddirty{\*\fldinst {\lang1053 HYPERLINK "\\\\l "_Hlk132979763" "}{\fs20\lang1053 {\*\datafield 00d0c9ea79f9bace118c8200aa004ba90b02000000010000000303000000000000c0000000000000460000040000005c6c2000ffffadde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {\ul\cf2\lang1053 http://www.ics.uci.edu/~dan/bridge/index.html +000000000000000000000000000000000000000000000000000000000000000000000000}}}{\fldrslt {\ul\cf2\lang1053 http://www.ics.uci.edu/~dan/bridge/index.html \par }}}\pard\plain \nowidctlpar\adjustright \lang2057 {\lang1053 \par Alexey Slovesnov: \par DDS source code and DDS executable. diff --git a/DLL-dds_1112_m.rtf b/DLL-dds_1112_m.rtf new file mode 100644 index 00000000..0a1deb60 --- /dev/null +++ b/DLL-dds_1112_m.rtf @@ -0,0 +1,123 @@ +{\rtf1\ansi\ansicpg1252\deff0\deflang1053\deflangfe1053{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}{\f1\froman\fprq2\fcharset0 Times New Roman;}{\f2\fnil\fcharset0 Calibri;}} +{\colortbl ;\red0\green0\blue255;\red0\green0\blue0;\red255\green0\blue0;} +{\stylesheet{ Normal;}{\s1 heading 1;}{\s2 heading 2;}{\s3 heading 3;}} +{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\nowidctlpar\f0\fs20 Bo Haglund, Bob Richardson\par +Rev M, 2011-10-14\par +Latest DLL issue with this description is available at {\field{\*\fldinst{HYPERLINK "http://www.bahnhof.se/wb758135/"}}{\fldrslt{\ul\cf1 http://www.bahnhof.se/wb758135/}}}\f0\fs20\par +\par +\par +\pard\keepn\nowidctlpar\s2\cf2\ul\b Short description of the DLL functions supported in Double Dummy Problem Solver 1.1.12\par +\pard\nowidctlpar\ulnone\b0\par +\pard\keepn\nowidctlpar\s3\b Callable functions\par +\pard\nowidctlpar\b0\par +extern "C" __declspec(dllimport) int __stdcall SolveBoard(struct deal, int target, \par + int solutions, int mode, struct futureTricks *futp);\par +\par +extern "C" __declspec(dllimport) int __stdcall SolveBoardPBN(struct dealPBN, int target, \par + int solutions, int mode, struct futureTricks *futp);\par +\par +\par +\pard\keepn\nowidctlpar\s3\b SolveBoard\par +\pard\nowidctlpar\b0\par +Before SolveBoard can be called, a structure of type "futureTricks" must be declared. \par +\par +\b SolveBoard\b0 returns a status integer, "no fault" means the DLL supplies the trick data in the "futureTricks" type structure.\line Status codes: \par + 1=No fault, \par + -1=Unknown fault, \par + -2=No of cards = 0, \par + -3=target > Number of tricks left, \par + -4=Duplicated cards, \par + -5=target < -1, \par + -7=target >13, \par + -8=solutions < 1, \par + -9=solutions > 3, \par +-10=No of cards > 52\par +-11=Not used\par +-12=Suit or rank value out of range for deal.currentTrickSuit or deal.currentTrickRank.\par +-13=Card already played in the current trick is also defined as a remaining card to play.\par +-14=Wrong number of remaining cards for a hand.\par + \line Structure \rdblquote\b deal\b0\rdblquote defines all data needed to describe the deal to be analyzed.\par +struct deal \{\f1 \par +\f0 int trump; /* I.e. which suit that is trump or if contract is NT, Spades=0, Hearts=1, Diamonds=2, Clubs=3, NT=4 */\f1 \par +\f0 int first; /* 0-3, 0=North, 1=East, 2=South, 3=West , Leading hand for the trick.*/\f1 \par + \f0 int currentTrickSuit[3]; /* 0-2 for up to 3 cards in the order played */\par + int currentTrickRank[3]; /* 2-14 for up to 3 cards */\f1\par +\f0 unsigned int remainCards[4][4]; /* 1\super st\nosupersub index hand (0-3), 2\super nd\nosupersub index suit (0-3), values as bitstring of ranks bit 0=0, bit 1=0, bit 2=rank 2, \'85\'85\'85. bit 14=rank 14, bit 15=0\f1 \f0 for cards remaining after already played cards (cards already played to the current trick are not included in this bitstring). \line The decimal value for a card then range between 4 (=rank 2) and 16384 (Ace=rank 14). */\f1 \par +\f0\};\f1 \f0\par +\par +Parameter \rdblquote\b target\b0\rdblquote is the number of tricks to be won by the side to play, -1 means that the program\f1 \f0 shall find the maximum number. For equivalent cards only the highest is returned. \par +\line Parameter \rdblquote\b solutions\b0\rdblquote defines how many card solutions that SolveBoard must return:\par + target=1-13, solutions=1: Returns only one of the cards. Its returned score is the same as target whentarget or higher tricks can be won. Otherwise, score \endash 1 is returned if target cannot be reached, or score 0 if no tricks can be won. \line target=-1, solutions=1: Returns only one of the optimum cards and its score.\par + \cf0 target=0, solutions=1: Returns only one of the cards legal to play with score set to 0.\cf2\line target 1-13, solutions=2: Return all cards meeting target. Their returned scores are the same as target when target or higher tricks can be won. Otherwise, only one card is returned with score \endash 1 if target cannot be reached, or score 0 for all cards legal to play if no tricks can be won.\line target \endash 1, solutions=2: Return all optimum cards with their scores.\par + \cf0 target=0, solutions=2: Return all cards legal to play with scores set to 0\cf3 .\cf2\line target irrelevant, solutions=3: Return all cards that can be legally played with their scores in descending order.\par +\par +Parameter \rdblquote\b mode\b0\rdblquote defines the DLL mode of operation.\line mode=0: Do not search to find the score if the hand to play has only one card, including its equivalents, to play. Score is set to \endash 2 for this card, indicating that there are no alternative cards. If there are multiple choices for cards to play, search is done to find the score. This mode is very fast but you don\rquote t \par + mode=1: Always \cf0\lang1033 search to find the score. Even when the hand to play has only one card, with possible equivalents, to play. For both mode=0 and mode=1: If the preceding SolveBoard call had the same trump suit and the same deal, except for deal.first, then the transposition table contents is reused from the preceding SolveBoard call. Setting mode=2 is no longer needed in this case, but can still be done for backwards compatibility.\line mode=2: As for mode=1, but the transposition table contents is reused from the preceding SolveBoard call. It is the responsibility of the programmer using the DLL to ensure that reusing the table is safe in the actual situation. Example: Deal is the same, except for deal.first. Trump suit is the same. \par +\pard\nowidctlpar\fi720 1\super st\nosupersub call: SolveBoard(deal, -1, 1, 1, &fut, 0), deal.first=1, i.e. East leads.\par +\pard\nowidctlpar \tab 2\super nd\nosupersub call: SolveBoard(deal, -1, 1, 2, &fut, 0), deal.first=2, i.e. South leads.\par + \tab 3rd call: SolveBoard(deal, -1, 1, 2, &fut, 0), deal.first=3, i.e. West leads. \par +\pard\nowidctlpar\fi720 4th call: SolveBoard(deal, -1, 1, 2, &fut, 0), deal.first=0, i.e. North leads. \cf2\lang1053\par +\pard\nowidctlpar\par +struct \b futureTricks\b0 \{ /* The DLL provides the score (number of tricks) that can be won by the card to play defined by its suit and rank. Array of all alternative cards. */\f1 \par +\f0 int nodes; /* Number of searched nodes */\par + int cards; /* No of alternative cards */\f1\par +\f0 int suit[13]; /* 0=Spades, 1=Hearts, 2=Diamonds, 3=Clubs */\par + int rank[13]; /* 2-14 for 2 through Ace *\b / \par + \b0 int equals[13]; /* Bitstring of ranks for equivalent lower rank cards. The decimal value range between 4 (=2) and 8192 (King=rank 13). When there are several \rdblquote equals\rdblquote , the value is the sum of each \rdblquote equal\rdblquote . *\b /\b0\par + int score[13]; /* -1 indicates that target was not reached, otherwise target or max numbe of tricks */\f1 \par +\f0\} ; \par +\cf0\lang1033\fs24\par +\pard\keepn\nowidctlpar\s3\cf2\lang1053\b\fs20\par +SolveBoardPBN\par +\par +\b0 In SolveBoardPBN the remaining cards in the deal information are given in PBN text\par +format (e.g. \line W:T5.K4.652.A98542 K6.QJT976.QT7.Q6 432.A.AKJ93.JT73 AQJ987.8532.84.K) instead of using bits 2-14 in an integer array. Otherwise, SolveboardPBN is identical to SolveBoard.\par +\par +struct dealPBN \{\par + int trump; \par + int first; \par + int currentTrickSuit[3]; \b\par + \b0 int currentTrickRank[3]; \par + char remainCards[80]; /* First character identifies the hand having the cards given first\par + in the string, then the cards of the other hands are given in a\par +\tab\tab\tab clock-wise order, see example above. Null characters fill out\par +\tab\tab\tab the character array at the end. */ \par +\};\par +\b\par +\par +\pard\nowidctlpar\cf0\lang1033\b0\fs24\par +\pard\keepn\nowidctlpar\s1\cf2\lang1053\b\fs20 Revision History\par +\pard\nowidctlpar\b0\par +Rev A, 2006-02-25.\tab\tab First issue.\par +\par +Rev B, 2006-03-20\tab\tab Updated issue.\par +\par +\pard\nowidctlpar\fi-2880\li2880 Rev C, 2006-03-28\tab Updated issue. Addition of the SolveBoard parameter \rdblquote mode\rdblquote .\par +\par +Rev D, 2006-04-05\tab Updated issue. Usage of target=0 to list all cards that are legal to play.\par +\par +Rev E, 2006-05-29\tab Updated issue. New error code \endash 10 for number of cards > 52.\par +\par +Rev F, 2006-08-09\tab Updated issue. New mode parameter value = 2. New error code \endash 11 for calling SolveBoard with mode = 2 and forbidden values of other parameters.\par +\pard\nowidctlpar\par +\pard\nowidctlpar\fi-2880\li2880 Rev F1, 2006-08-14\tab Clarifications on conditions for returning scores for the different combinations of the values for target and solutions.\par +\par +Rev F2, 2006-08-26\tab New error code \endash 12 for wrongly set values of deal.currentTrickSuit and\line deal.currentTrickRank.\par +\par +Rev G, 2007-01-04\tab New DDS release 1.1, otherwise no change compared to isse F2.\par +\par +Rev H, 2007-04-23\tab DDS release 1.1.4, changes for parameter mode=2.\par +\par +Rev I, 2010-04-10\tab DDS release 2.0, multi-thread support.\par +\par +Rev J, 2010-05-29\tab DDS release 2.1, OpenMP support, reuse of previous DD transposition table results of similar deals.\par +\par +Rev K, 2010-10-27\tab Correction of fault in the description: 2nd index in resTable of the structure ddTableResults is declarer hand.\par +\par +Rev L, 2011-10-14\tab DDS release 2.1.2, added SolveBoardPBN and CalcDDtablePBN.\par + \par +Rev M, 2011-10-14\tab DDS release 1.1.12, added SolveBoardPBN.\par +\par +\pard\sa200\sl276\slmult1\cf0\lang29\f2\fs22\par +} + \ No newline at end of file diff --git a/DLL-dds_11_h.rtf b/DLL-dds_11_h.rtf deleted file mode 100644 index f09a6086..00000000 --- a/DLL-dds_11_h.rtf +++ /dev/null @@ -1,108 +0,0 @@ -{\rtf1\ansi\ansicpg1252\uc1 \deff1\deflang1033\deflangfe1053{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f93\froman\fcharset238\fprq2 Times New Roman CE;}{\f94\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f96\froman\fcharset161\fprq2 Times New Roman Greek;}{\f97\froman\fcharset162\fprq2 Times New Roman Tur;} -{\f98\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f99\fswiss\fcharset238\fprq2 Arial CE;}{\f100\fswiss\fcharset204\fprq2 Arial Cyr;}{\f102\fswiss\fcharset161\fprq2 Arial Greek;}{\f103\fswiss\fcharset162\fprq2 Arial Tur;} -{\f104\fswiss\fcharset186\fprq2 Arial Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128; -\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\nowidctlpar\adjustright \f1\cgrid \snext0 Normal;}{ -\s1\nowidctlpar\outlinelevel0\adjustright \f1\cgrid \sbasedon0 \snext0 heading 1;}{\*\cs10 \additive Default Paragraph Font;}{\*\cs15 \additive \b \sbasedon10 Strong;}}{\info{\title Bo Haglund, Bob Richardson}{\author Bo Haglund}{\operator Bo Haglund} -{\creatim\yr2007\mo4\dy23\hr19\min18}{\revtim\yr2007\mo4\dy23\hr19\min45}{\version5}{\edmins18}{\nofpages3}{\nofwords904}{\nofchars5154}{\*\company }{\nofcharsws0}{\vern89}}\margl1417\margr1417\margt1417\margb1417 -\widowctrl\ftnbj\aenddoc\hyphhotz425\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\viewkind4\viewscale100 \fet0\sectd \linex0\headery709\footery709\colsx709\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}} -{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}} -{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9 -\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \nowidctlpar\adjustright \f1\cgrid {\fs20\lang1053 Bo Haglund, Bob Richardson -\par Rev H, 2007-04-23 -\par -\par -\par }{\b\fs20\cf1\lang1053 Short description of the DLL functions supported in Double Dummy Problem Solver 1.1}{\fs20\cf1\lang1053 -\par -\par -\par extern "C" __declspec(dllimport) int __stdcall SolveBoard(struct deal, int target, -\par int solutions, int mode, struct futureTricks *futp); -\par -\par /* Before SolveBoard can be called, a structure of type "futureTricks" must be declared. -\par -\par }{\b\fs20\cf1\lang1053 SolveBoard}{\fs20\cf1\lang1053 returns a status integer, "no fault" means the DLL supplies the trick data in the\line "futureTricks" type structure.\line Status codes: -\par 1=No fault, -\par -1=Unknown fault, -\par -2=No of cards = 0, -\par -3=target > Number of tricks left, -\par -4=Duplicated cards, -\par -5=target < -1, -\par -7=target >13, -\par -8=solutions < 1, -\par -9=solutions > 3, -\par -10=No of cards > 52 -\par -11=Not used -\par -12=Suit or rank value out of range for deal.currentTrickSuit or deal.currentTrickRank.\line \line Structure \'94}{\b\fs20\cf1\lang1053 deal}{\fs20\cf1\lang1053 \'94 defines all data needed to describe the deal to be analyzed. -\par struct deal \{}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 int trump; /* I.e. which suit that is trump or if contract is NT, Spades=0, Hearts=1, \line Diamonds=2, Clubs=3, NT=4 */}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 int first; /* 0-3, 0=North, 1=East, 2=South, 3=West , Leading hand for the trick.*/}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 int currentTrickSuit[3]; /* 0-3 for up to 3 cards in the order played */ -\par int currentTrickRank[3]; /* 2-14 for up to 3 cards */}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 unsigned int remainCards[4][4]; /* 1}{\fs20\cf1\lang1053\super st}{\fs20\cf1\lang1053 index hand (0-3), 2}{\fs20\cf1\lang1053\super nd}{\fs20\cf1\lang1053 index suit (0-3), values as bitstring of ranks\line \tab \tab \tab \tab - bit 0=0, bit 1=0, bit 2=rank 2, \'85\'85\'85. bit 14=rank 14, bit 15=0}{\f0\fs20\cf1\lang1053 -\par }\pard \li2880\nowidctlpar\adjustright {\fs20\cf1\lang1053 for cards remaining after already played cards (cards already \line played to the current trick are not included in this bitstring). \line - The decimal value for a card then range between 4 (=rank 2) and -\par 16384 (Ace=rank 14). */}{\f0\fs20\cf1\lang1053 -\par }\pard \nowidctlpar\adjustright {\fs20\cf1\lang1053 \};}{\f0\fs20\cf1\lang1053 }{\fs20\cf1\lang1053 -\par -\par Parameter \'94}{\b\fs20\cf1\lang1053 target}{\fs20\cf1\lang1053 \'94 is the number of tricks to be won by the side to play, -1 means that the program}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 shall find the maximum number. For equivalent cards only the highest is returned. -\par \line Parameter \'94}{\b\fs20\cf1\lang1053 solutions}{\fs20\cf1\lang1053 \'94 defines how many card solutions that SolveBoard must return: -\par target=1-13, solutions=1: Returns only one of the cards. Its returned score is the same as target when \line target or higher tricks can be won. Otherwise, score \endash 1 is returned if target \line - cannot be reached, or score 0 if no tricks can be won. \line target=-1, solutions=1: Returns only one of the optimum cards and its score. -\par }{\fs20\lang1053 target=0, solutions=1: Returns only one of the cards legal to play with score set to 0.}{\fs20\cf1\lang1053 \line target 1-13, solutions=2: Return all cards meeting target. Their returned scores are the same as\line - target when target or higher tricks can be won. Otherwise, only one card \line is returned with score \endash 1 if target cannot be reached, or score 0 for all cards \line - legal to play if no tricks can be won.\line target \endash 1, solutions=2: Return all optimum cards with their scores. -\par }{\fs20\lang1053 target=0, solutions=2: Return all cards legal to play with scores set to 0}{\fs20\cf6\lang1053 .}{\fs20\cf1\lang1053 \line target irrelevant, solutions=3: Return all cards that can be legally played with their scores in -\par descending order. -\par -\par Parameter \'94}{\b\fs20\cf1\lang1053 mode}{\fs20\cf1\lang1053 \'94 defines the DLL mode of operation. This mode does not affect the DLL if there are multiple choices for cards to play. If there is just one card to play, or multiple cards that are all - -\par equivalent, this mode determines whether or not the DLL will search to find the score.\line mode=0: Do not search to find the score if the hand to play has only one card, including its equivalents, -\par to play. Score is set to \endash 2 for this card, indicating that there are no alternative cards. This mode -\par is very fast but you don\rquote t -\par mode=1: Always }{\fs20 search to find the score. Even when the hand to play has only one card, with possible -\par equivalents, to play.\line mode=2: As for mode=1, but the transposition table contents is reused from the preceding SolveBoard\line call. Deal must be the same, except for deal.first. -\par Example: -\par 1}{\fs20\super st}{\fs20 call: SolveBoard(deal, -1, 1, 1, &fut), deal.first=1, i.e. East leads. -\par }{\fs20 2}{\fs20\super nd}{\fs20 call: SolveBoard(deal, }{\fs20 -1}{\fs20 , 1, 2, &fut), deal.first=}{\fs20 2}{\fs20 , i.e. }{\fs20 South}{\fs20 leads.}{\fs20 -\par 3rd call: SolveBoard(deal, -1, 1, 2, &fut), deal.first=3, i.e. West leads. -\par 4th}{\fs20 call: SolveBoard(deal, }{\fs20 -1}{\fs20 , 1, 2, &fut), deal.first=}{\fs20 0}{\fs20 , i.e. }{\fs20 North}{\fs20 leads. }{\fs20 }{\fs20\cf1\lang1053 -\par -\par struct }{\b\fs20\cf1\lang1053 futureTricks}{\fs20\cf1\lang1053 \{ /* The DLL provides the score (number of tricks) that can be won by the card to -\par \tab play defined by its suit and rank. Array of all alternative cards. */}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 int nodes; /* Number of searched nodes */ -\par int cards; /* No of alternative cards */}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 int suit[13]; /* 0=Spades, 1=Hearts, 2=Diamonds, 3=Clubs */ -\par int rank[13]; /* 2-14 for 2 through Ace *}{\b\fs20\cf1\lang1053 / -\par }{\fs20\cf1\lang1053 int equals[13]; /* Bitstring of ranks for equivalent lower rank cards. -\par }\pard \li1440\nowidctlpar\adjustright {\fs20\cf1\lang1053 The decimal value range between 4 (=2) and 8192 (King=rank 13). When there\line are several \'94equals\'94, the value is the sum of each \'94equal\'94. *}{\b\fs20\cf1\lang1053 /}{ -\fs20\cf1\lang1053 -\par }\pard \nowidctlpar\adjustright {\fs20\cf1\lang1053 int score[13]; /* -1 indicates that target was not reached, otherwise target or max number}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 of tricks */}{\f0\fs20\cf1\lang1053 -\par }{\fs20\cf1\lang1053 \} ; }{\f0\fs20\cf1\lang1053 -\par }\pard\plain \s1\keepn\nowidctlpar\outlinelevel0\adjustright \f1\cgrid {\b\fs20\cf1\lang1053 -\par Revision History -\par }\pard\plain \nowidctlpar\adjustright \f1\cgrid {\fs20\cf1\lang1053 -\par Rev A, 2006-02-25.\tab \tab First issue. -\par -\par Rev B, 2006-03-20\tab \tab Updated issue. -\par -\par }\pard \fi-2880\li2880\nowidctlpar\adjustright {\fs20\cf1\lang1053 Rev C, 2006-03-28\tab Updated issue. Addition of the SolveBoard parameter \'94mode\'94. -\par -\par Rev D, 2006-04-05\tab Updated issue. Usage of target=0 to list all cards that are legal to play. -\par -\par Rev E, 2006-05-29\tab Updated issue. New error code \endash 10 for number of cards > 52. -\par -\par Rev F, 2006-08-09\tab Updated issue. New mode parameter value = 2. New error code \endash 11 for calling SolveBoard with mode = 2 and forbidden values of other parameters. -\par }\pard \nowidctlpar\adjustright {\fs20\cf1\lang1053 -\par }\pard \fi-2880\li2880\nowidctlpar\adjustright {\fs20\cf1\lang1053 Rev F1, 2006-08-14\tab Clarifications on conditions for returning scores for the different combinations of the values for target and solutions. -\par -\par -\par Rev F2, 2006-08-26\tab New error code \endash 12 for wrongly set values of deal.currentTrickSuit and\line deal.currentTrickRank. -\par -\par Rev G, 2007-01-04\tab New DDS release 1.1, otherwise no change compared to isse F2. -\par -\par Rev H}{\fs20\cf1\lang1053 , 2007-}{\fs20\cf1\lang1053 04}{\fs20\cf1\lang1053 -}{\fs20\cf1\lang1053 23}{\fs20\cf1\lang1053 \tab DDS release 1.}{\fs20\cf1\lang1053 4}{\fs20\cf1\lang1053 , }{\fs20\cf1\lang1053 changes for parameter mode=2}{ -\fs20\cf1\lang1053 .}{\fs20\cf1\lang1053 -\par }} \ No newline at end of file diff --git a/DLL-dds_11_h.txt b/DLL-dds_11_h.txt deleted file mode 100644 index e416ef8a..00000000 --- a/DLL-dds_11_h.txt +++ /dev/null @@ -1,112 +0,0 @@ -Bo Haglund, Bob Richardson -Rev H, 2007-04-23 - - -Short description of the DLL functions supported in Double Dummy Problem Solver 1.1 - - -extern "C" __declspec(dllimport) int __stdcall SolveBoard(struct deal, int target, - int solutions, int mode, struct futureTricks *futp); - -/* Before SolveBoard can be called, a structure of type "futureTricks" must be declared. - -SolveBoard returns a status integer, "no fault" means the DLL supplies the trick data in the -"futureTricks" type structure. -Status codes: - 1=No fault, - -1=Unknown fault, - -2=No of cards = 0, - -3=target > Number of tricks left, - -4=Duplicated cards, - -5=target < -1, - -7=target >13, - -8=solutions < 1, - -9=solutions > 3, --10=No of cards > 52 --11=Not used --12=Suit or rank value out of range for deal.currentTrickSuit or deal.currentTrickRank. - -Structure ”deal” defines all data needed to describe the deal to be analyzed. -struct deal { - int trump; /* I.e. which suit that is trump or if contract is NT, Spades=0, Hearts=1, - Diamonds=2, Clubs=3, NT=4 */ - int first; /* 0-3, 0=North, 1=East, 2=South, 3=West , Leading hand for the trick.*/ - int currentTrickSuit[3]; /* 0-3 for up to 3 cards in the order played */ - int currentTrickRank[3]; /* 2-14 for up to 3 cards */ - unsigned int remainCards[4][4]; /* 1st index hand (0-3), 2nd index suit (0-3), values as bitstring of ranks - bit 0=0, bit 1=0, bit 2=rank 2, ………. bit 14=rank 14, bit 15=0 - for cards remaining after already played cards (cards already - played to the current trick are not included in this bitstring). - The decimal value for a card then range between 4 (=rank 2) and - 16384 (Ace=rank 14). */ -}; - -Parameter ”target” is the number of tricks to be won by the side to play, -1 means that the program -shall find the maximum number. For equivalent cards only the highest is returned. - -Parameter ”solutions” defines how many card solutions that SolveBoard must return: - target=1-13, solutions=1: Returns only one of the cards. Its returned score is the same as target when - target or higher tricks can be won. Otherwise, score –1 is returned if target - cannot be reached, or score 0 if no tricks can be won. - target=-1, solutions=1: Returns only one of the optimum cards and its score. - target=0, solutions=1: Returns only one of the cards legal to play with score set to 0. - target 1-13, solutions=2: Return all cards meeting target. Their returned scores are the same as - target when target or higher tricks can be won. Otherwise, only one card - is returned with score –1 if target cannot be reached, or score 0 for all cards - legal to play if no tricks can be won. - target –1, solutions=2: Return all optimum cards with their scores. - target=0, solutions=2: Return all cards legal to play with scores set to 0. - target irrelevant, solutions=3: Return all cards that can be legally played with their scores in - descending order. - -Parameter ”mode” defines the DLL mode of operation. This mode does not affect the DLL if there are multiple choices for cards to play. If there is just one card to play, or multiple cards that are all -equivalent, this mode determines whether or not the DLL will search to find the score. - mode=0: Do not search to find the score if the hand to play has only one card, including its equivalents, - to play. Score is set to –2 for this card, indicating that there are no alternative cards. This mode - is very fast but you don’t - mode=1: Always search to find the score. Even when the hand to play has only one card, with possible - equivalents, to play. - mode=2: As for mode=1, but the transposition table contents is reused from the preceding SolveBoard - call. Deal must be the same, except for deal.first. - Example: - 1st call: SolveBoard(deal, -1, 1, 1, &fut), deal.first=1, i.e. East leads. - 2nd call: SolveBoard(deal, -1, 1, 2, &fut), deal.first=2, i.e. South leads. - 3rd call: SolveBoard(deal, -1, 1, 2, &fut), deal.first=3, i.e. West leads. - 4th call: SolveBoard(deal, -1, 1, 2, &fut), deal.first=0, i.e. North leads. - -struct futureTricks { /* The DLL provides the score (number of tricks) that can be won by the card to - play defined by its suit and rank. Array of all alternative cards. */ - int nodes; /* Number of searched nodes */ - int cards; /* No of alternative cards */ - int suit[13]; /* 0=Spades, 1=Hearts, 2=Diamonds, 3=Clubs */ - int rank[13]; /* 2-14 for 2 through Ace */ - int equals[13]; /* Bitstring of ranks for equivalent lower rank cards. - The decimal value range between 4 (=2) and 8192 (King=rank 13). When there - are several ”equals”, the value is the sum of each ”equal”. */ - int score[13]; /* -1 indicates that target was not reached, otherwise target or max number - of tricks */ -} ; - -Revision History - -Rev A, 2006-02-25. First issue. - -Rev B, 2006-03-20 Updated issue. - -Rev C, 2006-03-28 Updated issue. Addition of the SolveBoard parameter ”mode”. - -Rev D, 2006-04-05 Updated issue. Usage of target=0 to list all cards that are legal to play. - -Rev E, 2006-05-29 Updated issue. New error code –10 for number of cards > 52. - -Rev F, 2006-08-09 Updated issue. New mode parameter value = 2. New error code –11 for calling SolveBoard with mode = 2 and forbidden values of other parameters. - -Rev F1, 2006-08-14 Clarifications on conditions for returning scores for the different combinations of the values for target and solutions. - - -Rev F2, 2006-08-26 New error code –12 for wrongly set values of deal.currentTrickSuit and -deal.currentTrickRank. - -Rev G, 2007-01-04 New DDS release 1.1, otherwise no change compared to isse F2. - -Rev H, 2007-04-23 DDS release 1.4, changes for parameter mode=2. \ No newline at end of file diff --git a/dds.cpp b/dds.cpp index fe0b83d1..1c708245 100644 --- a/dds.cpp +++ b/dds.cpp @@ -1,5 +1,5 @@ -/* DDS 1.1.11 A bridge double dummy solver. */ +/* DDS 1.1.12 A bridge double dummy solver. */ /* Copyright (C) 2006-2010 by Bo Haglund */ /* Cleanups and porting to Linux and MacOSX (C) 2006 by Alex Martelli */ /* */ @@ -17,7 +17,7 @@ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc, 51 Franklin Street, 5th Floor, Boston MA 02110-1301, USA. */ -/*#include "stdafx.h"*/ /* Uncomment for Visual C++ */ +/*#include "stdafx.h"*/ /* Needed by Visual C++ */ #include "dll.h" @@ -31,35 +31,24 @@ int nodes; int trickNodes; int no[50]; int iniDepth; -int handToPlay; -int payOff, val; struct pos iniPosition, position; struct pos lookAheadPos; /* Is initialized for starting alpha-beta search */ struct moveType forbiddenMoves[14]; struct moveType initialMoves[4]; -struct moveType cd; struct movePlyType movePly[50]; int tricksTarget; struct gameInfo game; int newDeal; -/*int similarDeal;*/ -int newTrump; -/*unsigned short int diffDeal; -unsigned short int aggDeal;*/ int estTricks[4]; FILE *fp2, *fp7, *fp11; -struct moveType * bestMove; -struct winCardType * temp_win; -int hiwinSetSize=0, hinodeSetSize=0; -int hilenSetSize=0; -int MaxnodeSetSize=0; -int MaxwinSetSize=0; -int MaxlenSetSize=0; +struct moveType bestMove[50]; +struct moveType bestMoveTT[50]; +struct winCardType temp_win[5]; int nodeSetSizeLimit=0; int winSetSizeLimit=0; int lenSetSizeLimit=0; -LONGLONG maxmem, allocmem, summem; +__int64 maxmem, allocmem, summem; int wmem, nmem, lmem; int maxIndex; int wcount, ncount, lcount; @@ -70,22 +59,11 @@ int * highestRank; int * counttable; struct adaptWinRanksType * adaptWins; unsigned char cardRank[15], cardSuit[5], cardHand[4]; -LONGLONG suitLengths=0; struct posSearchType *rootnp[14][4]; struct winCardType **pw; struct nodeCardsType **pn; struct posSearchType **pl; -#ifdef CANCEL -int cancelOrdered=FALSE; -int cancelStarted=FALSE; -int threshold=CANCELCHECK; -#endif - - -#ifdef _MANAGED -#pragma managed(push, off) -#endif #if defined(_WIN32) extern "C" BOOL APIENTRY DllMain(HMODULE hModule, @@ -93,11 +71,8 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, LPVOID lpReserved) { if (ul_reason_for_call==DLL_PROCESS_ATTACH) - InitStart(); + InitStart(0,0); else if (ul_reason_for_call==DLL_PROCESS_DETACH) { - if (bestMove) - free(bestMove); - bestMove=NULL; Wipe(); if (pw[0]) free(pw[0]); @@ -108,15 +83,21 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, if (pl[0]) free(pl[0]); pl[0]=NULL; + if (pw) + free(pw); + pw=NULL; + if (pn) + free(pn); + pn=NULL; + if (pl) + free(pl); + pl=NULL; if (ttStore) free(ttStore); ttStore=NULL; if (rel) free(rel); rel=NULL; - if (temp_win) - free(temp_win); - temp_win=NULL; if (highestRank) free(highestRank); highestRank=NULL; @@ -126,14 +107,13 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, if (adaptWins) free(adaptWins); adaptWins=NULL; + /*_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_WNDW ); + _CrtDumpMemoryLeaks();*/ /* MEMORY LEAK? */ } return 1; } #endif -#ifdef _MANAGED -#pragma managed(pop) -#endif #ifdef PLUSVER int STDCALL SolveBoard(struct deal dl, int target, @@ -143,9 +123,13 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, int solutions, int mode, struct futureTricks *futp) { #endif - int k, l, n, cardCount, found, totalTricks, tricks, last, checkRes; + int k, n, cardCount, found, totalTricks, tricks, last, checkRes; int g, upperbound, lowerbound, first, i, j, h, forb, ind, flag, noMoves; - int mcurr; + int similarDeal; + int newTrump; + unsigned short int diffDeal; + unsigned short int aggDeal; + int mcurr, val, payOff, handToPlay; int noStartMoves; int handRelFirst; int noOfCardsPerHand[4]; @@ -154,10 +138,15 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, int maxHand=0, maxSuit=0, maxRank; unsigned short int aggrRemain; struct movePlyType temp; - struct moveType mv; + struct moveType mv, cd; + int hiwinSetSize=0, hinodeSetSize=0; + int hilenSetSize=0; + int MaxnodeSetSize=0; + int MaxwinSetSize=0; + int MaxlenSetSize=0; /*FILE *fp;*/ - /*InitStart();*/ /* Include InitStart() if inside SolveBoard, + /*InitStart(0,0);*/ /* Include InitStart() if inside SolveBoard, but preferable InitStart should be called outside SolveBoard like in DllMain for Windows. */ @@ -205,12 +194,14 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, tricksTarget=target; newDeal=FALSE; newTrump=FALSE; - /*diffDeal=0; aggDeal=0;*/ + diffDeal=0; aggDeal=0; + cardCount=0; for (i=0; i<=3; i++) { for (j=0; j<=3; j++) { - /*diffDeal+=((dl.remainCards[i][j]>>2)^ + cardCount+=counttable[dl.remainCards[i][j]>>2]; + diffDeal+=((dl.remainCards[i][j]>>2)^ (game.suit[i][j])); - aggDeal+=(dl.remainCards[i][j]>>2);*/ + aggDeal+=(dl.remainCards[i][j]>>2); if (game.suit[i][j]!=dl.remainCards[i][j]>>2) { game.suit[i][j]=dl.remainCards[i][j]>>2; newDeal=TRUE; @@ -218,14 +209,16 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, } } - /*if (newDeal) { + if (newDeal) { if (diffDeal==0) similarDeal=TRUE; else if ((aggDeal/diffDeal)>SIMILARDEALLIMIT) similarDeal=TRUE; else similarDeal=FALSE; - }*/ + } + else + similarDeal=FALSE; if (dl.trump!=trump) newTrump=TRUE; @@ -241,11 +234,6 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, } } - cardCount=0; - for (k=0; k<=3; k++) - for (l=0; l<=3; l++) - cardCount+=counttable[game.suit[k][l]]; - if (dl.currentTrickRank[2]) { if ((dl.currentTrickRank[2]<2)||(dl.currentTrickRank[2]>14) ||(dl.currentTrickSuit[2]<0)||(dl.currentTrickSuit[2]>3)) { @@ -475,12 +463,13 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, futp->score[0]=1; else futp->score[0]=0; + /*_CrtDumpMemoryLeaks();*/ /* MEMORY LEAK? */ return 1; } if ((mode!=2)&& - (((newDeal)/*&&(!similarDeal)*/) - || newTrump)) { + (((newDeal)&&(!similarDeal)) + || newTrump || (winSetSize > SIMILARMAXWINNODES))) { Wipe(); winSetSizeLimit=WINIT; nodeSetSizeLimit=NINIT; @@ -522,6 +511,7 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, futp->equals[0]= movePly[iniDepth].move[0].sequence<<2; futp->score[0]=-2; + /*_CrtDumpMemoryLeaks();*/ /* MEMORY LEAK? */ return 1; } } @@ -542,18 +532,12 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, futp->cards=1; else futp->cards=movePly[iniDepth].last+1; + /*_CrtDumpMemoryLeaks();*/ /* MEMORY LEAK? */ return 1; } if ((target!=-1)&&(solutions!=3)) { val=ABsearch(&lookAheadPos, tricksTarget, iniDepth); - #ifdef CANCEL - if (cancelStarted) { - cancelOrdered=FALSE; - cancelStarted=FALSE; - return 2; - } - #endif temp=movePly[iniDepth]; last=movePly[iniDepth].last; noMoves=last+1; @@ -599,13 +583,6 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, else tricks=g; val=ABsearch(&lookAheadPos, tricks, iniDepth); - #ifdef CANCEL - if (cancelStarted) { - cancelOrdered=FALSE; - cancelStarted=FALSE; - return 2; - } - #endif if (val==TRUE) mv=bestMove[game.noOfCards-4]; hiwinSetSize=Max(hiwinSetSize, winSetSize); @@ -681,20 +658,9 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, forb++; } } - if (1/*(winSetSize=winSetFill)||(nodeSetSize>=nodeSetFill)*/) - InitSearch(&iniPosition, game.noOfCards-4, - initialMoves, first, FALSE); - else InitSearch(&iniPosition, game.noOfCards-4, initialMoves, first, TRUE); do { @@ -761,13 +723,6 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, else tricks=g; val=ABsearch(&lookAheadPos, tricks, iniDepth); - #ifdef CANCEL - if (cancelStarted) { - cancelOrdered=FALSE; - cancelStarted=FALSE; - return 2; - } - #endif if (val==TRUE) mv=bestMove[game.noOfCards-4]; hiwinSetSize=Max(hiwinSetSize, winSetSize); @@ -780,18 +735,14 @@ extern "C" BOOL APIENTRY DllMain(HMODULE hModule, if (lenSetSize>MaxlenSetSize) MaxlenSetSize=lenSetSize; if (val==FALSE) { - upperbound=tricks-1; - g=upperbound; - } - else { - lowerbound=tricks; - g=lowerbound; - } - if (0/*(winSetSize>=winSetFill)||(nodeSetSize>=nodeSetFill)*/) - InitSearch(&iniPosition, game.noOfCards-4, - initialMoves, first, FALSE); - else - InitSearch(&iniPosition, game.noOfCards-4, + upperbound=tricks-1; + g=upperbound; + } + else { + lowerbound=tricks; + g=lowerbound; + } + InitSearch(&iniPosition, game.noOfCards-4, initialMoves, first, TRUE); } while (lowerbound 450000) { - maxmem=5000000*sizeof(struct nodeCardsType)+ - 15000000*sizeof(struct winCardType)+ - 200000*sizeof(struct posSearchType); - } - else if (pcmem > 240000) { - maxmem=3200000*sizeof(struct nodeCardsType)+ - 6400000*sizeof(struct winCardType)+ - 200000*sizeof(struct posSearchType); - } - else if (pcmem > 100000) { - maxmem=800000*sizeof(struct nodeCardsType)+ - 2000000*sizeof(struct winCardType)+ - 100000*sizeof(struct posSearchType); + GetSystemInfo(&temp); } else { - maxmem=400000*sizeof(struct nodeCardsType)+ - 1000000*sizeof(struct winCardType)+ - 50000*sizeof(struct posSearchType); - }*/ + pcmem=(long double)(1000000 * gb_ram); + } - /*fp=fopen("mem.txt", "w"); - - fprintf (fp, "The MEMORYSTATUS structure is %ld bytes long; it should be %d.\n\n", - stat.dwLength, sizeof (stat)); - fprintf (fp, "There is %ld percent of memory in use.\n", - stat.dwMemoryLoad); - fprintf (fp, "There are %*ld total Kbytes of physical memory.\n", - 7, stat.dwTotalPhys/1024); - fprintf (fp, "There are %*ld free Kbytes of physical memory.\n", - 7, stat.dwAvailPhys/1024); - fprintf (fp, "There are %*ld total Kbytes of paging file.\n", - 7, stat.dwTotalPageFile/1024); - fprintf (fp, "There are %*ld free Kbytes of paging file.\n", - 7, stat.dwAvailPageFile/1024); - fprintf (fp, "There are %*ld total Kbytes of virtual memory.\n", - 7, stat.dwTotalVirtual/1024); - fprintf (fp, "There are %*ld free Kbytes of virtual memory.\n", - 7, stat.dwAvailVirtual/1024); - fprintf(fp, "\n"); - fprintf(fp, "nsize=%d wsize=%d lsize=%d\n", nodeSetSizeLimit, winSetSizeLimit, - lenSetSizeLimit); + nodeSetSizeLimit=NINIT; + winSetSizeLimit=WINIT; + lenSetSizeLimit=LINIT; - fclose(fp);*/ + if ((gb_ram!=0)&&(ncores!=0)) + maxmem=gb_ram * ((8000001*sizeof(struct nodeCardsType)+ + 25000001*sizeof(struct winCardType)+ + 400001*sizeof(struct posSearchType))); + else { + maxmem = (__int64)(pcmem-32678) * 700; + /* Linear calculation of maximum memory, formula by Michiel de Bondt */ -#endif + if (maxmem < 10485760) exit (1); + } bitMapRank[15]=0x2000; bitMapRank[14]=0x1000; @@ -972,11 +886,6 @@ void InitStart(void) { bitMapRank[1]=0; bitMapRank[0]=0; - bestMove = (struct moveType *)calloc(50, sizeof(struct moveType)); - /*bestMove = new moveType [50];*/ - if (bestMove==NULL) - exit(1); - lho[0]=1; lho[1]=2; lho[2]=3; lho[3]=0; rho[0]=3; rho[1]=0; rho[2]=1; rho[3]=2; partner[0]=2; partner[1]=3; partner[2]=0; partner[3]=1; @@ -991,9 +900,6 @@ void InitStart(void) { cardHand[0]='N'; cardHand[1]='E'; cardHand[2]='S'; cardHand[3]='W'; - temp_win = (struct winCardType *)calloc(5, sizeof(struct winCardType)); - if (temp_win==NULL) - exit(1); summem=(WINIT+1)*sizeof(struct winCardType)+ (NINIT+1)*sizeof(struct nodeCardsType)+ @@ -1050,7 +956,7 @@ void InitStart(void) { if (ttStore==NULL) exit(1); - rel = (struct relRanksType *)calloc(8192/*16384*/, sizeof(struct relRanksType)); + rel = (struct relRanksType *)calloc(8192, sizeof(struct relRanksType)); /*rel = new relRanksType[8192];*/ if (rel==NULL) exit(1); @@ -1119,7 +1025,7 @@ void InitStart(void) { void InitGame(int gameNo, int moveTreeFlag, int first, int handRelFirst) { - int k, s, h, m; + int k, s, h, m, r, ord; unsigned int topBitRank=1; unsigned short int ind; @@ -1160,6 +1066,13 @@ void InitGame(int gameNo, int moveTreeFlag, int first, int handRelFirst) { rel[ind]=rel[ind ^ topBitRank]; for (s=0; s<4; s++) { + ord=1; + for (r=14; r>=2; r--) { + if ((ind & bitMapRank[r])!=0) { + rel[ind].relRank[r][s]=ord; + ord++; + } + } for (h=0; h<4; h++) { if (game.suit[h][s] & topBitRank) { rel[ind].aggrRanks[s]= @@ -1201,7 +1114,7 @@ void InitGame(int gameNo, int moveTreeFlag, int first, int handRelFirst) { void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], int first, int mtd) { - int s, d, h, /*max, hmax=0, */handRelFirst, maxAgg, maxHand=0; + int s, d, h, handRelFirst, maxAgg, maxHand=0; int k, noOfStartMoves; /* Number of start moves in the 1st trick */ int hand[3], suit[3], rank[3]; struct moveType move; @@ -1226,6 +1139,7 @@ void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], for (d=0; d<=49; d++) { /*bestMove[d].suit=0;*/ bestMove[d].rank=0; + bestMoveTT[d].rank=0; /*bestMove[d].weight=0; bestMove[d].sequence=0; 0315 */ } @@ -1376,35 +1290,15 @@ void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], lastTTstore=0; #endif - recInd=0; - return; } -int mexists, ready, hfirst; -int mcurrent, qtricks, out, sout, hout; -int res; -unsigned char cind; -int minimum, sopFound, nodeFound; int score1Counts[50], score0Counts[50]; int sumScore1Counts, sumScore0Counts; int c1[50], c2[50], c3[50], c4[50], c5[50], c6[50], c7[50], c8[50], c9[50]; int sumc1, sumc2, sumc3, sumc4, sumc5, sumc6, sumc7, sumc8, sumc9; -int scoreFlag; -int tricks, n; -int hh, ss, rr, mm, dd, fh; -int mcount, /*hand, */suit, rank, order; -int k, cardFound, currHand, a, found; -struct evalType evalData; -struct winCardType * np; -struct posSearchType * pp; -struct nodeCardsType * sopP; -struct nodeCardsType * tempP; -unsigned short int aggr[4]; -unsigned short int tricksLeft; -unsigned short int ranks; int ABsearch(struct pos * posPoint, int target, int depth) { /* posPoint points to the current look-ahead position, @@ -1412,26 +1306,23 @@ int ABsearch(struct pos * posPoint, int target, int depth) { depth is the remaining search length, must be positive, the value of the subtree is returned. */ - int moveExists, value, hand; + int moveExists, mexists, value, hand, scoreFlag, found; + int ready, hfirst, hh, ss, rr, mcurrent, qtricks, tricks, res, k; unsigned short int makeWinRank[4]; struct nodeCardsType * cardsP; + struct evalType evalData; + struct winCardType * np; + struct posSearchType * pp; + __int64 suitLengths; + struct nodeCardsType * tempP; + unsigned short int aggr[4]; + unsigned short int ranks; struct evalType Evaluate(struct pos * posPoint); void Make(struct pos * posPoint, unsigned short int trickCards[4], int depth); void Undo(struct pos * posPoint, int depth); - #ifdef CANCEL - if (nodes > threshold) { - if (cancelOrdered) { - cancelStarted=TRUE; - return FALSE; - } - else - threshold+=CANCELCHECK; - } - #endif - /*cardsP=NULL;*/ hand=handId(posPoint->first[depth], posPoint->handRelFirst); nodes++; @@ -1482,7 +1373,7 @@ int ABsearch(struct pos * posPoint, int target, int depth) { } if (nodeTypeStore[hand]==MAXNODE) { - qtricks=QuickTricks(posPoint, hand, depth, target, &res); + qtricks=QuickTricks(posPoint, hand, depth, target, trump, &res); if (res) { if (qtricks==0) return FALSE; @@ -1503,11 +1394,11 @@ int ABsearch(struct pos * posPoint, int target, int depth) { } #endif } - if (!LaterTricksMIN(posPoint,hand,depth,target)) + if (!LaterTricksMIN(posPoint,hand,depth,target, trump)) return FALSE; } else { - qtricks=QuickTricks(posPoint, hand, depth, target, &res); + qtricks=QuickTricks(posPoint, hand, depth, target, trump, &res); if (res) { if (qtricks==0) return TRUE; @@ -1528,69 +1419,135 @@ int ABsearch(struct pos * posPoint, int target, int depth) { } #endif } - if (LaterTricksMAX(posPoint,hand,depth,target)) + if (LaterTricksMAX(posPoint,hand,depth,target, trump)) return TRUE; } } - else if (posPoint->handRelFirst==1) { ss=posPoint->move[depth+1].suit; ranks=posPoint->rankInSuit[hand][ss] | posPoint->rankInSuit[partner[hand]][ss]; found=FALSE; rr=0; qtricks=0; - if ( ranks >(bitMapRank[posPoint->move[depth+1].rank] | - posPoint->rankInSuit[lho[hand]][ss])) { - /* Own side has highest card in suit */ - if (!trumpContract || ((ss==trump)|| - (posPoint->rankInSuit[lho[hand]][trump]==0) - || (posPoint->rankInSuit[lho[hand]][ss]!=0))) { - rr=highestRank[ranks]; - if (rr!=0) { - found=TRUE; - qtricks=1; - } - else - found=FALSE; - } - } - else if (trumpContract && (ss!=trump) && + + if ((trump!=4) && (ss!=trump) && (((posPoint->rankInSuit[hand][ss]==0) - && (posPoint->rankInSuit[hand][trump]!=0))|| - ((posPoint->rankInSuit[partner[hand]][ss]==0) - && (posPoint->rankInSuit[partner[hand]][trump]!=0)))) { - /* Own side can ruff */ + && (posPoint->rankInSuit[hand][trump]!=0))|| + ((posPoint->rankInSuit[partner[hand]][ss]==0) + && (posPoint->rankInSuit[partner[hand]][trump]!=0)))) { + /* Own side can ruff */ if ((posPoint->rankInSuit[lho[hand]][ss]!=0)|| (posPoint->rankInSuit[lho[hand]][trump]==0)) { - found=TRUE; + found=TRUE; qtricks=1; } - } - if (nodeTypeStore[hand]==MAXNODE) { - if ((posPoint->tricksMAX+qtricks>=target)&&(found)&& - (depth!=iniDepth)) { - for (k=0; k<=3; k++) - posPoint->winRanks[depth][k]=0; - if (rr!=0) - posPoint->winRanks[depth][ss]= - posPoint->winRanks[depth][ss] | bitMapRank[rr]; - return TRUE; - } } - else { - if (((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target)&& - (found)&&(depth!=iniDepth)) { - for (k=0; k<=3; k++) - posPoint->winRanks[depth][k]=0; - if (rr!=0) - posPoint->winRanks[depth][ss]= - posPoint->winRanks[depth][ss] | bitMapRank[rr]; + + else if ( ranks >(bitMapRank[posPoint->move[depth+1].rank] | + posPoint->rankInSuit[lho[hand]][ss])) { + /* Own side has highest card in suit */ + if ((trump==4) || ((ss==trump)|| + (posPoint->rankInSuit[lho[hand]][trump]==0) + || (posPoint->rankInSuit[lho[hand]][ss]!=0))) { + rr=highestRank[ranks]; + if (rr!=0) { + found=TRUE; + qtricks=1; + } + else + found=FALSE; + } + } + + if ((found)&&(depth!=iniDepth)) { + for (k=0; k<=3; k++) + posPoint->winRanks[depth][k]=0; + if (rr!=0) + posPoint->winRanks[depth][ss]=bitMapRank[rr]; + + if (nodeTypeStore[hand]==MAXNODE) { + if (posPoint->tricksMAX+qtricks>=target) { + return TRUE; + } + else if (trump==4) { + if (posPoint->rankInSuit[hand][ss] > posPoint->rankInSuit[partner[hand]][ss]) + hh=hand; /* Hand to lead next trick */ + else + hh=partner[hand]; + + if ((posPoint->winner[ss].hand==hh)&&(posPoint->secondBest[ss].rank!=0)&& + (posPoint->secondBest[ss].hand==hh)) { + qtricks++; + posPoint->winRanks[depth][ss]|=bitMapRank[posPoint->secondBest[ss].rank]; + if (posPoint->tricksMAX+qtricks>=target) { + return TRUE; + } + } + + for (k=0; k<=3; k++) { + if ((k!=ss)&&(posPoint->length[hh][k]!=0)) { /* Not lead suit, not void in suit */ + if ((posPoint->length[lho[hh]][k]==0)&&(posPoint->length[rho[hh]][k]==0) + &&(posPoint->length[partner[hh]][k]==0)) { + qtricks+=counttable[posPoint->rankInSuit[hh][k]]; + if (posPoint->tricksMAX+qtricks>=target) { + return TRUE; + } + } + else if ((posPoint->winner[k].rank!=0)&&(posPoint->winner[k].hand==hh)) { + qtricks++; + posPoint->winRanks[depth][k]|=bitMapRank[posPoint->winner[k].rank]; + if (posPoint->tricksMAX+qtricks>=target) { + return TRUE; + } + } + } + } + } + } + else { + /* MIN node */ + if ((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target) { return FALSE; + } + else if (trump==4) { + if (posPoint->rankInSuit[hand][ss] > posPoint->rankInSuit[partner[hand]][ss]) + hh=hand; /* Hand to lead next trick */ + else + hh=partner[hand]; + + if ((posPoint->winner[ss].hand==hh)&&(posPoint->secondBest[ss].rank!=0)&& + (posPoint->secondBest[ss].hand==hh)) { + qtricks++; + posPoint->winRanks[depth][ss]|=bitMapRank[posPoint->secondBest[ss].rank]; + if ((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target) { + return FALSE; + } + } + + for (k=0; k<=3; k++) { + if ((k!=ss)&&(posPoint->length[hh][k]!=0)) { /* Not lead suit, not void in suit */ + if ((posPoint->length[lho[hh]][k]==0)&&(posPoint->length[rho[hh]][k]==0) + &&(posPoint->length[partner[hh]][k]==0)) { + qtricks+=counttable[posPoint->rankInSuit[hh][k]]; + if ((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target) { + return FALSE; + } + } + else if ((posPoint->winner[k].rank!=0)&&(posPoint->winner[k].hand==hh)) { + qtricks++; + posPoint->winRanks[depth][k]|=bitMapRank[posPoint->winner[k].rank]; + if ((posPoint->tricksMAX+((depth)>>2)+3-qtricks)<=target) { + return FALSE; + } + } + } + } + } } } } if ((posPoint->handRelFirst==0)&& - (depth!=iniDepth)/*&&(depth<32)*/) { + (depth!=iniDepth)) { for (ss=0; ss<=3; ss++) { aggr[ss]=0; for (hh=0; hh<=3; hh++) @@ -1602,9 +1559,9 @@ int ABsearch(struct pos * posPoint, int target, int depth) { suitLengths=0; for (ss=0; ss<=2; ss++) for (hh=0; hh<=3; hh++) { - suitLengths=suitLengths<<4; - suitLengths|=posPoint->length[hh][ss]; - } + suitLengths=suitLengths<<4; + suitLengths|=posPoint->length[hh][ss]; + } pp=SearchLenAndInsert(rootnp[tricks][hand], suitLengths, FALSE, &res); /* Find node that fits the suit lengths */ @@ -1622,8 +1579,8 @@ int ABsearch(struct pos * posPoint, int target, int depth) { adaptWins[aggr[ss]].winRanks[(int)cardsP->leastWin[ss]]; if (cardsP->bestMoveRank!=0) { - bestMove[depth].suit=cardsP->bestMoveSuit; - bestMove[depth].rank=cardsP->bestMoveRank; + bestMoveTT[depth].suit=cardsP->bestMoveSuit; + bestMoveTT[depth].rank=cardsP->bestMoveRank; } #ifdef STAT c5[depth]++; @@ -1658,8 +1615,8 @@ int ABsearch(struct pos * posPoint, int target, int depth) { adaptWins[aggr[ss]].winRanks[(int)cardsP->leastWin[ss]]; if (cardsP->bestMoveRank!=0) { - bestMove[depth].suit=cardsP->bestMoveSuit; - bestMove[depth].rank=cardsP->bestMoveRank; + bestMoveTT[depth].suit=cardsP->bestMoveSuit; + bestMoveTT[depth].rank=cardsP->bestMoveRank; } #ifdef STAT c6[depth]++; @@ -1765,8 +1722,8 @@ int ABsearch(struct pos * posPoint, int target, int depth) { posPoint->winRanks[depth+1][ss]= adaptWins[aggr[ss]].winRanks[(int)tempP->leastWin[ss]]; if (tempP->bestMoveRank!=0) { - bestMove[depth+1].suit=tempP->bestMoveSuit; - bestMove[depth+1].rank=tempP->bestMoveRank; + bestMoveTT[depth+1].suit=tempP->bestMoveSuit; + bestMoveTT[depth+1].rank=tempP->bestMoveRank; } for (ss=0; ss<=3; ss++) posPoint->winRanks[depth+1][ss]=posPoint->winRanks[depth+1][ss] @@ -1779,8 +1736,8 @@ int ABsearch(struct pos * posPoint, int target, int depth) { posPoint->winRanks[depth+1][ss]= adaptWins[aggr[ss]].winRanks[(int)tempP->leastWin[ss]]; if (tempP->bestMoveRank!=0) { - bestMove[depth+1].suit=tempP->bestMoveSuit; - bestMove[depth+1].rank=tempP->bestMoveRank; + bestMoveTT[depth+1].suit=tempP->bestMoveSuit; + bestMoveTT[depth+1].rank=tempP->bestMoveRank; } for (ss=0; ss<=3; ss++) posPoint->winRanks[depth+1][ss]=posPoint->winRanks[depth+1][ss] @@ -1852,11 +1809,6 @@ int ABsearch(struct pos * posPoint, int target, int depth) { Make(posPoint, makeWinRank, depth); /* Make current move */ value=ABsearch(posPoint, target, depth-1); - - #ifdef CANCEL - if (cancelStarted) - return FALSE; - #endif Undo(posPoint, depth); /* Retract current move */ if (value==FALSE) { @@ -1885,7 +1837,8 @@ int ABsearch(struct pos * posPoint, int target, int depth) { k=target; else k=target-1; - BuildSOP(posPoint, tricks, hand, target, depth, + if (depth!=iniDepth) + BuildSOP(posPoint, suitLengths, tricks, hand, target, depth, value, k); if (clearTTflag) { /* Wipe out the TT dynamically allocated structures @@ -2139,7 +2092,9 @@ void Make(struct pos * posPoint, unsigned short int trickCards[4], posPoint->length[t][u]--; +#ifdef STAT no[depth]++; +#endif return; } @@ -2338,17 +2293,18 @@ void UpdateSecondBest(struct pos * posPoint, int suit) { int QuickTricks(struct pos * posPoint, int hand, - int depth, int target, int *result) { + int depth, int target, int trump, int *result) { unsigned short int ranks; int suit, sum, qtricks, commPartner, commRank=0, commSuit=-1, s, found=FALSE; - int opps/*, candWin[4]*/; + int opps; int countLho, countRho, countPart, countOwn, lhoTrumpRanks=0, rhoTrumpRanks=0; - int cutoff, k, lowestQtricks=0, count=0; + int cutoff, k, hh, ss, rr, lowestQtricks=0, count=0; + *result=TRUE; qtricks=0; - for (s=0; s<=3; s++) - posPoint->winRanks[depth][s]=0; + for (s=0; s<=3; s++) + posPoint->winRanks[depth][s]=0; if ((depth<=0)||(depth==iniDepth)) { *result=FALSE; @@ -2362,7 +2318,7 @@ int QuickTricks(struct pos * posPoint, int hand, commPartner=FALSE; for (s=0; s<=3; s++) { - if ((trumpContract)&&(trump!=s)) { + if ((trump!=4)&&(trump!=s)) { if (posPoint->winner[s].hand==partner[hand]) { /* Partner has winning card */ if (posPoint->rankInSuit[hand][s]!=0) { @@ -2397,7 +2353,7 @@ int QuickTricks(struct pos * posPoint, int hand, } } } - else if (!trumpContract) { + else if (trump==4) { if (posPoint->winner[s].hand==partner[hand]) { /* Partner has winning card */ if (posPoint->rankInSuit[hand][s]!=0) { @@ -2420,7 +2376,7 @@ int QuickTricks(struct pos * posPoint, int hand, } } - if (trumpContract && (!commPartner) && + if ((trump!=4) && (!commPartner) && (posPoint->rankInSuit[hand][trump]!=0) && (posPoint->winner[trump].hand==partner[hand])) { commPartner=TRUE; @@ -2429,7 +2385,7 @@ int QuickTricks(struct pos * posPoint, int hand, } - if (trumpContract) { + if (trump!=4) { suit=trump; lhoTrumpRanks=posPoint->length[lho[hand]][trump]; rhoTrumpRanks=posPoint->length[rho[hand]][trump]; @@ -2446,7 +2402,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (!opps && (countPart==0)) { if (countOwn==0) { - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2454,27 +2410,27 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; } - if (trumpContract && (trump!=suit)) { + if ((trump!=4) && (trump!=suit)) { if ((lhoTrumpRanks==0) && /* LHO has no trump */ (rhoTrumpRanks==0)) { /* RHO has no trump */ qtricks=qtricks+countOwn; - if (qtricks>=cutoff) + if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2484,7 +2440,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2492,14 +2448,14 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; } } else { - if (!opps && trumpContract && (suit==trump)) { + if (!opps && (trump!=4) && (suit==trump)) { sum=Max(countOwn, countPart); for (s=0; s<=3; s++) { if ((sum>0)&&(s!=trump)&&(countOwn>=countPart)&&(posPoint->length[hand][s]>0)&& @@ -2513,7 +2469,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else if (!opps) { sum=Min(countOwn,countPart); - if (!trumpContract) { + if (trump==4) { if (sum>=cutoff) return sum; } @@ -2525,7 +2481,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (commPartner) { if (!opps && (countOwn==0)) { - if (trumpContract && (trump!=suit)) { + if ((trump!=4) && (trump!=suit)) { if ((lhoTrumpRanks==0) && /* LHO has no trump */ (rhoTrumpRanks==0)) { @@ -2536,13 +2492,13 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2553,7 +2509,7 @@ int QuickTricks(struct pos * posPoint, int hand, bitMapRank[commRank]; if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit=trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2561,14 +2517,14 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; } } else { - if (!opps && trumpContract && (suit==trump)) { + if (!opps && (trump!=4) && (suit==trump)) { sum=Max(countOwn, countPart); for (s=0; s<=3; s++) { if ((sum>0)&&(s!=trump)&&(countOwn<=countPart)&&(posPoint->length[partner[hand]][s]>0)&& @@ -2585,7 +2541,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else if (!opps) { sum=Min(countOwn,countPart); - if (!trumpContract) { + if (trump==4) { if (sum>=cutoff) return sum; } @@ -2596,10 +2552,10 @@ int QuickTricks(struct pos * posPoint, int hand, } } } - } + } /* 08-01-30 */ if (posPoint->winner[suit].rank==0) { - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2607,7 +2563,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2615,7 +2571,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (posPoint->winner[suit].hand==hand) { /* Winner found in own hand */ - if ((trumpContract)&&(trump!=suit)) { + if ((trump!=4)&&(trump!=suit)) { if (((countLho!=0) || /* LHO not void */ (lhoTrumpRanks==0)) @@ -2637,27 +2593,12 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } } - /*if (posPoint->secondBest[suit].rank==0) { - if (trumpContract && (suit==trump)) { - if (trump==0) - suit=1; - else - suit=0; - } - else { - suit++; - if (trumpContract && (suit==trump)) - suit++; - } - continue; - }*/ - if (posPoint->secondBest[suit].hand==hand) { /* Second best found in own hand */ if ((lhoTrumpRanks==0)&& @@ -2671,7 +2612,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2694,7 +2635,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2713,7 +2654,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+countOwn-1; if (qtricks>=cutoff) return qtricks; - if (trumpContract && (trump==suit)) { + if ((trump!=4) && (trump==suit)) { if (trump==0) suit=1; else @@ -2721,7 +2662,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2736,7 +2677,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+countOwn-2; if (qtricks>=cutoff) return qtricks; - if ((trumpContract && (suit==trump))) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2744,7 +2685,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2763,7 +2704,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+Max(countOwn-2,countPart-2); if (qtricks>=cutoff) return qtricks; - if ((trumpContract && (suit==trump))) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2771,7 +2712,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2787,7 +2728,7 @@ int QuickTricks(struct pos * posPoint, int hand, /* Winner found at partner*/ if (commPartner) { /* There is communication with the partner */ - if ((trumpContract)&&(trump!=suit)) { + if ((trump!=4)&&(trump!=suit)) { if (((countLho!=0) || /* LHO not void */ (lhoTrumpRanks==0)) @@ -2812,7 +2753,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2832,7 +2773,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2858,7 +2799,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (qtricks>=cutoff) return qtricks; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -2911,7 +2852,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+countPart-1; if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2919,7 +2860,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2935,7 +2876,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+countPart-2; if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2943,7 +2884,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -2963,7 +2904,7 @@ int QuickTricks(struct pos * posPoint, int hand, qtricks=qtricks+Max(countPart-2,countOwn-2); if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -2971,7 +2912,7 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } continue; @@ -3012,7 +2953,8 @@ int QuickTricks(struct pos * posPoint, int hand, } } } - if (trumpContract &&(suit!=trump)&&(countOwn>0)&&(lowestQtricks==0)&& + if ((trump!=4) &&(suit!=trump)&& + (countOwn>0)&&(lowestQtricks==0)&& ((qtricks==0)||((posPoint->winner[suit].hand!=hand)&& (posPoint->winner[suit].hand!=partner[hand])&& (posPoint->winner[trump].hand!=hand)&& @@ -3024,7 +2966,7 @@ int QuickTricks(struct pos * posPoint, int hand, if (1>=cutoff) return 1; suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -3042,7 +2984,7 @@ int QuickTricks(struct pos * posPoint, int hand, } } suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -3062,7 +3004,7 @@ int QuickTricks(struct pos * posPoint, int hand, return 1; } suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -3082,7 +3024,7 @@ int QuickTricks(struct pos * posPoint, int hand, return 1; } suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; continue; } @@ -3090,7 +3032,7 @@ int QuickTricks(struct pos * posPoint, int hand, } if (qtricks>=cutoff) return qtricks; - if (trumpContract && (suit==trump)) { + if ((trump!=4) && (suit==trump)) { if (trump==0) suit=1; else @@ -3098,14 +3040,14 @@ int QuickTricks(struct pos * posPoint, int hand, } else { suit++; - if (trumpContract && (suit==trump)) + if ((trump!=4) && (suit==trump)) suit++; } } while (suit<=3); if (qtricks==0) { - if ((!trumpContract)||(posPoint->winner[trump].rank==0)) { + if ((trump==4)||(posPoint->winner[trump].rank==0)) { found=FALSE; for (ss=0; ss<=3; ss++) { if (posPoint->winner[ss].rank==0) @@ -3118,8 +3060,8 @@ int QuickTricks(struct pos * posPoint, int hand, } } else if ((posPoint->length[partner[hand]][ss]>0)&& - (posPoint->length[hand][ss]>0)&& - (posPoint->length[partner[hh]][ss]>0)) { + (posPoint->length[hand][ss]>0)&& + (posPoint->length[partner[hh]][ss]>0)) { count++; } } @@ -3127,12 +3069,12 @@ int QuickTricks(struct pos * posPoint, int hand, if (nodeTypeStore[hand]==MAXNODE) { if ((posPoint->tricksMAX+(depth>>2)-Max(0,count-1))winner[ss].hand==-1) + if (posPoint->winner[ss].hand==-1) posPoint->winRanks[depth][ss]=0; else if ((posPoint->length[hand][ss]>0) &&(nodeTypeStore[posPoint->winner[ss].hand]==MINNODE)) posPoint->winRanks[depth][ss]= - bitMapRank[posPoint->winner[ss].rank]; + bitMapRank[posPoint->winner[ss].rank]; else posPoint->winRanks[depth][ss]=0; } @@ -3141,13 +3083,13 @@ int QuickTricks(struct pos * posPoint, int hand, } else { if ((posPoint->tricksMAX+1+Max(0,count-1))>=target) { - for (ss=0; ss<=3; ss++) { - if (posPoint->winner[ss].hand==-1) - posPoint->winRanks[depth][ss]=0; - else if ((posPoint->length[hand][ss]>0) - &&(nodeTypeStore[posPoint->winner[ss].hand]==MAXNODE)) - posPoint->winRanks[depth][ss]= - bitMapRank[posPoint->winner[ss].rank]; + for (ss=0; ss<=3; ss++) { + if (posPoint->winner[ss].hand==-1) + posPoint->winRanks[depth][ss]=0; + else if ((posPoint->length[hand][ss]>0) + &&(nodeTypeStore[posPoint->winner[ss].hand]==MAXNODE)) + posPoint->winRanks[depth][ss]= + bitMapRank[posPoint->winner[ss].rank]; else posPoint->winRanks[depth][ss]=0; } @@ -3162,10 +3104,12 @@ int QuickTricks(struct pos * posPoint, int hand, return qtricks; } -int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target) { + +int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target, + int trump) { int hh, ss, sum=0; - if ((!trumpContract)||(posPoint->winner[trump].rank==0)) { + if ((trump==4)||(posPoint->winner[trump].rank==0)) { for (ss=0; ss<=3; ss++) { hh=posPoint->winner[ss].hand; if (hh!=-1) { @@ -3177,8 +3121,8 @@ int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target) { (sum>0)&&(depth>0)&&(depth!=iniDepth)) { if ((posPoint->tricksMAX+(depth>>2)winner[ss].hand==-1) - posPoint->winRanks[depth][ss]=0; + if (posPoint->winner[ss].hand==-1) + posPoint->winRanks[depth][ss]=0; else if (nodeTypeStore[posPoint->winner[ss].hand]==MINNODE) posPoint->winRanks[depth][ss]=bitMapRank[posPoint->winner[ss].rank]; else @@ -3188,7 +3132,7 @@ int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target) { } } } - else if (trumpContract && (posPoint->winner[trump].rank!=0) && + else if ((trump!=4) && (posPoint->winner[trump].rank!=0) && (nodeTypeStore[posPoint->winner[trump].hand]==MINNODE)) { if ((posPoint->length[hand][trump]==0)&& (posPoint->length[partner[hand]][trump]==0)) { @@ -3215,30 +3159,31 @@ int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target) { if ((nodeTypeStore[hh]==MINNODE)&&(posPoint->secondBest[trump].rank!=0)) { if (((posPoint->length[hh][trump]>1) || (posPoint->length[partner[hh]][trump]>1))&& - ((posPoint->tricksMAX+(depth>>2)-1)0)&&(depth!=iniDepth)) { + ((posPoint->tricksMAX+(depth>>2)-1)0) + &&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->winRanks[depth][ss]=0; posPoint->winRanks[depth][trump]= - bitMapRank[posPoint->winner[trump].rank] | + bitMapRank[posPoint->winner[trump].rank] | bitMapRank[posPoint->secondBest[trump].rank] ; - return FALSE; + return FALSE; } } } } } - else if (trumpContract) { + else if (trump!=4) { hh=posPoint->secondBest[trump].hand; - if (hh!=-1) { + if (hh!=-1) { if ((nodeTypeStore[hh]==MINNODE)&& (posPoint->length[hh][trump]>1)&& - (posPoint->winner[trump].hand==rho[hh]) + (posPoint->winner[trump].hand==rho[hh]) &&(posPoint->secondBest[trump].rank!=0)) { if (((posPoint->tricksMAX+(depth>>2))0)&&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->winRanks[depth][ss]=0; - posPoint->winRanks[depth][trump]= + posPoint->winRanks[depth][trump]= bitMapRank[posPoint->secondBest[trump].rank] ; return FALSE; } @@ -3249,10 +3194,11 @@ int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target) { } -int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target) { +int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target, + int trump) { int hh, ss, sum=0; - if ((!trumpContract)||(posPoint->winner[trump].rank==0)) { + if ((trump==4)||(posPoint->winner[trump].rank==0)) { for (ss=0; ss<=3; ss++) { hh=posPoint->winner[ss].hand; if (hh!=-1) { @@ -3265,7 +3211,7 @@ int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target) { if ((posPoint->tricksMAX+1>=target)) { for (ss=0; ss<=3; ss++) { if (posPoint->winner[ss].hand==-1) - posPoint->winRanks[depth][ss]=0; + posPoint->winRanks[depth][ss]=0; else if (nodeTypeStore[posPoint->winner[ss].hand]==MAXNODE) posPoint->winRanks[depth][ss]=bitMapRank[posPoint->winner[ss].rank]; else @@ -3275,7 +3221,7 @@ int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target) { } } } - else if (trumpContract && (posPoint->winner[trump].rank!=0) && + else if ((trump!=4) && (posPoint->winner[trump].rank!=0) && (nodeTypeStore[posPoint->winner[trump].hand]==MAXNODE)) { if ((posPoint->length[hand][trump]==0)&& (posPoint->length[partner[hand]][trump]==0)) { @@ -3301,31 +3247,33 @@ int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target) { if ((nodeTypeStore[hh]==MAXNODE)&&(posPoint->secondBest[trump].rank!=0)) { if (((posPoint->length[hh][trump]>1) || (posPoint->length[partner[hh]][trump]>1))&& - ((posPoint->tricksMAX+2)>=target)&&(depth>0)&&(depth!=iniDepth)) { + ((posPoint->tricksMAX+2)>=target)&&(depth>0) + &&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->winRanks[depth][ss]=0; posPoint->winRanks[depth][trump]= - bitMapRank[posPoint->winner[trump].rank] | - bitMapRank[posPoint->secondBest[trump].rank]; + bitMapRank[posPoint->winner[trump].rank] | + bitMapRank[posPoint->secondBest[trump].rank]; return TRUE; } } } } } - else if (trumpContract) { - hh=posPoint->secondBest[trump].hand; + else if (trump!=4) { + hh=posPoint->secondBest[trump].hand; if (hh!=-1) { if ((nodeTypeStore[hh]==MAXNODE)&& (posPoint->length[hh][trump]>1)&&(posPoint->winner[trump].hand==rho[hh]) &&(posPoint->secondBest[trump].rank!=0)) { - if (((posPoint->tricksMAX+1)>=target)&&(depth>0)&&(depth!=iniDepth)) { + if (((posPoint->tricksMAX+1)>=target)&&(depth>0) + &&(depth!=iniDepth)) { for (ss=0; ss<=3; ss++) posPoint->winRanks[depth][ss]=0; posPoint->winRanks[depth][trump]= bitMapRank[posPoint->secondBest[trump].rank] ; return TRUE; - } + } } } } @@ -3333,21 +3281,22 @@ int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target) { } -unsigned short ris; -int q, first; -int recInd=0; - int MoveGen(struct pos * posPoint, int depth) { int suit, k, m, n, r, s, t, state; - int scount[4]; - int WeightAlloc(struct pos *, struct moveType * mp, int depth, - unsigned short notVoidInSuit); + unsigned short ris; + int q, first; + int scount[4]; + int WeightAllocTrump(struct pos *, struct moveType * mp, int depth, + unsigned short notVoidInSuit, int trump); + int WeightAllocNT(struct pos * posPoint, struct moveType * mp, int depth, + unsigned short notVoidInSuit); for (k=0; k<4; k++) lowestWin[depth][k]=0; m=0; r=posPoint->handRelFirst; + assert((r>=0)&&(r<=3)); first=posPoint->first[depth]; q=handId(first, r); @@ -3374,15 +3323,21 @@ int MoveGen(struct pos * posPoint, int depth) { state=MOVESVALID; else /* If the card still exists and it is in own hand */ - movePly[depth].move[m-1].sequence= - movePly[depth].move[m-1].sequence | bitMapRank[k]; + movePly[depth].move[m-1].sequence|=bitMapRank[k]; } k--; } if (m!=1) { - for (k=0; k<=m-1; k++) - movePly[depth].move[k].weight=WeightAlloc(posPoint, - &movePly[depth].move[k], depth, ris); + if (trump!=4) { + for (k=0; k<=m-1; k++) + movePly[depth].move[k].weight=WeightAllocTrump(posPoint, + &movePly[depth].move[k], depth, ris, trump); + } + else { + for (k=0; k<=m-1; k++) + movePly[depth].move[k].weight=WeightAllocNT(posPoint, + &movePly[depth].move[k], depth, ris); + } } movePly[depth].last=m-1; @@ -3397,7 +3352,7 @@ int MoveGen(struct pos * posPoint, int depth) { } else { /* First hand or void in suit */ for (suit=0; suit<=3; suit++) { - k=14; state=MOVESVALID; + k=14; state=MOVESVALID; while (k>=2) { if ((posPoint->rankInSuit[q][suit] & bitMapRank[k])&& (state==MOVESVALID)) { @@ -3415,16 +3370,22 @@ int MoveGen(struct pos * posPoint, int depth) { state=MOVESVALID; else /* If the card still exists and it is in own hand */ - movePly[depth].move[m-1].sequence= - movePly[depth].move[m-1].sequence | bitMapRank[k]; + movePly[depth].move[m-1].sequence|=bitMapRank[k]; } k--; } } - for (k=0; k<=m-1; k++) - movePly[depth].move[k].weight=WeightAlloc(posPoint, + if (trump!=4) { + for (k=0; k<=m-1; k++) + movePly[depth].move[k].weight=WeightAllocTrump(posPoint, + &movePly[depth].move[k], depth, ris, trump); + } + else { + for (k=0; k<=m-1; k++) + movePly[depth].move[k].weight=WeightAllocNT(posPoint, &movePly[depth].move[k], depth, ris); + } movePly[depth].last=m-1; InsertSort(m, depth); @@ -3463,50 +3424,354 @@ int MoveGen(struct pos * posPoint, int depth) { } } -int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, + +int WeightAllocNT(struct pos * posPoint, struct moveType * mp, int depth, unsigned short notVoidInSuit) { int weight=0, k, l, kk, ll, suit, suitAdd=0, leadSuit; - int suitWeightDelta; + int suitWeightDelta, first, q; + int rRank; int suitBonus=0; int winMove=FALSE; - unsigned short suitCount, suitCountLH, suitCountRH; + unsigned short suitCount, suitCountLH, suitCountRH, aggr; int countLH, countRH; first=posPoint->first[depth]; q=handId(first, posPoint->handRelFirst); suit=mp->suit; + aggr=0; + for (k=0; k<=3; k++) + aggr|=posPoint->rankInSuit[k][suit]; + rRank=rel[aggr].relRank[mp->rank][suit]; + + switch (posPoint->handRelFirst) { + case 0: + suitCount=posPoint->length[q][suit]; + suitCountLH=posPoint->length[lho[q]][suit]; + suitCountRH=posPoint->length[rho[q]][suit]; + + if ((posPoint->winner[suit].hand==rho[q])|| + ((posPoint->secondBest[suit].hand!=-1)&& + (posPoint->secondBest[suit].hand==rho[q]))) { + suitBonus-=7/*6*//*12*//*17*/; + } + + else if ((posPoint->winner[suit].hand==lho[q])&& + (posPoint->secondBest[suit].hand==partner[q])) + /* This case was suggested by Jol Bradmetz. */ + suitBonus+=34/*37*//*32*//*20*/; + + if (suitCountLH!=0) + countLH=(suitCountLH<<2); + else + countLH=depth+4; + if (suitCountRH!=0) + countRH=(suitCountRH<<2); + else + countRH=depth+4; + + suitWeightDelta=suitBonus-((countLH+countRH)<<5)/(19/*20*//*15*/); + + if (posPoint->winner[suit].rank==mp->rank) + winMove=TRUE; + else if (posPoint->rankInSuit[partner[first]][suit] > + (posPoint->rankInSuit[lho[first]][suit] | + posPoint->rankInSuit[rho[first]][suit])) { + winMove=TRUE; + } + + if (winMove) { + if (posPoint->winner[suit].hand==first) { + if ((posPoint->secondBest[suit].hand!=-1)&& + (posPoint->secondBest[suit].hand==partner[first])) + weight=suitWeightDelta+48/*51*//*50*/+rRank; + else if (posPoint->winner[suit].rank==mp->rank) + weight=suitWeightDelta+35/*34*//*31*/; + else + weight=suitWeightDelta+35/*33*//*27*//*21*/+rRank; + } + else if (posPoint->winner[suit].hand==partner[first]) { + /* If partner has winning card */ + if (posPoint->secondBest[suit].hand==first) + weight=suitWeightDelta+45/*50*/+rRank; + else + weight=suitWeightDelta+33/*35*/+rRank; + } + + if ((bestMove[depth].suit==suit)&& + (bestMove[depth].rank==mp->rank)) + weight+=121/*122*//*112*//*73*/; + else if ((bestMoveTT[depth].suit==suit)&& + (bestMoveTT[depth].rank==mp->rank)) + weight+=18/*17*//*14*/; + } + else { + if (((suitCountLH==1)&&(posPoint->winner[suit].hand==lho[first])) + ||((suitCountRH==1)&&(posPoint->winner[suit].hand==rho[first]))) + weight=suitWeightDelta+25/*23*//*22*/+rRank; + else if (posPoint->winner[suit].hand==first) { + weight=suitWeightDelta-28/*27*//*12*//*10*/+rRank; + } + else if ((mp->sequence)&& + (mp->rank==posPoint->secondBest[suit].rank)) + weight=suitWeightDelta+42/*36*//*32*/; + else + weight=suitWeightDelta+12/*9*/+rRank; + + if ((bestMove[depth].suit==suit)&& + (bestMove[depth].rank==mp->rank)) + weight+=47/*45*//*39*//*38*/; + else if ((bestMoveTT[depth].suit==suit)&& + (bestMoveTT[depth].rank==mp->rank)) + weight+=17/*16*//*19*//*14*/; + } + + break; - if (!notVoidInSuit) { - suitCount=posPoint->length[q][suit]; - /*suitAdd=suitCount+suitCount;*/ - suitAdd=(suitCount<<6)/36; - if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) - suitAdd-=2; + case 1: + leadSuit=posPoint->move[depth+1].suit; + if (leadSuit==suit) { + if (bitMapRank[mp->rank]> + (bitMapRank[posPoint->move[depth+1].rank] | + posPoint->rankInSuit[partner[first]][suit])) + winMove=TRUE; + else if (posPoint->rankInSuit[rho[first]][suit]> + (bitMapRank[posPoint->move[depth+1].rank] | + posPoint->rankInSuit[partner[first]][suit])) + winMove=TRUE; + } + else { + /* Side with highest rank in leadSuit wins */ + if (posPoint->rankInSuit[rho[first]][leadSuit] > + (posPoint->rankInSuit[partner[first]][leadSuit] | + bitMapRank[posPoint->move[depth+1].rank])) + winMove=TRUE; + } + + kk=posPoint->rankInSuit[partner[first]][leadSuit]; + ll=posPoint->rankInSuit[rho[first]][leadSuit]; + k=kk & (-kk); l=ll & (-ll); /* Only least significant 1 bit */ + if (winMove) { + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(23/*20*//*21*//*24*//*30*//*35*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(4/*5*/); + else if ((suitCount==1)&&(posPoint->winner[suit].hand==q)) + suitAdd-=(5/*8*//*5*/); + + weight=/*60*/-(mp->rank)+suitAdd; + } + else if (k > bitMapRank[mp->rank]) + weight=65/*62*/+rRank; + /* If lowest card for partner to leading hand + is higher than lho played card, playing as low as + possible will give the cheapest win */ + else if ((ll > bitMapRank[posPoint->move[depth+1].rank])&& + (posPoint->rankInSuit[first][leadSuit] > ll)) + weight=49+rRank; + /* If rho has a card in the leading suit that + is higher than the trick leading card but lower + than the highest rank of the leading hand, then + lho playing the lowest card will be the cheapest + win */ + else if (mp->rank > posPoint->move[depth+1].rank) { + if (bitMapRank[mp->rank] < ll) + + weight=57/*60*/+rRank; /* If played card is lower than any of the cards of + rho, it will be the cheapest win */ + else if (bitMapRank[mp->rank] > kk) + weight=73-(mp->rank); + /* If played card is higher than any cards at partner + of the leading hand, rho can play low, under the + condition that he has a lower card than lho played */ + } + else if (posPoint->length[rho[first]][leadSuit]>0) { + if (mp->sequence) + weight=50-(mp->rank); + /* Playing a card in a sequence may promote a winner */ + else + weight=48-(mp->rank); + } + /*else + weight=45-(mp->rank);*/ + } + else { + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/35; + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=5; + else if ((suitCount==1)&&(posPoint->winner[suit].hand==q)) + suitAdd-=6/*5*/; + + weight=-(mp->rank)+suitAdd; + + } + else if ((k > bitMapRank[mp->rank])|| + (l > bitMapRank[mp->rank])) + weight=-3+rRank; + /* If lowest rank for either partner to leading hand + or rho is higher than played card for lho, + lho should play as low card as possible */ + else if (mp->rank > posPoint->move[depth+1].rank) { + if (mp->sequence) { + weight=10+rRank; + } + else { + weight=13-(mp->rank); + } + } + else { + weight=-15+rRank; + } + } + + break; + + case 2: + + leadSuit=posPoint->move[depth+2].suit; + if (WinningMove(mp, &(posPoint->move[depth+1]))) { + if (suit==leadSuit) { + if (bitMapRank[mp->rank] > + posPoint->rankInSuit[rho[first]][suit]) + winMove=TRUE; + } + } + else if (posPoint->high[depth+1]==first) { + if (posPoint->length[rho[first]][leadSuit]!=0) { + if (posPoint->rankInSuit[rho[first]][leadSuit] + < bitMapRank[posPoint->move[depth+2].rank]) + winMove=TRUE; + } + else + winMove=TRUE; + } + + if (winMove) { + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(24/*27*//*30*//*35*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(4/*2*//*5*/); + else if ((suitCount==1)&&(posPoint->winner[suit].hand==q)) + suitAdd-=(2/*1*//*2*//*5*/); + + weight=-(mp->rank)+suitAdd; + } + else { + weight=60+rRank; + + } + } + else { + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(21/*26*//*29*//*35*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(3/*5*/); + else if ((suitCount==1)&&(posPoint->winner[suit].hand==q)) + suitAdd-=(2/*5*/); + + weight=-(mp->rank)+suitAdd; + + } + else { + /*weight=20-(mp->rank);*/ + + if (WinningMove(mp, &(posPoint->move[depth+1]))) { + if (mp->rank==posPoint->secondBest[leadSuit].rank) + weight=25; + else if (mp->sequence) + weight=20-(mp->rank); + else + weight=10-(mp->rank); + } + else + weight=-10-(mp->rank); + } + } + + break; + + case 3: + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(32/*35*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(6/*5*/); + else if ((suitCount==1)&&(posPoint->winner[suit].hand==q)) + suitAdd-=(7/*9*//*8*//*5*/); + + weight=30-(mp->rank)+suitAdd; + } + else if ((posPoint->high[depth+1])==(lho[first])) { + /* If the current winning move is given by the partner */ + weight=30-(mp->rank); + } + else if (WinningMove(mp, &(posPoint->move[depth+1]))) + /* If present move is superior to current winning move and the + current winning move is not given by the partner */ + weight=30-(mp->rank); + else { + /* If present move is not superior to current winning move and the + current winning move is not given by the partner */ + weight=14-(mp->rank); + } } + return weight; +} + + +int WeightAllocTrump(struct pos * posPoint, struct moveType * mp, int depth, + unsigned short notVoidInSuit, int trump) { + int weight=0, k, l, kk, ll, suit, suitAdd=0, leadSuit; + int suitWeightDelta, first, q, rRank; + int suitBonus=0; + int winMove=FALSE; + unsigned short suitCount, suitCountLH, suitCountRH, aggr; + int countLH, countRH; + + first=posPoint->first[depth]; + q=handId(first, posPoint->handRelFirst); + suit=mp->suit; + aggr=0; + for (k=0; k<=3; k++) + aggr|=posPoint->rankInSuit[k][suit]; + rRank=rel[aggr].relRank[mp->rank][suit]; switch (posPoint->handRelFirst) { case 0: - suitCount=posPoint->length[q][suit]; + suitCount=posPoint->length[q][suit]; suitCountLH=posPoint->length[lho[q]][suit]; suitCountRH=posPoint->length[rho[q]][suit]; - if ((trump!=4) && (suit!=trump) && + if ((suit!=trump) && (((posPoint->rankInSuit[lho[q]][suit]==0) && (posPoint->rankInSuit[lho[q]][trump]!=0)) || ((posPoint->rankInSuit[rho[q]][suit]==0) && (posPoint->rankInSuit[rho[q]][trump]!=0)))) - suitBonus=-10/*12*//*15*/; + suitBonus=-13/*20*//*-10*/; - if ((posPoint->winner[suit].hand==rho[q])|| - ((posPoint->secondBest[suit].hand!=-1)&&(posPoint->secondBest[suit].hand==rho[q]))) { - suitBonus-=18; - } + if ((suit!=trump)&&(posPoint->length[partner[q]][suit]==0)&& + (posPoint->length[partner[q]][trump]>0)&&(suitCountRH>0)) + suitBonus+=19/*28*/; - if ((trump!=4)&&(suit!=trump)&&(suitCount==1)&& + if ((posPoint->winner[suit].hand==rho[q])|| + ((posPoint->secondBest[suit].hand!=-1)&& + (posPoint->secondBest[suit].hand==rho[q]))) { + suitBonus-=11/*12*//*13*//*18*/; + } + else if ((posPoint->winner[suit].hand==lho[q])&& + (posPoint->secondBest[suit].hand==partner[q])) + /* This case was suggested by Jol Bradmetz. */ + suitBonus+=30/*28*//*22*/; + + if ((suit!=trump)&&(suitCount==1)&& (posPoint->length[q][trump]>0)&& - (posPoint->length[partner[q]][suit]>1)&& - (posPoint->winner[suit].hand==partner[q])) - suitBonus+=16; + (posPoint->length[partner[q]][suit]>1)&& + (posPoint->winner[suit].hand==partner[q])) + suitBonus+=21/*24*//*19*//*16*/; if (suitCountLH!=0) countLH=(suitCountLH<<2); @@ -3517,11 +3782,11 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, else countRH=depth+4; - /*suitWeightDelta=suitBonus-((countLH+countRH)<<1);*/ - suitWeightDelta=suitBonus-((countLH+countRH)<<5)/15; + suitWeightDelta=suitBonus- + ((countLH+countRH)<<5)/(12/*15*/); if (posPoint->winner[suit].rank==mp->rank) { - if ((trump!=4)&&(suit!=trump)) { + if ((suit!=trump)) { if ((posPoint->length[partner[first]][suit]!=0)|| (posPoint->length[partner[first]][trump]==0)) { if (((posPoint->length[lho[first]][suit]!=0)|| @@ -3544,17 +3809,17 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, else if (posPoint->rankInSuit[partner[first]][suit] > (posPoint->rankInSuit[lho[first]][suit] | posPoint->rankInSuit[rho[first]][suit])) { - if ((trump!=4) && (suit!=trump)) { + if (suit!=trump) { if (((posPoint->length[lho[first]][suit]!=0)|| (posPoint->length[lho[first]][trump]==0))&& - ((posPoint->length[rho[first]][suit]!=0)|| - (posPoint->length[rho[first]][trump]==0))) + ((posPoint->length[rho[first]][suit]!=0)|| + (posPoint->length[rho[first]][trump]==0))) winMove=TRUE; } else winMove=TRUE; } - else if ((trump!=4)&&(suit!=trump)) { + else if (suit!=trump) { if ((posPoint->length[partner[first]][suit]==0)&& (posPoint->length[partner[first]][trump]!=0)) { if ((posPoint->length[lho[first]][suit]==0)&& @@ -3562,8 +3827,8 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, (posPoint->length[rho[first]][suit]==0)&& (posPoint->length[rho[first]][trump]!=0)) { if (posPoint->rankInSuit[partner[first]][trump]> - (posPoint->rankInSuit[lho[first]][trump] | - posPoint->rankInSuit[rho[first]][trump])) + (posPoint->rankInSuit[lho[first]][trump] | + posPoint->rankInSuit[rho[first]][trump])) winMove=TRUE; } else if ((posPoint->length[lho[first]][suit]==0)&& @@ -3584,63 +3849,70 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, } if (winMove) { - if (((suitCountLH==1)&&(posPoint->winner[suit].hand==lho[first])) + if (((suitCountLH==1)&&(posPoint->winner[suit].hand==lho[first])) ||((suitCountRH==1)&&(posPoint->winner[suit].hand==rho[first]))) - weight=suitWeightDelta+40-(mp->rank); + weight=suitWeightDelta+41/*44*//*41*//*51*//*40*/+rRank; else if (posPoint->winner[suit].hand==first) { if ((posPoint->secondBest[suit].hand!=-1)&& - (posPoint->secondBest[suit].hand==partner[first])) - weight=suitWeightDelta+50-(mp->rank); - else if (posPoint->winner[suit].rank==mp->rank) + (posPoint->secondBest[suit].hand==partner[first])) + weight=suitWeightDelta+46/*45*//*63*//*53*//*50*/+rRank; + else if (posPoint->winner[suit].rank==mp->rank) weight=suitWeightDelta+31; else - weight=suitWeightDelta+19-(mp->rank); + weight=suitWeightDelta+4/*22*//*21*/+rRank; } else if (posPoint->winner[suit].hand==partner[first]) { /* If partner has winning card */ if (posPoint->secondBest[suit].hand==first) - weight=suitWeightDelta+50-(mp->rank); + weight=suitWeightDelta+34/*35*//*46*//*50*/+rRank; else - weight=suitWeightDelta+35-(mp->rank); + weight=suitWeightDelta+25/*35*/+rRank; } else if ((mp->sequence)&& (mp->rank==posPoint->secondBest[suit].rank)) - weight=suitWeightDelta+40/*-(mp->rank)*/; + weight=suitWeightDelta+39/*51*//*39*//*40*/; else - weight=suitWeightDelta+30-(mp->rank); - if ((bestMove[depth].suit==mp->suit)&& + weight=suitWeightDelta+7/*19*//*29*/+rRank; + + if ((bestMove[depth].suit==suit)&& (bestMove[depth].rank==mp->rank)) - weight+=50; + weight+=53/*50*//*52*/; + else if ((bestMoveTT[depth].suit==suit)&& + (bestMoveTT[depth].rank==mp->rank)) + weight+=13/*15*//*12*//*11*/; } else { if (((suitCountLH==1)&&(posPoint->winner[suit].hand==lho[first])) ||((suitCountRH==1)&&(posPoint->winner[suit].hand==rho[first]))) - weight=suitWeightDelta+20-(mp->rank); + weight=suitWeightDelta+rRank-2; else if (posPoint->winner[suit].hand==first) { if ((posPoint->secondBest[suit].rank!=0)&& - (posPoint->secondBest[suit].hand==partner[first])) - weight=suitWeightDelta+35-(mp->rank); + (posPoint->secondBest[suit].hand==partner[first])) + weight=suitWeightDelta+34/*31*//*35*//*20*/+rRank; else if (posPoint->winner[suit].rank==mp->rank) - weight=suitWeightDelta+16; + weight=suitWeightDelta+36/*25*/; else - weight=suitWeightDelta+4-(mp->rank); + weight=suitWeightDelta-14/*15*//*18*//*12*/+rRank; } else if (posPoint->winner[suit].hand==partner[first]) { /* If partner has winning card */ if (posPoint->secondBest[suit].hand==first) - weight=suitWeightDelta+35-(mp->rank); + weight=suitWeightDelta+28/*27*/+rRank; else - weight=suitWeightDelta+20-(mp->rank); + weight=suitWeightDelta+28/*34*/+rRank; } else if ((mp->sequence)&& (mp->rank==posPoint->secondBest[suit].rank)) - weight=suitWeightDelta+20/*-(mp->rank)*/; + weight=suitWeightDelta+31; else - weight=suitWeightDelta+4-(mp->rank); - weight+=9; - if ((bestMove[depth].suit==mp->suit)&& + weight=suitWeightDelta+13-(mp->rank); + + if ((bestMove[depth].suit==suit)&& (bestMove[depth].rank==mp->rank)) - weight+=30; + weight+=20; + else if ((bestMoveTT[depth].suit==suit)&& + (bestMoveTT[depth].rank==mp->rank)) + weight+=(3/*4*//*10*//*9*/); } break; @@ -3651,7 +3923,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, if (bitMapRank[mp->rank]> (bitMapRank[posPoint->move[depth+1].rank] | posPoint->rankInSuit[partner[first]][suit])) { - if ((trump!=4) && (suit!=trump)) { + if (suit!=trump) { if ((posPoint->length[partner[first]][suit]!=0)|| (posPoint->length[partner[first]][trump]==0)) winMove=TRUE; @@ -3667,7 +3939,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, else if (posPoint->rankInSuit[rho[first]][suit]> (bitMapRank[posPoint->move[depth+1].rank] | posPoint->rankInSuit[partner[first]][suit])) { - if ((trump!=4) && (suit!=trump)) { + if (suit!=trump) { if ((posPoint->length[partner[first]][suit]!=0)|| (posPoint->length[partner[first]][trump]==0)) winMove=TRUE; @@ -3679,7 +3951,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, (posPoint->rankInSuit[rho[first]][suit] | posPoint->rankInSuit[partner[first]][suit] | bitMapRank[mp->rank])) { - if ((trump!=4) && (suit!=trump)) { + if (suit!=trump) { if ((posPoint->length[rho[first]][suit]==0)&& (posPoint->length[rho[first]][trump]!=0)) { if ((posPoint->length[partner[first]][suit]!=0)|| @@ -3692,7 +3964,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, } } else { /* winnerHand is partner to first */ - if ((trump!=4) && (suit!=trump)) { + if (suit!=trump) { if ((posPoint->length[rho[first]][suit]==0)&& (posPoint->length[rho[first]][trump]!=0)) winMove=TRUE; @@ -3701,7 +3973,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, } else { /* Leading suit differs from suit played by LHO */ - if ((trump!=4) && (suit==trump)) { + if (suit==trump) { if (posPoint->length[partner[first]][leadSuit]!=0) winMove=TRUE; else if (bitMapRank[mp->rank]> @@ -3713,7 +3985,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, posPoint->rankInSuit[partner[first]][trump])) winMove=TRUE; } - else if ((trump!=4) && (leadSuit!=trump)) { + else if (leadSuit!=trump) { /* Neither suit nor leadSuit is trump */ if (posPoint->length[partner[first]][leadSuit]!=0) { if (posPoint->rankInSuit[rho[first]][leadSuit] > @@ -3749,69 +4021,83 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, k=kk & (-kk); l=ll & (-ll); /* Only least significant 1 bit */ if (winMove) { if (!notVoidInSuit) { - if ((trump!=4) && (suit==trump)) - weight=25/*30*/-(mp->rank)+suitAdd; + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(42/*36*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=2; + + if (suit==trump) + weight=25/*23*/-(mp->rank)+suitAdd; else weight=60-(mp->rank)+suitAdd; /* Better discard than ruff since rho - wins anyway */ + wins anyway */ } else if (k > bitMapRank[mp->rank]) - weight=45-(mp->rank); /* If lowest card for partner to leading hand - is higher than lho played card, playing as low as - possible will give the cheapest win */ + weight=38/*41*/+rRank; + /* If lowest card for partner to leading hand + is higher than lho played card, playing as low as + possible will give the cheapest win */ else if ((ll > bitMapRank[posPoint->move[depth+1].rank])&& - (posPoint->rankInSuit[first][leadSuit] > ll)) - weight=60-(mp->rank); /* If rho has a card in the leading suit that - is higher than the trick leading card but lower - than the highest rank of the leading hand, then - lho playing the lowest card will be the cheapest - win */ - else if (mp->rank > posPoint->move[depth+1].rank) { + (posPoint->rankInSuit[first][leadSuit] > ll)) + weight=37/*40*/+rRank; + /* If rho has a card in the leading suit that + is higher than the trick leading card but lower + than the highest rank of the leading hand, then + lho playing the lowest card will be the cheapest + win */ + else if (mp->rank > posPoint->move[depth+1].rank) { if (bitMapRank[mp->rank] < ll) weight=75-(mp->rank); /* If played card is lower than any of the cards of - rho, it will be the cheapest win */ + rho, it will be the cheapest win */ else if (bitMapRank[mp->rank] > kk) weight=70-(mp->rank); /* If played card is higher than any cards at partner - of the leading hand, rho can play low, under the - condition that he has a lower card than lho played */ + of the leading hand, rho can play low, under the + condition that he has a lower card than lho played */ else { if (mp->sequence) - weight=60-(mp->rank); + weight=62/*63*//*60*/-(mp->rank); else - weight=45-(mp->rank); + weight=51/*45*/-(mp->rank); } } else if (posPoint->length[rho[first]][leadSuit]>0) { if (mp->sequence) - weight=50-(mp->rank); /* Playing a card in a sequence may promote a winner */ + weight=47/*50*/-(mp->rank); /* Playing a card in a sequence may promote a winner */ + else - weight=45-(mp->rank); + weight=45-(mp->rank); } else - weight=45-(mp->rank); + weight=39/*45*/-(mp->rank); } else { - if (!notVoidInSuit) { - if ((trump!=4) && (suit==trump)) { - weight=15-(mp->rank)+suitAdd; /* Ruffing is preferred, makes the trick + if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(33/*36*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(1/*2*/); + + if (suit==trump) { + weight=16/*15*/-(mp->rank)+suitAdd; /* Ruffing is preferred, makes the trick costly for the opponents */ } else - weight=-(mp->rank)+suitAdd; + weight=-6-(mp->rank)+suitAdd; } else if ((k > bitMapRank[mp->rank])|| - (l > bitMapRank[mp->rank])) - weight=-(mp->rank); /* If lowest rank for either partner to leading hand - or rho is higher than played card for lho, - lho should play as low card as possible */ + (l > bitMapRank[mp->rank])) + weight=-10/*-9*/+rRank; + /* If lowest rank for either partner to leading hand + or rho is higher than played card for lho, + lho should play as low card as possible */ else if (mp->rank > posPoint->move[depth+1].rank) { if (mp->sequence) - weight=20-(mp->rank); + weight=22/*19*/-(mp->rank); else weight=10-(mp->rank); } else - weight=-(mp->rank); + weight=-17+rRank; } break; @@ -3821,7 +4107,7 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, leadSuit=posPoint->move[depth+2].suit; if (WinningMove(mp, &(posPoint->move[depth+1]))) { if (suit==leadSuit) { - if ((trump!=4) && (leadSuit!=trump)) { + if (leadSuit!=trump) { if (((posPoint->length[rho[first]][suit]!=0)|| (posPoint->length[rho[first]][trump]==0))&& (bitMapRank[mp->rank] > @@ -3848,57 +4134,60 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, < bitMapRank[posPoint->move[depth+2].rank]) winMove=TRUE; } - else if (trump==4) - winMove=TRUE; - else if ((trump!=4) && (leadSuit==trump)) + else if (leadSuit==trump) winMove=TRUE; - else if ((trump!=4) && (leadSuit!=trump) && + else if ((leadSuit!=trump) && (posPoint->length[rho[first]][trump]==0)) winMove=TRUE; } if (winMove) { if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(42/*36*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(3/*2*/); + if (posPoint->high[depth+1]==first) { - if ((trump!=4) && (suit==trump)) - weight=30-(mp->rank)+suitAdd; /* Ruffs partner's winner */ - else - weight=60-(mp->rank)+suitAdd; + if (suit==trump) + weight=30-(mp->rank)+suitAdd; /* Ruffs partner's winner */ + else + weight=60-(mp->rank)+suitAdd; } else if (WinningMove(mp, &(posPoint->move[depth+1]))) /* Own hand on top by ruffing */ - weight=70-(mp->rank)+suitAdd; - else if ((trump!=4) && (suit==trump)) - /* Discard a trump but still losing */ - weight=15-(mp->rank)+suitAdd; - else - weight=30-(mp->rank)+suitAdd; + weight=70-(mp->rank)+suitAdd; } else - weight=60-(mp->rank); + weight=60-(mp->rank); } else { if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/36; + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(3/*2*/); + if (WinningMove(mp, &(posPoint->move[depth+1]))) /* Own hand on top by ruffing */ - weight=40-(mp->rank)+suitAdd; - else if ((trump!=4) && (suit==trump)) + weight=40-(mp->rank)+suitAdd; + else if (suit==trump) /* Discard a trump but still losing */ - weight=-15-(mp->rank)+suitAdd; + weight=-/*33*/36+rRank+suitAdd; else weight=-(mp->rank)+suitAdd; } else { if (WinningMove(mp, &(posPoint->move[depth+1]))) { if (mp->rank==posPoint->secondBest[leadSuit].rank) - weight=25/*35*/; + weight=25; else if (mp->sequence) - weight=20/*30*/-(mp->rank); + weight=21/*20*/-(mp->rank); else - weight=10/*20*/-(mp->rank); + weight=10-(mp->rank); } else - weight=-10/*0*/-(mp->rank); + weight=-10-(mp->rank); } } @@ -3906,42 +4195,47 @@ int WeightAlloc(struct pos * posPoint, struct moveType * mp, int depth, case 3: if (!notVoidInSuit) { + suitCount=posPoint->length[q][suit]; + suitAdd=(suitCount<<6)/(27/*36*/); + if ((suitCount==2)&&(posPoint->secondBest[suit].hand==q)) + suitAdd-=(2/*0*//*2*/); + if ((posPoint->high[depth+1])==lho[first]) { /* If the current winning move is given by the partner */ - if ((trump!=4) && (suit==trump)) + if (suit==trump) /* Ruffing partners winner? */ - weight=14-(mp->rank)+suitAdd; + weight=2/*17*/-(mp->rank)+suitAdd; else weight=30-(mp->rank)+suitAdd; } else if (WinningMove(mp, &(posPoint->move[depth+1]))) /* Own hand ruffs */ - weight=30-(mp->rank)+suitAdd; + weight=28/*27*/+rRank+suitAdd; else if (suit==trump) - weight=-(mp->rank); + weight=-13+rRank; else weight=14-(mp->rank)+suitAdd; } else if ((posPoint->high[depth+1])==(lho[first])) { /* If the current winning move is given by the partner */ - if ((trump!=4) && (suit==trump)) + if (suit==trump) /* Ruffs partners winner */ - weight=24-(mp->rank); + weight=11+rRank; else - weight=30-(mp->rank); + weight=17+rRank; } else if (WinningMove(mp, &(posPoint->move[depth+1]))) /* If present move is superior to current winning move and the current winning move is not given by the partner */ - weight=30-(mp->rank); + weight=22+rRank; else { /* If present move is not superior to current winning move and the current winning move is not given by the partner */ - if ((trump!=4) && (suit==trump)) + if (suit==trump) /* Ruffs but still loses */ - weight=-(mp->rank); + weight=-13+rRank; else - weight=14-(mp->rank); + weight=1+rRank; } } return weight; @@ -4134,10 +4428,6 @@ int InvWinMask(int mask) { default: return 0; } } - - -int listNo; -struct winCardType * nextp; int WinningMove(struct moveType * mvp1, struct moveType * mvp2) { @@ -4229,7 +4519,7 @@ struct nodeCardsType * FindSOP(struct pos * posPoint, int target, int tricks, int * valp) { struct nodeCardsType * sopP; struct winCardType * np; - int s; + int s, res; np=nodeP; s=0; while ((np!=NULL)&&(s<4)) { @@ -4237,8 +4527,8 @@ struct nodeCardsType * FindSOP(struct pos * posPoint, np->orderSet) { /* Winning rank set fits position */ if (s==3) { - sopP=CheckSOP(posPoint, np->first, target, tricks, &res, &val); - *valp=val; + sopP=CheckSOP(posPoint, np->first, target, tricks, &res, valp/*&val*/); + /**valp=val;*/ if (res) { return sopP; } @@ -4438,7 +4728,7 @@ struct nodeCardsType * BuildPath(struct pos * posPoint, struct posSearchType * SearchLenAndInsert(struct posSearchType - * rootp, LONGLONG key, int insertNode, int *result) { + * rootp, __int64 key, int insertNode, int *result) { /* Search for node which matches with the suit length combination given by parameter key. If no such node is found, NULL is returned if parameter insertNode is FALSE, otherwise a new @@ -4448,7 +4738,10 @@ struct posSearchType * SearchLenAndInsert(struct posSearchType programming", vol.3 "Sorting and searching", 6.2.2 Algorithm T, page 424. */ - struct posSearchType *np, *p; + struct posSearchType *np, *p, *sp; + + if (insertNode) + sp=&posSearch[lenSetSize]; np=rootp; while (1) { @@ -4460,7 +4753,7 @@ struct posSearchType * SearchLenAndInsert(struct posSearchType if (np->left!=NULL) np=np->left; else if (insertNode) { - p=&posSearch[lenSetSize]; + p=sp/*&posSearch[lenSetSize]*/; AddLenSet(); np->left=p; p->posSearchPoint=NULL; @@ -4478,7 +4771,7 @@ struct posSearchType * SearchLenAndInsert(struct posSearchType if (np->right!=NULL) np=np->right; else if (insertNode) { - p=&posSearch[lenSetSize]; + p=sp/*&posSearch[lenSetSize]*/; AddLenSet(); np->right=p; p->posSearchPoint=NULL; @@ -4497,8 +4790,8 @@ struct posSearchType * SearchLenAndInsert(struct posSearchType -void BuildSOP(struct pos * posPoint, int tricks, int firstHand, int target, - int depth, int scoreFlag, int score) { +void BuildSOP(struct pos * posPoint, __int64 suitLengths, + int tricks, int firstHand, int target, int depth, int scoreFlag, int score) { int ss, hh, res, wm; unsigned short int w; unsigned short int temp[4][4]; @@ -4506,6 +4799,11 @@ void BuildSOP(struct pos * posPoint, int tricks, int firstHand, int target, struct nodeCardsType * cardsP; struct posSearchType * np; +#ifdef TTDEBUG + int k, mcurrent, rr; + mcurrent=movePly[depth].current; +#endif + for (ss=0; ss<=3; ss++) { w=posPoint->winRanks[depth][ss]; if (w==0) { @@ -4605,32 +4903,32 @@ void BuildSOP(struct pos * posPoint, int tricks, int firstHand, int target, cardSuit[movePly[depth+k+1].move[mcurrent].suit], cardRank[movePly[depth+k+1].move[mcurrent].rank]); } + fprintf(fp7, "\n"); + for (hh=0; hh<=3; hh++) { + fprintf(fp7, "hand=%c\n", cardHand[hh]); + for (ss=0; ss<=3; ss++) { + fprintf(fp7, "suit=%c", cardSuit[ss]); + for (rr=14; rr>=2; rr--) + if (posPoint->rankInSuit[hh][ss] & bitMapRank[rr]) + fprintf(fp7, " %c", cardRank[rr]); fprintf(fp7, "\n"); - for (hh=0; hh<=3; hh++) { - fprintf(fp7, "hand=%c\n", cardHand[hh]); - for (ss=0; ss<=3; ss++) { - fprintf(fp7, "suit=%c", cardSuit[ss]); - for (rr=14; rr>=2; rr--) - if (posPoint->rankInSuit[hh][ss] & bitMapRank[rr]) - fprintf(fp7, " %c", cardRank[rr]); - fprintf(fp7, "\n"); - } - fprintf(fp7, "\n"); - } - fprintf(fp7, "\n"); + } + fprintf(fp7, "\n"); + } + fprintf(fp7, "\n"); - for (hh=0; hh<=3; hh++) { - fprintf(fp7, "hand=%c\n", cardHand[hh]); - for (ss=0; ss<=3; ss++) { - fprintf(fp7, "suit=%c", cardSuit[ss]); - for (rr=1; rr<=13; rr++) - if (posPoint->relRankInSuit[hh][ss] & bitMapRank[15-rr]) - fprintf(fp7, " %c", cardRank[rr]); - fprintf(fp7, "\n"); - } - fprintf(fp7, "\n"); - } + for (hh=0; hh<=3; hh++) { + fprintf(fp7, "hand=%c\n", cardHand[hh]); + for (ss=0; ss<=3; ss++) { + fprintf(fp7, "suit=%c", cardSuit[ss]); + for (rr=1; rr<=13; rr++) + if (posPoint->relRankInSuit[hh][ss] & bitMapRank[15-rr]) + fprintf(fp7, " %c", cardRank[rr]); fprintf(fp7, "\n"); + } + fprintf(fp7, "\n"); + } + fprintf(fp7, "\n"); } #endif } @@ -4686,7 +4984,7 @@ int NextMove(struct pos *posPoint, int depth) { if (bitMapRank[currMove.rank]= @@ -4695,8 +4993,6 @@ int NextMove(struct pos *posPoint, int depth) { } return FALSE; } - - /* New: */ else { while (movePly[depth].current<=movePly[depth].last-1) { movePly[depth].current++; @@ -4709,15 +5005,6 @@ int NextMove(struct pos *posPoint, int depth) { } return FALSE; } - - /* Removed: - else if (movePly[depth].current<=movePly[depth].last-1) { - movePly[depth].current++; - return TRUE; - } - else - return FALSE;*/ - } else { while (movePly[depth].current<=movePly[depth].last-1) { @@ -4737,6 +5024,7 @@ int DumpInput(int errCode, struct deal dl, int target, FILE *fp; int i, j, k; + unsigned short ranks[4][4]; fp=fopen("dump.txt", "w"); if (fp==NULL) @@ -4744,22 +5032,90 @@ int DumpInput(int errCode, struct deal dl, int target, fprintf(fp, "Error code=%d\n", errCode); fprintf(fp, "\n"); fprintf(fp, "Deal data:\n"); - fprintf(fp, "trump=%d\n", dl.trump); - fprintf(fp, "first=%d\n", dl.trump); + if (dl.trump!=4) + fprintf(fp, "trump=%c\n", cardSuit[dl.trump]); + else + fprintf(fp, "trump=N\n"); + fprintf(fp, "first=%c\n", cardHand[dl.first]); for (k=0; k<=2; k++) - fprintf(fp, "index=%d currentTrickSuit=%d currentTrickRank=%d\n", - k, dl.currentTrickSuit[k], dl.currentTrickRank[k]); + if (dl.currentTrickRank[k]!=0) + fprintf(fp, "index=%d currentTrickSuit=%c currentTrickRank=%c\n", + k, cardSuit[dl.currentTrickSuit[k]], cardRank[dl.currentTrickRank[k]]); for (i=0; i<=3; i++) - for (j=0; j<=3; j++) + for (j=0; j<=3; j++) { fprintf(fp, "index1=%d index2=%d remainCards=%d\n", i, j, dl.remainCards[i][j]); + ranks[i][j]=dl.remainCards[i][/*3-*/j]>>2; + } fprintf(fp, "\n"); fprintf(fp, "target=%d\n", target); fprintf(fp, "solutions=%d\n", solutions); fprintf(fp, "mode=%d\n", mode); + fprintf(fp, "\n"); + PrintDeal(fp, ranks); fclose(fp); return 0; -} +} + +void PrintDeal(FILE *fp, unsigned short ranks[][4]) { + int i, count, ec[4], trickCount=0, s, r; + for (i=0; i<=3; i++) { + count=counttable[ranks[3][i]]; + if (count>5) + ec[i]=TRUE; + else + ec[i]=FALSE; + trickCount=trickCount+count; + } + fprintf(fp, "\n"); + for (s=0; s<=3; s++) { + fprintf(fp, "\t%c ", cardSuit[s]); + if (!ranks[0][s]) + fprintf(fp, "--"); + else { + for (r=14; r>=2; r--) + if ((ranks[0][s] & bitMapRank[r])!=0) + fprintf(fp, "%c", cardRank[r]); + } + fprintf(fp, "\n"); + } + for (s=0; s<=3; s++) { + fprintf(fp, "%c ", cardSuit[s]); + if (!ranks[3][s]) + fprintf(fp, "--"); + else { + for (r=14; r>=2; r--) + if ((ranks[3][s] & bitMapRank[r])!=0) + fprintf(fp, "%c", cardRank[r]); + } + if (ec[s]) + fprintf(fp, "\t\%c ", cardSuit[s]); + else + fprintf(fp, "\t\t\%c ", cardSuit[s]); + if (!ranks[1][s]) + fprintf(fp, "--"); + else { + for (r=14; r>=2; r--) + if ((ranks[1][s] & bitMapRank[r])!=0) + fprintf(fp, "%c", cardRank[r]); + } + fprintf(fp, "\n"); + } + for (s=0; s<=3; s++) { + fprintf(fp, "\t%c ", cardSuit[s]); + if (!ranks[2][s]) + fprintf(fp, "--"); + else { + for (r=14; r>=2; r--) + if ((ranks[2][s] & bitMapRank[r])!=0) + fprintf(fp, "%c", cardRank[r]); + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); + return; +} + void Wipe(void) { @@ -4901,18 +5257,32 @@ int STDCALL CalcDDtable(struct ddTableDeal tableDeal, struct ddTableResults * ta for (first=0; first<=3; first++) { dl.first=first; dl.trump=tr; - res=SolveBoard(dl, -1, 1, 1, &fut, 0); - if (res==1) { - tablep->resTable[tr][rho[dl.first]]=13-fut.score[0]; - } - else - return 0; + res=SolveBoard(dl, -1, 1, 1, &fut, 0); + if (res==1) { + tablep->resTable[tr][rho[dl.first]]=13-fut.score[0]; + } + else + /*return 0;*/ + return res; /* 2011-07-27 */ } return 1; } -#endif +int STDCALL CalcDDtablePBN(struct ddTableDealPBN tableDealPBN, + struct ddTableResults * tablep) { + int res; + struct ddTableDeal tableDeal; + int ConvertFromPBN(char * dealBuff, unsigned int remainCards[4][4]); + + if (ConvertFromPBN(tableDealPBN.cards, tableDeal.cards)!=1) + return -99; + + res=CalcDDtable(tableDeal, tablep); + + return res; +} +#endif #ifdef TTDEBUG @@ -4990,5 +5360,169 @@ void ReceiveTTstore(struct pos *posPoint, struct nodeCardsType * cardsP, } #endif +int ConvertFromPBN(char * dealBuff, unsigned int remainCards[4][4]) { + int bp=0, first, card, hand, handRelFirst, suitInHand, h, s; + int IsCard(char cardChar); + + for (h=0; h<=3; h++) + for (s=0; s<=3; s++) + remainCards[h][s]=0; + + while (((dealBuff[bp]!='W')&&(dealBuff[bp]!='N')&& + (dealBuff[bp]!='E')&&(dealBuff[bp]!='S')&& + (dealBuff[bp]!='w')&&(dealBuff[bp]!='n')&& + (dealBuff[bp]!='e')&&(dealBuff[bp]!='s'))&&(bp<3)) + bp++; + + if (bp>=3) + return 0; + + if ((dealBuff[bp]=='N')||(dealBuff[bp]=='n')) + first=0; + else if ((dealBuff[bp]=='E')||(dealBuff[bp]=='e')) + first=1; + else if ((dealBuff[bp]=='S')||(dealBuff[bp]=='s')) + first=2; + else + first=3; + + bp++; + bp++; + + handRelFirst=0; suitInHand=0; + + while (bp<80) { + card=IsCard(dealBuff[bp]); + if (card) { + switch (first) { + case 0: + hand=handRelFirst; + break; + case 1: + if (handRelFirst==0) + hand=1; + else if (handRelFirst==3) + hand=0; + else + hand=handRelFirst+1; + break; + case 2: + if (handRelFirst==0) + hand=2; + else if (handRelFirst==1) + hand=3; + else + hand=handRelFirst-2; + break; + default: + if (handRelFirst==0) + hand=3; + else + hand=handRelFirst-1; + } + + remainCards[hand][suitInHand]|=(bitMapRank[card]<<2); + + } + else if (dealBuff[bp]=='.') + suitInHand++; + else if (dealBuff[bp]==' ') { + handRelFirst++; + suitInHand=0; + } + bp++; + } + return 1; +} + +int IsCard(char cardChar) { + switch (cardChar) { + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'T': + return 10; + case 'J': + return 11; + case 'Q': + return 12; + case 'K': + return 13; + case 'A': + return 14; + case 't': + return 10; + case 'j': + return 11; + case 'q': + return 12; + case 'k': + return 13; + case 'a': + return 14; + default: + return 0; + } +} + +#ifdef PLUSVER +int STDCALL SolveBoardPBN(struct dealPBN dlpbn, int target, + int solutions, int mode, struct futureTricks *futp, int thrId) { + int res, k; + struct deal dl; + int ConvertFromPBN(char * dealBuff, unsigned int remainCards[4][4]); + + if (ConvertFromPBN(dlpbn.remainCards, dl.remainCards)!=1) + return -99; + + for (k=0; k<=2; k++) { + dl.currentTrickRank[k]=dlpbn.currentTrickRank[k]; + dl.currentTrickSuit[k]=dlpbn.currentTrickSuit[k]; + } + dl.first=dlpbn.first; + dl.trump=dlpbn.trump; + + res=SolveBoard(dl, target, solutions, mode, futp, 0); + + return res; +} + +#else +#ifdef PBN +int STDCALL SolveBoardPBN(struct dealPBN dlpbn, int target, + int solutions, int mode, struct futureTricks *futp) { + int res, k; + struct deal dl; + int ConvertFromPBN(char * dealBuff, unsigned int remainCards[4][4]); + + if (ConvertFromPBN(dlpbn.remainCards, dl.remainCards)!=1) + return -99; + + for (k=0; k<=2; k++) { + dl.currentTrickRank[k]=dlpbn.currentTrickRank[k]; + dl.currentTrickSuit[k]=dlpbn.currentTrickSuit[k]; + } + dl.first=dlpbn.first; + dl.trump=dlpbn.trump; + + res=SolveBoard(dl, target, solutions, mode, futp); + + return res; +} +#endif +#endif diff --git a/dll.h b/dll.h index 1f2bd4ab..d066b629 100644 --- a/dll.h +++ b/dll.h @@ -1,8 +1,5 @@ -/* portability-macros header prefix */ -#if !defined(_MSC_VER) -#define LONGLONG long long -#endif +/* portability-macros header prefix */ /* Windows requires a __declspec(dllexport) tag, etc */ #if defined(_WIN32) @@ -28,18 +25,24 @@ /* end of portability-macros section */ +#define DDS_VERSION 111201 /* Version 1.1.12. Allowing for 2 digit + minor versions */ /*#define BENCH*/ +#define PBN + /*#define PLUSVER*/ #include +/*#define _CRTDBG_MAP_ALLOC */ /* MEMORY LEAK? */ #include +/*#include */ /* MEMORY LEAK? */ #include #include +#include /*#define STAT*/ /* Define STAT to generate a statistics log, stat.txt */ /*#define TTDEBUG*/ /* Define TTDEBUG to generate transposition table debug information */ -/*#define CANCEL*/ /* Define CANCEL to get support for cancelling ongoing search */ #ifdef TTDEBUG #define SEARCHSIZE 20000 @@ -47,8 +50,6 @@ #define SEARCHSIZE 1 #endif -#define CANCELCHECK 200000 - #if defined(INFINITY) # undef INFINITY #endif @@ -70,7 +71,8 @@ #define WINIT 700000/*1000000*/ #define LINIT 50000 -/*#define SIMILARDEALLIMIT 5*/ +#define SIMILARDEALLIMIT 5 +#define SIMILARMAXWINNODES 700000 #define Max(x, y) (((x) >= (y)) ? (x) : (y)) #define Min(x, y) (((x) <= (y)) ? (x) : (y)) @@ -137,6 +139,13 @@ struct deal { unsigned int remainCards[4][4]; }; +struct dealPBN { + int trump; + int first; + int currentTrickSuit[3]; + int currentTrickRank[3]; + char remainCards[80]; +}; struct pos { unsigned short int rankInSuit[4][4]; /* 1st index is hand, 2nd index is @@ -199,6 +208,7 @@ struct evalType { struct relRanksType { int aggrRanks[4]; int winMask[4]; + char relRank[15][4]; }; struct adaptWinRanksType { @@ -220,13 +230,17 @@ struct ddTableDeal { unsigned int cards[4][4]; }; +struct ddTableDealPBN { + char cards[80]; +}; + struct ddTableResults { int resTable[5][4]; }; extern struct gameInfo game; -extern int newDeal; +/*extern int newDeal;*/ extern struct gameInfo * gameStore; extern struct ttStoreType * ttStore; extern struct nodeCardsType * nodeCards; @@ -240,7 +254,8 @@ extern struct moveType forbiddenMoves[14]; /* Initial depth moves that will be excluded from the search */ extern struct moveType initialMoves[4]; extern struct moveType highMove; -extern struct moveType * bestMove; +extern struct moveType bestMove[50]; +extern struct moveType bestMoveTT[50]; extern struct relRanksType * rel; extern struct winCardType **pw; extern struct nodeCardsType **pn; @@ -264,7 +279,6 @@ extern int trump; extern int nodes; /* Number of nodes searched */ extern int no[50]; /* Number of nodes searched on each depth level */ -extern int payOff; extern int iniDepth; extern int treeDepth; extern int tricksTarget; /* No of tricks for MAX in order to @@ -274,7 +288,6 @@ extern int tricksTargetOpp; /* Target no of tricks for MAX opponent */ extern int targetNS; extern int targetEW; -extern int handToPlay; extern int nodeSetSize; extern int winSetSize; extern int lenSetSize; @@ -286,15 +299,11 @@ extern int highHand; extern int nodeSetSizeLimit; extern int winSetSizeLimit; extern int lenSetSizeLimit; -extern int estTricks[4]; -extern int recInd; +extern int estTricks[4]; extern int suppressTTlog; extern unsigned char suitChar[4]; extern unsigned char rankChar[15]; extern unsigned char handChar[4]; -extern int cancelOrdered; -extern int cancelStarted; -extern int threshold; extern unsigned char cardRank[15], cardSuit[5], cardHand[4]; extern FILE * fp2, *fp7, *fp11; @@ -303,15 +312,23 @@ extern FILE * fp2, *fp7, *fp11; #ifdef PLUSVER EXTERN_C DLLEXPORT int STDCALL SolveBoard(struct deal dl, int target, int solutions, int mode, struct futureTricks *futp, int threadIndex); +EXTERN_C DLLEXPORT int STDCALL SolveBoardPBN(struct dealPBN dlpbn, int target, + int solutions, int mode, struct futureTricks *futp, int thrId); EXTERN_C DLLEXPORT int STDCALL CalcDDtable(struct ddTableDeal tableDeal, struct ddTableResults * tablep); -#else +EXTERN_C DLLEXPORT int STDCALL CalcDDtablePBN(struct ddTableDealPBN tableDealPBN, + struct ddTableResults * tablep); +#else EXTERN_C DLLEXPORT int STDCALL SolveBoard(struct deal dl, int target, int solutions, int mode, struct futureTricks *futp); +#ifdef PBN + EXTERN_C DLLEXPORT int STDCALL SolveBoardPBN(struct dealPBN dlpbn, int target, + int solutions, int mode, struct futureTricks *futp); +#endif #endif -void InitStart(void); +void InitStart(int gb_ram, int ncores); void InitGame(int gameNo, int moveTreeFlag, int first, int handRelFirst); void InitSearch(struct pos * posPoint, int depth, struct moveType startMoves[], int first, int mtd); @@ -325,9 +342,9 @@ void UpdateSecondBest(struct pos * posPoint, int suit); int WinningMove(struct moveType * mvp1, struct moveType * mvp2); int AdjustMoveList(void); int QuickTricks(struct pos * posPoint, int hand, - int depth, int target, int *result); -int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target); -int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target); + int depth, int target, int trump, int *result); +int LaterTricksMIN(struct pos *posPoint, int hand, int depth, int target, int trump); +int LaterTricksMAX(struct pos *posPoint, int hand, int depth, int target, int trump); struct nodeCardsType * CheckSOP(struct pos * posPoint, struct nodeCardsType * nodep, int target, int tricks, int * result, int *value); struct nodeCardsType * UpdateSOP(struct pos * posPoint, struct nodeCardsType @@ -338,10 +355,10 @@ struct nodeCardsType * FindSOP(struct pos * posPoint, struct cardType NextCard(struct cardType card); struct nodeCardsType * BuildPath(struct pos * posPoint, struct posSearchType *nodep, int * result); -void BuildSOP(struct pos * posPoint, int tricks, int firstHand, int target, - int depth, int scoreFlag, int score); +void BuildSOP(struct pos * posPoint, __int64 suitLengths, int tricks, + int firstHand, int target, int depth, int scoreFlag, int score); struct posSearchType * SearchLenAndInsert(struct posSearchType - * rootp, LONGLONG key, int insertNode, int *result); + * rootp, __int64 key, int insertNode, int *result); void Undo(struct pos * posPoint, int depth); int CheckDeal(struct moveType * cardp); int InvBitMapRank(unsigned short bitMap); @@ -353,3 +370,4 @@ void Wipe(void); void AddNodeSet(void); void AddLenSet(void); void AddWinSet(void); +void PrintDeal(FILE *fp, unsigned short ranks[][4]); diff --git a/readme.txt b/readme.txt index 49f26293..32f73c14 100644 --- a/readme.txt +++ b/readme.txt @@ -1,10 +1,11 @@ -DDS 1.1.9, Bo Haglund 2008-09-07 +DDS 1.1.12, Bo Haglund 2011-10-21 -For Win32, DDS compiles with Visual C++ 2005 Express edition -and the Mingw port of gcc 3.4.2. +For Win32, DDS compiles with Visual C++ 2010 Express edition +and the Mingw port of gcc. When using Visual C++, the statement -#include "stdafx.h" at the beginning of dds.cpp must be uncommented. +#include "stdafx.h" at the beginning of dds.cpp must be uncommented. + Linking with an application using DDS ------------------------------------- @@ -14,31 +15,22 @@ without the overhead of InitStart() at each call. For this purpose, the application code must have an include statement for the dll.h file in DDS. -Setting up the maximum size of the transposition table ------------------------------------------------------- -When compiling for Win32, the maximum size of the transposition table is automatically set depending on the physical memory size of -the PC. - -When compiling with Linux, the maximum transposition table size -(maxmem) is set as follows in dds.cpp (search for maxmem)in InitStart: - -maxmem=5000000*sizeof(struct nodeCardsType)+ - 15000000*sizeof(struct winCardType)+ - 200000*sizeof(struct posSearchType); - -If needed change the values, see examples later in the code for Win32 with different PC memory sizes. - - Options at DDS compilation -------------------------- -There are 3 compiling options: +Compiling options: 1) Compilation without definitions of STAT or TTDEBUG. This is the default case given in the distributed source where definitions of STAT and TTDEBUG are commented away. This compilation alternative gives the best performance. +By default the PBN versions for remaning cards in the deal information +are included in SolveBoardPBN. Removing the PBN definition in dll.h +will make a compilation without this function. This can be useful +if DDS 1.1.12 is to replace 1.1.11, and the application using DDS cannot +accept an interface change towards DDS. + 2) Compilation with definition STAT. Uncomment the definition of STAT. This gives deal search statistics information for each call diff --git a/release_notes.txt b/release_notes.txt index 2e5328a4..e796da87 100644 --- a/release_notes.txt +++ b/release_notes.txt @@ -232,6 +232,77 @@ and QuickTricks slightly faster. +Release Notes DDS 2.0.0 +----------------------- +A bug was fixed. +SolveBoard is now thread-safe. +The SolveBoard parameter "mode" no longer needs to be set to 2. +DDS automatically detect situations when the transposition +table contents can be reused. +Used with a single thread, DDS 2.0.0 has about the same speed as DDS 1.1.9. +Used with 2 parallel threads, DDS 2.0.0 is twice as fast as the single +thread case. + +A new function, CalcDDtable, has been added. +CalcDDtable calls SolveBoard using parallel threads. The number of +parallel threads is the same as the number of processor cores. +CalcDDtable calculates the double dummy values of the initial 52 cards +for all the 20 trump suit/leading hand combinations. + + +Release Notes DDS 2.0.1 +----------------------- +In 2.0.0, the contents of the transposition table could be erronously +be reused when the previous position contained a different number of +cards. This was caused by an erroneous implementation of the +deal similarity test. This bug was fixed by removing the similarity test. + +The DDS version number is defined by a #define statement in dll.h. + + +Release Notes DDS 2.1.0 +----------------------- +Added OpenMP as multi-thread support for CalcDDtable when compiling with +gcc 4.4.0 or later. + +Added a similarity deals test function for reuse of the transposition +table contents when the current deal is similar to the previous deal. + + +Release Notes DDS 2.1.1 +----------------------- +The maximum number of threads is configurable depending on the size of the +physical memory. The configuration is either done automatically by reading +out the physical memory size by the operating system, or by supplying +parameter values in InitStart. + + +Release Notes DDS 2.1.2 +----------------------- +2 new callable functions have been added: +SolveBoardPBN and CalcDDtablePBN. +They both accept PBN format for the remaining cards in the deal information +instead of the bit codes. + +Code improvements have been done concerning quick tricks detection and move +ordering. 2.1.2 is about 10% faster than 2.1.1. + + +Release Notes DDS 1.1.12 +------------------------ +2 new callable functions have been added: +SolveBoardPBN and CalcDDtablePBN. +They both accept PBN format for the remaining cards in the deal information +instead of the bit codes. + +Code improvements have been done concerning quick tricks detection and move +ordering. 1.1.12 is about 15-20% faster than 1.1.11. + + + + + +