diff --git a/library/src/ab_search.hpp b/library/src/ab_search.hpp index 37b772162..99d8d725b 100644 --- a/library/src/ab_search.hpp +++ b/library/src/ab_search.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include auto ab_search( diff --git a/library/src/api/BUILD.bazel b/library/src/api/BUILD.bazel index 9c6f8f72f..a55cff5b6 100644 --- a/library/src/api/BUILD.bazel +++ b/library/src/api/BUILD.bazel @@ -11,12 +11,25 @@ exports_files( visibility = ["//visibility:public"], ) +# Compile-time constants and macros shared with the whole solver. Kept as its +# own dependency-free target so //library/src/utility:constants can fold its +# bridge dimensions in here without a dependency cycle. +cc_library( + name = "dds_constants", + hdrs = ["dds_constants.hpp"], + include_prefix = "api", + visibility = ["//visibility:public"], + deps = [], +) + cc_library( name = "api_definitions", hdrs = [ "calc_dd_table.hpp", "calc_par.hpp", "dds.h", + "dds_c_data_types.h", + "dds_data_types.hpp", "dll.h", "dds_api.hpp", "dds_c_api.h", @@ -27,6 +40,7 @@ cc_library( include_prefix = "api", visibility = ["//visibility:public"], deps = [ + ":dds_constants", "//library/src/utility:constants", ], ) diff --git a/library/src/api/PBN.h b/library/src/api/PBN.h index 994c84a4e..4ba65cafa 100644 --- a/library/src/api/PBN.h +++ b/library/src/api/PBN.h @@ -9,7 +9,7 @@ #pragma once -#include +#include /** diff --git a/library/src/api/calc_dd_table.hpp b/library/src/api/calc_dd_table.hpp index 51e1cb734..b5f21a58e 100644 --- a/library/src/api/calc_dd_table.hpp +++ b/library/src/api/calc_dd_table.hpp @@ -12,7 +12,7 @@ #pragma once -#include +#include #include // Naming note: New C++ APIs in DDS 3 use snake_case (calc_dd_table). diff --git a/library/src/api/calc_par.hpp b/library/src/api/calc_par.hpp index 5dc3ebb51..f904a5fbf 100644 --- a/library/src/api/calc_par.hpp +++ b/library/src/api/calc_par.hpp @@ -11,7 +11,7 @@ #pragma once -#include +#include #include // Naming note: New C++ APIs in DDS 3 use snake_case (calc_par, calc_par_from_table). diff --git a/library/src/api/dds.h b/library/src/api/dds.h index 7d537d45e..3160632ca 100644 --- a/library/src/api/dds.h +++ b/library/src/api/dds.h @@ -16,199 +16,9 @@ #include #endif -// Project headers -#include - - -constexpr int THREADMEM_SMALL_MAX_MB = 30; -constexpr int THREADMEM_SMALL_DEF_MB = 20; -constexpr int THREADMEM_LARGE_MAX_MB = 160; -constexpr int THREADMEM_LARGE_DEF_MB = 95; - -constexpr int MAXNODE = 1; -constexpr int MINNODE = 0; - -constexpr int SIMILARDEALLIMIT = 5; -constexpr int SIMILARMAXWINNODES = 700000; - - -/* "hand" is leading hand, "relative" is hand relative leading -hand. -The handId macro implementation follows a solution -by Thomas Andrews. -All hand identities are given as -0=NORTH, 1=EAST, 2=SOUTH, 3=WEST. */ - -#include - -/** - * @brief Calculate relative hand position. - * @param hand Base hand position (0=NORTH, 1=EAST, 2=SOUTH, 3=WEST) - * @param relative Relative offset (0-3) - * @return Resulting hand position (0-3) - */ -#define HAND_ID(hand, relative) ((hand + relative) & 3) - -/** - * @brief Represents a single card move in the game. - * - * Contains information about a card that can be played, including - * its suit, rank, sequence status, and sorting weight. - */ -struct MoveType -{ - int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) - int rank; ///< Rank of the card (2-14: 2 through Ace) - int sequence; ///< Whether this move is the first in a sequence - int weight; ///< Weight used for sorting during move generation -}; - -/** - * @brief Collection of moves available at a single ply. - * - * Stores all possible moves at a given point in the game, - * along with tracking of current and last move indices. - */ -struct MovePlyType -{ - MoveType move[14]; ///< Array of possible moves (max 13 cards + sentinel) - int current; ///< Index of current move being considered - int last; ///< Index of last valid move in array -}; - -/** - * @brief Identifies a high card by rank and holding hand. - * - * Used to track high cards in each suit during analysis. - */ -struct HighCardType -{ - int rank; ///< Rank of the high card (2-14) - int hand; ///< Hand holding the card (0-3: N, E, S, W) -}; - -/** - * @brief Complete position state during game analysis. - * - * Represents the full state of a bridge position including card distribution, - * trump information, and current play state. This is the core data structure - * used throughout the solver. - */ -struct Pos -{ - unsigned short int rank_in_suit[DDS_HANDS][DDS_SUITS]; ///< Bitmask of ranks held by each hand in each suit - unsigned short int aggr[DDS_SUITS]; ///< Aggregate bitmask of all cards in each suit - unsigned char length[DDS_HANDS][DDS_SUITS]; ///< Number of cards each hand holds in each suit - int hand_dist[DDS_HANDS]; ///< Total number of cards held by each hand - - unsigned short int win_ranks[50][DDS_SUITS]; ///< Cards that win by rank at each depth - int first[50]; ///< Hand that leads the trick for each ply - MoveType move[50]; ///< Presently winning move at each ply - int hand_rel_first; ///< Current hand, relative to first hand - int tricks_max; ///< Aggregated tricks won by maximizing side - HighCardType winner[DDS_SUITS]; ///< Winning rank of trick in each suit - HighCardType second_best[DDS_SUITS]; ///< Second best rank in each suit -}; - -/** - * @brief Trick-level data for current play state. - * - * Tracks information about the current trick being played, - * including play counts, best cards, and lead information. - */ -struct TrickDataType -{ - int play_count[DDS_SUITS]; ///< Number of cards played in each suit - int best_rank; ///< Rank of best card played so far - int best_suit; ///< Suit of best card played so far - int best_sequence; ///< Sequence of best card - int rel_winner; ///< Relative position of current trick winner - int next_lead_hand; ///< Hand that will lead next trick -}; - -/** - * @brief Evaluation result for a position. - * - * Contains the number of tricks that can be won and which specific - * card ranks can win in each suit. - */ -struct EvalType -{ - int tricks; ///< Number of tricks that can be won from this position - unsigned short int win_ranks[DDS_SUITS]; ///< Bitmask of winning ranks in each suit -}; - -/** - * @brief Simple card representation. - * - * Basic structure identifying a card by suit and rank. - */ -struct Card -{ - int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) - int rank; ///< Rank of the card (2-14: 2 through Ace) -}; - -/** - * @brief Extended card representation with sequence information. - * - * Like Card but includes sequence information for tracking - * equivalent cards during move generation. - */ -struct ExtCard -{ - int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) - int rank; ///< Rank of the card (2-14: 2 through Ace) - int sequence; ///< Sequence identifier for equivalent cards -}; - -/** - * @brief Absolute rank with holding hand. - * - * Compact representation (2 bytes) identifying a card rank - * and which hand holds it. - */ -struct AbsRankType // 2 bytes -{ - char rank; ///< Rank of the card (2-14) - signed char hand; ///< Hand holding the card (0-3: N, E, S, W) -}; - -/** - * @brief Relative rank table for all suits. - * - * Contains absolute rank information for all possible card positions - * across all suits. Used for quick lookup during position analysis. - */ -struct RelRanksType // 120 bytes -{ - AbsRankType abs_rank[15][DDS_SUITS]; ///< Rank information indexed by position and suit -}; - -/** - * @brief Parameters for batch board solving. - * - * Contains input/output structures for solving multiple boards - * in a single operation. - */ -struct ParamType -{ - int no_of_boards; ///< Number of boards to solve - Boards const * bop; ///< Pointer to input boards - SolvedBoards * solvedp; ///< Pointer to output solutions - int error; ///< Error code from operation -}; - -/** - * @brief Execution mode for solver operations. - * - * Determines how the solver processes a position - solving for best play, - * calculating all possible outcomes, or tracing a specific line of play. - */ -enum class RunMode -{ - DDS_RUN_SOLVE = 0, ///< Solve mode: find optimal play - DDS_RUN_CALC = 1, ///< Calculate mode: compute all outcomes - DDS_RUN_TRACE = 2, ///< Trace mode: analyze specific play sequence - DDS_RUN_SIZE = 3 ///< Size sentinel (not a valid mode) -}; +// Aggregator for the solver's compile-time constants and data model. The +// public function-declaration surface (SolveBoard, CalcDDtable, ...) lives in +// and is included only by API consumers and the API implementation +// files, never by internal solver code. +#include +#include // also pulls in diff --git a/library/src/api/dds_c_api.h b/library/src/api/dds_c_api.h index 1e11053c2..d6c193fec 100644 --- a/library/src/api/dds_c_api.h +++ b/library/src/api/dds_c_api.h @@ -9,10 +9,11 @@ and ctypes a single clean, stable ABI to bind against. NOTE: the *exported symbols* are a pure C ABI, but this header is not itself - compilable by a C front-end: it includes , whose flat API is - declared with C++ trailing-return syntax (auto ... -> int). Consume the ABI - by binding to the compiled library's symbols (FFM/ctypes/.NET) or by parsing - the headers with a C++ mode (jextract); do not #include this from a C + compilable by a C front-end: it pulls in , which in + turn includes , where the shared constants are C++ + `constexpr` (and other declarations use C++-only syntax). Consume the ABI by + binding to the compiled library's symbols (FFM/ctypes/.NET) or by parsing + the headers with a C++ mode (jextract); do not include this from a C translation unit. See LICENSE and README. @@ -20,7 +21,7 @@ #pragma once -#include /* struct Deal, FutureTricks, DdTableDeal, DdTableResults, ParResults */ +#include /* struct Deal, FutureTricks, DdTableDeal, DdTableDealPBN, DdTableResults, ParResults; DLLEXPORT */ #ifdef __cplusplus extern "C" { diff --git a/library/src/api/dds_c_data_types.h b/library/src/api/dds_c_data_types.h new file mode 100644 index 000000000..cb10c18a8 --- /dev/null +++ b/library/src/api/dds_c_data_types.h @@ -0,0 +1,81 @@ +/* + DDS, a bridge double dummy solver. + + Copyright (C) 2006-2014 by Bo Haglund / + 2014-2018 by Bo Haglund & Soren Hein. + + See LICENSE and README. +*/ + +#pragma once + +/// @file dds_c_data_types.h +/// @brief The plain-old-data structures that cross the pure-C ABI shim. +/// +/// This is the subset of the legacy data types that appear in +/// `dds_c_api.h` signatures (`struct Deal`, `struct FutureTricks`, +/// `struct DdTableDeal`, `struct DdTableDealPBN`, `struct DdTableResults`, +/// `struct ParResults`). It is split out from `dds_data_types.hpp` so the +/// C-ABI shim can pull in exactly what it passes by pointer and nothing +/// else. Every remaining legacy and internal type lives in +/// `dds_data_types.hpp`, which includes this header. + +#include + +/** + * @brief Stores the result of a double dummy analysis for a single position. + * + * Contains the number of nodes searched, the number of cards in the result, + * and arrays for each card's suit, rank, equality group, and score. + */ +struct FutureTricks +{ + int nodes; + int cards; + int suit[13]; + int rank[13]; + int equals[13]; + int score[13]; +}; + +/** + * @brief Represents a bridge Deal for double dummy analysis. + * + * @param trump The trump suit (0 = NT, 1 = Spades, ...) + * @param first The hand to play first (0 = N, 1 = E, ...) + * @param currentTrickSuit Suits of cards played in the current trick + * @param currentTrickRank Ranks of cards played in the current trick + * @param remainCards Remaining cards in each hand and suit + */ +struct Deal +{ + int trump; + int first; + int currentTrickSuit[3]; + int currentTrickRank[3]; + unsigned int remainCards[DDS_HANDS][DDS_SUITS]; +}; + +struct DdTableDeal +{ + unsigned int cards[DDS_HANDS][DDS_SUITS]; +}; + +struct DdTableDealPBN +{ + char cards[80]; +}; + +struct DdTableResults +{ + int res_table[DDS_STRAINS][DDS_HANDS]; +}; + +struct ParResults +{ + /* index = 0 is NS view and index = 1 + is EW view. By 'view' is here meant + which side that starts the bidding. */ + char par_score[2][16]; + char par_contracts_string[2][128]; +}; diff --git a/library/src/api/dds_constants.hpp b/library/src/api/dds_constants.hpp new file mode 100644 index 000000000..2c848d8a5 --- /dev/null +++ b/library/src/api/dds_constants.hpp @@ -0,0 +1,239 @@ +/* + DDS, a bridge double dummy solver. + + Copyright (C) 2006-2014 by Bo Haglund / + 2014-2018 by Bo Haglund & Soren Hein. + + See LICENSE and README. +*/ + +#pragma once + +/// @file dds_constants.hpp +/// @brief Compile-time constants and macros shared across the whole solver. +/// +/// This header carries the values that other headers use to size arrays and +/// loop bounds: the fixed bridge dimensions, the frozen legacy-API version and +/// capacity limits, the solver status codes, and the export/calling-convention +/// macros. It defines no types and pulls in no other project header, so both +/// internal solver code and external API headers can include it without +/// dragging in the public function-declaration surface (`api/dll.h`). + +// --------------------------------------------------------------------------- +// Export / calling-convention macros +// --------------------------------------------------------------------------- + +#if (defined(_WIN32) || defined(__CYGWIN__)) && ! defined(__clang__) + #define DLLEXPORT __declspec(dllexport) + #define STDCALL __stdcall +#else + #define DLLEXPORT + #define STDCALL +#endif + +#ifdef __cplusplus + #define EXTERN_C extern "C" +#else + #define EXTERN_C + #include // make "bool" available +#endif + +// --------------------------------------------------------------------------- +// Fixed bridge dimensions +// --------------------------------------------------------------------------- + +/// @defgroup dds_dimensions Bridge dimensions +/// @{ +/// These are `constexpr` and are treated as immutable across the codebase — +/// array sizes and loop bounds everywhere assume them. +constexpr int DDS_STRAINS = 5; ///< Number of strains (4 suits + no trump) +constexpr int DDS_HANDS = 4; ///< Number of hands (N/E/S/W) +constexpr int DDS_SUITS = 4; ///< Number of suits (S/H/D/C) +constexpr int DDS_NOTRUMP = 4; ///< No trump strain index +/// @} + +// --------------------------------------------------------------------------- +// Legacy C API version and capacity limits +// --------------------------------------------------------------------------- + +/* Version 3.1.0. Allowing for 2 digit minor versions */ +// These three stay object-like macros: this is the frozen legacy C API surface +// and external consumers conventionally test the version / limits in the +// preprocessor (e.g. #if DDS_VERSION >= 30100, #ifdef MAXNOOFBOARDS). +#define DDS_VERSION 30100 + +#define MAXNOOFBOARDS 200 + +#define MAXNOOFTABLES 40 + +// --------------------------------------------------------------------------- +// Solver status codes +// --------------------------------------------------------------------------- + +// Error codes. See interface document for more detail. +// Call ErrorMessage(code, line[]) to get the text form in line[]. + +// Success. +constexpr int RETURN_NO_FAULT = 1; +constexpr const char TEXT_NO_FAULT[] = "Success"; + +// Currently happens when fopen() fails or when AnalyseAllPlaysBin() +// get a different number of Boards in its first two arguments. +constexpr int RETURN_UNKNOWN_FAULT = -1; +constexpr const char TEXT_UNKNOWN_FAULT[] = "General error"; + +// SolveBoard() +constexpr int RETURN_ZERO_CARDS = -2; +constexpr const char TEXT_ZERO_CARDS[] = "Zero cards"; + +// SolveBoard() +constexpr int RETURN_TARGET_TOO_HIGH = -3; +constexpr const char TEXT_TARGET_TOO_HIGH[] = + "Target exceeds number of tricks"; + +// SolveBoard() +constexpr int RETURN_DUPLICATE_CARDS = -4; +constexpr const char TEXT_DUPLICATE_CARDS[] = "Cards duplicated"; + +// SolveBoard() +constexpr int RETURN_TARGET_WRONG_LO = -5; +constexpr const char TEXT_TARGET_WRONG_LO[] = + "Target is less than -1"; + +// SolveBoard() +constexpr int RETURN_TARGET_WRONG_HI = -7; +constexpr const char TEXT_TARGET_WRONG_HI[] = + "Target is higher than 13"; + +// SolveBoard() +constexpr int RETURN_SOLNS_WRONG_LO = -8; +constexpr const char TEXT_SOLNS_WRONG_LO[] = + "Solutions parameter is less than 1"; + +// SolveBoard() +constexpr int RETURN_SOLNS_WRONG_HI = -9; +constexpr const char TEXT_SOLNS_WRONG_HI[] = + "Solutions parameter is higher than 3"; + +// SolveBoard(), self-explanatory. +constexpr int RETURN_TOO_MANY_CARDS = -10; +constexpr const char TEXT_TOO_MANY_CARDS[] = "Too many cards"; + +// SolveBoard() +constexpr int RETURN_SUIT_OR_RANK = -12; +constexpr const char TEXT_SUIT_OR_RANK[] = + "currentTrickSuit or currentTrickRank has wrong data"; + +// SolveBoard +constexpr int RETURN_PLAYED_CARD = -13; +constexpr const char TEXT_PLAYED_CARD[] = + "Played card also remains in a hand"; + +// SolveBoard() +constexpr int RETURN_CARD_COUNT = -14; +constexpr const char TEXT_CARD_COUNT[] = + "Wrong number of remaining cards in a hand"; + +// SolveBoard() +constexpr int RETURN_THREAD_INDEX = -15; +constexpr const char TEXT_THREAD_INDEX[] = + "Thread index is not 0 .. maximum"; + +// SolveBoard() +constexpr int RETURN_MODE_WRONG_LO = -16; +constexpr const char TEXT_MODE_WRONG_LO[] = + "Mode parameter is less than 0"; + +// SolveBoard() +constexpr int RETURN_MODE_WRONG_HI = -17; +constexpr const char TEXT_MODE_WRONG_HI[] = + "Mode parameter is higher than 2"; + +// SolveBoard() +constexpr int RETURN_TRUMP_WRONG = -18; +constexpr const char TEXT_TRUMP_WRONG[] = "Trump is not in 0 .. 4"; + +// SolveBoard() +constexpr int RETURN_FIRST_WRONG = -19; +constexpr const char TEXT_FIRST_WRONG[] = "First is not in 0 .. 2"; + +// AnalysePlay*() family of functions. +// (a) Less than 0 or more than 52 cards supplied. +// (b) Invalid suit or rank supplied. +// (c) A played card is not held by the right player. +constexpr int RETURN_PLAY_FAULT = -98; +constexpr const char TEXT_PLAY_FAULT[] = "AnalysePlay input error"; + +// Returned from a number of places if a PBN string is faulty. +constexpr int RETURN_PBN_FAULT = -99; +constexpr const char TEXT_PBN_FAULT[] = "PBN string error"; + +// SolveBoard() and AnalysePlay*() +constexpr int RETURN_TOO_MANY_BOARDS = -101; +constexpr const char TEXT_TOO_MANY_BOARDS[] = + "Too many Boards requested"; + +// Returned from multi-threading functions. +constexpr int RETURN_THREAD_CREATE = -102; +constexpr const char TEXT_THREAD_CREATE[] = + "Could not create threads"; + +// Returned from multi-threading functions when something went +// wrong while waiting for all threads to complete. +constexpr int RETURN_THREAD_WAIT = -103; +constexpr const char TEXT_THREAD_WAIT[] = + "Something failed waiting for thread to end"; + +// Tried to set a multi-threading system that is not present in DLL. +constexpr int RETURN_THREAD_MISSING = -104; +constexpr const char TEXT_THREAD_MISSING[] = + "Multi-threading system not present"; + +// CalcAllTables*() +constexpr int RETURN_NO_SUIT = -201; +constexpr const char TEXT_NO_SUIT[] = + "Denomination filter vector has no entries"; + +// CalcAllTables*() +constexpr int RETURN_TOO_MANY_TABLES = -202; +constexpr const char TEXT_TOO_MANY_TABLES[] = + "Too many DD tables requested"; + +// SolveAllChunks*() +constexpr int RETURN_CHUNK_SIZE = -301; +constexpr const char TEXT_CHUNK_SIZE[] = "Chunk size is less than 1"; + +// Par(), SidesPar(), SidesParBin(), DealerPar(), DealerParBin() +constexpr int RETURN_PAR_TABLE_FAULT = -401; +constexpr const char TEXT_PAR_TABLE_FAULT[] = + "Missing double dummy table, or an entry outside the range 0 to 13"; + +// --------------------------------------------------------------------------- +// Solver tuning constants +// --------------------------------------------------------------------------- + +constexpr int THREADMEM_SMALL_MAX_MB = 30; +constexpr int THREADMEM_SMALL_DEF_MB = 20; +constexpr int THREADMEM_LARGE_MAX_MB = 160; +constexpr int THREADMEM_LARGE_DEF_MB = 95; + +constexpr int MAXNODE = 1; +constexpr int MINNODE = 0; + +constexpr int SIMILARDEALLIMIT = 5; +constexpr int SIMILARMAXWINNODES = 700000; + +/* "hand" is leading hand, "relative" is hand relative leading +hand. +The handId macro implementation follows a solution +by Thomas Andrews. +All hand identities are given as +0=NORTH, 1=EAST, 2=SOUTH, 3=WEST. */ + +/** + * @brief Calculate relative hand position. + * @param hand Base hand position (0=NORTH, 1=EAST, 2=SOUTH, 3=WEST) + * @param relative Relative offset (0-3) + * @return Resulting hand position (0-3) + */ +#define HAND_ID(hand, relative) ((hand + relative) & 3) diff --git a/library/src/api/dds_data_types.hpp b/library/src/api/dds_data_types.hpp new file mode 100644 index 000000000..67313bc69 --- /dev/null +++ b/library/src/api/dds_data_types.hpp @@ -0,0 +1,414 @@ +/* + DDS, a bridge double dummy solver. + + Copyright (C) 2006-2014 by Bo Haglund / + 2014-2018 by Bo Haglund & Soren Hein. + + See LICENSE and README. +*/ + +#pragma once + +/// @file dds_data_types.hpp +/// @brief Every DDS data type that the pure-C ABI shim does not need. +/// +/// This is the internal / C++-side view of the solver's data model: the +/// legacy plain-old-data structures that never cross the `dds_c_api.h` +/// boundary (batch containers, PBN variants, the par-result family, play +/// traces, `DDSInfo`) plus the core search structures used throughout the +/// solver (`Pos`, `MoveType`, `EvalType`, ...). The C-ABI subset lives in +/// `dds_c_data_types.h`, which this header includes, so `#include +/// ` gives internal code the whole data model +/// without pulling in the public function-declaration surface +/// (`api/dll.h`). + +#include +#include +#include // card-representation lookup tables (lho/rho/partner, + // bit_map_rank, card_rank/suit/hand) + +// =========================================================================== +// Legacy plain-old-data structures (not part of the pure-C ABI shim) +// =========================================================================== + +/** + * @brief Represents a bridge Deal in PBN (Portable Bridge Notation) format. + * + * @param trump The trump suit + * @param first The hand to play first + * @param currentTrickSuit Suits of cards played in the current trick + * @param currentTrickRank Ranks of cards played in the current trick + * @param remainCards PBN string describing remaining cards. Only the first hand may have a compass letter (N/E/S/W); later hands follow clockwise with no extra directions. + */ +struct DealPBN +{ + int trump; + int first; + int currentTrickSuit[3]; + int currentTrickRank[3]; + char remainCards[80]; +}; + + +/** + * @brief Represents multiple bridge deals for batch analysis. + * + * @param noOfBoards Number of deals + * @param deals Array of deals + * @param target Array of targets for each Deal + * @param solutions Array of solution modes for each Deal + * @param mode Array of modes for each Deal + */ +struct Boards +{ + int no_of_boards; + struct Deal deals[MAXNOOFBOARDS]; + int target[MAXNOOFBOARDS]; + int solutions[MAXNOOFBOARDS]; + int mode[MAXNOOFBOARDS]; +}; + +/** + * @brief Multiple boards in PBN format for batch solving. + * + * Similar to Boards but uses PBN (Portable Bridge Notation) format + * for deal representation. Used for solving multiple boards efficiently. + * + * @see Boards + */ +struct BoardsPBN +{ + int no_of_boards; ///< Number of boards to solve + struct DealPBN deals[MAXNOOFBOARDS]; ///< Array of deals in PBN format + int target[MAXNOOFBOARDS]; ///< Target tricks for each board + int solutions[MAXNOOFBOARDS]; ///< Solution mode for each board + int mode[MAXNOOFBOARDS]; ///< Solve mode for each board +}; + +/** + * @brief Solutions for multiple boards. + * + * Container for results from batch board solving operations. + * Each entry contains the complete future tricks analysis for one board. + * + * @see FutureTricks + */ +struct SolvedBoards +{ + int no_of_boards; ///< Number of solved boards + struct FutureTricks solved_board[MAXNOOFBOARDS]; ///< Array of solutions +}; + +struct DdTableDeals +{ + int no_of_tables; + struct DdTableDeal deals[MAXNOOFTABLES * DDS_STRAINS]; +}; + +struct DdTableDealsPBN +{ + int no_of_tables; + struct DdTableDealPBN deals[MAXNOOFTABLES * DDS_STRAINS]; +}; + +struct DdTablesRes +{ + int no_of_boards; + struct DdTableResults results[MAXNOOFTABLES * DDS_STRAINS]; +}; + +struct AllParResults +{ + struct ParResults par_results[MAXNOOFTABLES]; +}; + +struct ParResultsDealer +{ + /* number: Number of contracts yielding the par score. + score: Par score for the specified dealer hand. + contracts: Par contract text strings. The first contract + is in contracts[0], the last one in contracts[number-1]. + The detailed text format is is given in the DLL interface + document. + */ + int number; + int score; + char contracts[10][10]; +}; + +struct ContractType +{ + int under_tricks; /* 0 = make 1-13 = sacrifice */ + int over_tricks; /* 0-3, e.g. 1 for 4S + 1. */ + int level; /* 1-7 */ + int denom; /* 0 = No Trumps, 1 = trump Spades, 2 = trump Hearts, + 3 = trump Diamonds, 4 = trump Clubs */ + int seats; /* One of the cases N, E, W, S, NS, EW; + 0 = N 1 = E, 2 = S, 3 = W, 4 = NS, 5 = EW */ +}; + +struct ParResultsMaster +{ + int score; /* Sign according to the NS view */ + int number; /* Number of contracts giving the par score */ + struct ContractType contracts[10]; /* Par contracts */ +}; + +struct ParTextResults +{ + char par_text[2][128]; /* Short text for par information, e.g. + Par -110: EW 2S EW 2D+1 */ + bool equal; /* true in the normal case when it does not matter who + starts the bidding. Otherwise, false. */ +}; + + +struct PlayTraceBin +{ + int number; + int suit[52]; + int rank[52]; +}; + +struct PlayTracePBN +{ + int number; + char cards[106]; +}; + +struct SolvedPlay +{ + int number; + int tricks[53]; +}; + +struct PlayTracesBin +{ + int no_of_boards; + struct PlayTraceBin plays[MAXNOOFBOARDS]; +}; + +struct PlayTracesPBN +{ + int no_of_boards; + struct PlayTracePBN plays[MAXNOOFBOARDS]; +}; + +struct SolvedPlays +{ + int no_of_boards; + struct SolvedPlay solved[MAXNOOFBOARDS]; +}; + +struct DDSInfo +{ + // Version 2.8.0 has 2, 8, 0 and a string of 2.8.0 + int major, minor, patch; + char version_string[10]; + + // Currently 0 = unknown, 1 = Windows, 2 = Cygwin, 3 = Linux, 4 = Apple + int system; + + // We know 32 and 64-bit systems. + int numBits; + + // Currently 0 = unknown, 1 = Microsoft Visual C++, 2 = mingw, + // 3 = GNU g++, 4 = clang + int compiler; + + // Currently 0 = none, 1 = DllMain, 2 = Unix-style + int constructor; + + int numCores; + + // Currently + // 0 = none, + // 1 = Windows (native), + // 2 = OpenMP, + // 3 = GCD, + // 4 = Boost, + // 5 = STL, + // 6 = TBB, + // 7 = STLIMPL (for_each), experimental only + // 8 = PPLIMPL (for_each), experimental only + int threading; + + // The actual number of threads configured + int noOfThreads; + + // This will break if there are > 128 threads... + // The string is of the form LLLSSS meaning 3 large TT memories + // and 3 small ones. + char threadSizes[128]; + + char systemString[1024]; +}; + + +// =========================================================================== +// Core search structures used throughout the solver +// =========================================================================== + +/** + * @brief Represents a single card move in the game. + * + * Contains information about a card that can be played, including + * its suit, rank, sequence status, and sorting weight. + */ +struct MoveType +{ + int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) + int rank; ///< Rank of the card (2-14: 2 through Ace) + int sequence; ///< Whether this move is the first in a sequence + int weight; ///< Weight used for sorting during move generation +}; + +/** + * @brief Collection of moves available at a single ply. + * + * Stores all possible moves at a given point in the game, + * along with tracking of current and last move indices. + */ +struct MovePlyType +{ + MoveType move[14]; ///< Array of possible moves (max 13 cards + sentinel) + int current; ///< Index of current move being considered + int last; ///< Index of last valid move in array +}; + +/** + * @brief Identifies a high card by rank and holding hand. + * + * Used to track high cards in each suit during analysis. + */ +struct HighCardType +{ + int rank; ///< Rank of the high card (2-14) + int hand; ///< Hand holding the card (0-3: N, E, S, W) +}; + +/** + * @brief Complete position state during game analysis. + * + * Represents the full state of a bridge position including card distribution, + * trump information, and current play state. This is the core data structure + * used throughout the solver. + */ +struct Pos +{ + unsigned short int rank_in_suit[DDS_HANDS][DDS_SUITS]; ///< Bitmask of ranks held by each hand in each suit + unsigned short int aggr[DDS_SUITS]; ///< Aggregate bitmask of all cards in each suit + unsigned char length[DDS_HANDS][DDS_SUITS]; ///< Number of cards each hand holds in each suit + int hand_dist[DDS_HANDS]; ///< Total number of cards held by each hand + + unsigned short int win_ranks[50][DDS_SUITS]; ///< Cards that win by rank at each depth + int first[50]; ///< Hand that leads the trick for each ply + MoveType move[50]; ///< Presently winning move at each ply + int hand_rel_first; ///< Current hand, relative to first hand + int tricks_max; ///< Aggregated tricks won by maximizing side + HighCardType winner[DDS_SUITS]; ///< Winning rank of trick in each suit + HighCardType second_best[DDS_SUITS]; ///< Second best rank in each suit +}; + +/** + * @brief Trick-level data for current play state. + * + * Tracks information about the current trick being played, + * including play counts, best cards, and lead information. + */ +struct TrickDataType +{ + int play_count[DDS_SUITS]; ///< Number of cards played in each suit + int best_rank; ///< Rank of best card played so far + int best_suit; ///< Suit of best card played so far + int best_sequence; ///< Sequence of best card + int rel_winner; ///< Relative position of current trick winner + int next_lead_hand; ///< Hand that will lead next trick +}; + +/** + * @brief Evaluation result for a position. + * + * Contains the number of tricks that can be won and which specific + * card ranks can win in each suit. + */ +struct EvalType +{ + int tricks; ///< Number of tricks that can be won from this position + unsigned short int win_ranks[DDS_SUITS]; ///< Bitmask of winning ranks in each suit +}; + +/** + * @brief Simple card representation. + * + * Basic structure identifying a card by suit and rank. + */ +struct Card +{ + int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) + int rank; ///< Rank of the card (2-14: 2 through Ace) +}; + +/** + * @brief Extended card representation with sequence information. + * + * Like Card but includes sequence information for tracking + * equivalent cards during move generation. + */ +struct ExtCard +{ + int suit; ///< Suit of the card (0-3: spades, hearts, diamonds, clubs) + int rank; ///< Rank of the card (2-14: 2 through Ace) + int sequence; ///< Sequence identifier for equivalent cards +}; + +/** + * @brief Absolute rank with holding hand. + * + * Compact representation (2 bytes) identifying a card rank + * and which hand holds it. + */ +struct AbsRankType // 2 bytes +{ + char rank; ///< Rank of the card (2-14) + signed char hand; ///< Hand holding the card (0-3: N, E, S, W) +}; + +/** + * @brief Relative rank table for all suits. + * + * Contains absolute rank information for all possible card positions + * across all suits. Used for quick lookup during position analysis. + */ +struct RelRanksType // 120 bytes +{ + AbsRankType abs_rank[15][DDS_SUITS]; ///< Rank information indexed by position and suit +}; + +/** + * @brief Parameters for batch board solving. + * + * Contains input/output structures for solving multiple boards + * in a single operation. + */ +struct ParamType +{ + int no_of_boards; ///< Number of boards to solve + Boards const * bop; ///< Pointer to input boards + SolvedBoards * solvedp; ///< Pointer to output solutions + int error; ///< Error code from operation +}; + +/** + * @brief Execution mode for solver operations. + * + * Determines how the solver processes a position - solving for best play, + * calculating all possible outcomes, or tracing a specific line of play. + */ +enum class RunMode +{ + DDS_RUN_SOLVE = 0, ///< Solve mode: find optimal play + DDS_RUN_CALC = 1, ///< Calculate mode: compute all outcomes + DDS_RUN_TRACE = 2, ///< Trace mode: analyze specific play sequence + DDS_RUN_SIZE = 3 ///< Size sentinel (not a valid mode) +}; diff --git a/library/src/api/dll.h b/library/src/api/dll.h index b6050aa3f..d77c9aec8 100644 --- a/library/src/api/dll.h +++ b/library/src/api/dll.h @@ -10,447 +10,18 @@ #pragma once -#include - -#if (defined(_WIN32) || defined(__CYGWIN__)) && ! defined(__clang__) - #define DLLEXPORT __declspec(dllexport) - #define STDCALL __stdcall -#else - #define DLLEXPORT - #define STDCALL -#endif - -#ifdef __cplusplus - #define EXTERN_C extern "C" -#else - #define EXTERN_C - #include // make "bool" available -#endif - -/* Version 3.1.0. Allowing for 2 digit minor versions */ -// These three stay object-like macros: this is the frozen legacy C API -// header and external consumers conventionally test the version / limits in -// the preprocessor (e.g. #if DDS_VERSION >= 30100, #ifdef MAXNOOFBOARDS). -#define DDS_VERSION 30100 - -#define MAXNOOFBOARDS 200 - -#define MAXNOOFTABLES 40 - - -// Error codes. See interface document for more detail. -// Call ErrorMessage(code, line[]) to get the text form in line[]. - -// Success. -constexpr int RETURN_NO_FAULT = 1; -constexpr const char TEXT_NO_FAULT[] = "Success"; - -// Currently happens when fopen() fails or when AnalyseAllPlaysBin() -// get a different number of Boards in its first two arguments. -constexpr int RETURN_UNKNOWN_FAULT = -1; -constexpr const char TEXT_UNKNOWN_FAULT[] = "General error"; - -// SolveBoard() -constexpr int RETURN_ZERO_CARDS = -2; -constexpr const char TEXT_ZERO_CARDS[] = "Zero cards"; - -// SolveBoard() -constexpr int RETURN_TARGET_TOO_HIGH = -3; -constexpr const char TEXT_TARGET_TOO_HIGH[] = - "Target exceeds number of tricks"; - -// SolveBoard() -constexpr int RETURN_DUPLICATE_CARDS = -4; -constexpr const char TEXT_DUPLICATE_CARDS[] = "Cards duplicated"; - -// SolveBoard() -constexpr int RETURN_TARGET_WRONG_LO = -5; -constexpr const char TEXT_TARGET_WRONG_LO[] = - "Target is less than -1"; - -// SolveBoard() -constexpr int RETURN_TARGET_WRONG_HI = -7; -constexpr const char TEXT_TARGET_WRONG_HI[] = - "Target is higher than 13"; - -// SolveBoard() -constexpr int RETURN_SOLNS_WRONG_LO = -8; -constexpr const char TEXT_SOLNS_WRONG_LO[] = - "Solutions parameter is less than 1"; - -// SolveBoard() -constexpr int RETURN_SOLNS_WRONG_HI = -9; -constexpr const char TEXT_SOLNS_WRONG_HI[] = - "Solutions parameter is higher than 3"; - -// SolveBoard(), self-explanatory. -constexpr int RETURN_TOO_MANY_CARDS = -10; -constexpr const char TEXT_TOO_MANY_CARDS[] = "Too many cards"; - -// SolveBoard() -constexpr int RETURN_SUIT_OR_RANK = -12; -constexpr const char TEXT_SUIT_OR_RANK[] = - "currentTrickSuit or currentTrickRank has wrong data"; - -// SolveBoard -constexpr int RETURN_PLAYED_CARD = -13; -constexpr const char TEXT_PLAYED_CARD[] = - "Played card also remains in a hand"; - -// SolveBoard() -constexpr int RETURN_CARD_COUNT = -14; -constexpr const char TEXT_CARD_COUNT[] = - "Wrong number of remaining cards in a hand"; - -// SolveBoard() -constexpr int RETURN_THREAD_INDEX = -15; -constexpr const char TEXT_THREAD_INDEX[] = - "Thread index is not 0 .. maximum"; - -// SolveBoard() -constexpr int RETURN_MODE_WRONG_LO = -16; -constexpr const char TEXT_MODE_WRONG_LO[] = - "Mode parameter is less than 0"; - -// SolveBoard() -constexpr int RETURN_MODE_WRONG_HI = -17; -constexpr const char TEXT_MODE_WRONG_HI[] = - "Mode parameter is higher than 2"; - -// SolveBoard() -constexpr int RETURN_TRUMP_WRONG = -18; -constexpr const char TEXT_TRUMP_WRONG[] = "Trump is not in 0 .. 4"; - -// SolveBoard() -constexpr int RETURN_FIRST_WRONG = -19; -constexpr const char TEXT_FIRST_WRONG[] = "First is not in 0 .. 2"; - -// AnalysePlay*() family of functions. -// (a) Less than 0 or more than 52 cards supplied. -// (b) Invalid suit or rank supplied. -// (c) A played card is not held by the right player. -constexpr int RETURN_PLAY_FAULT = -98; -constexpr const char TEXT_PLAY_FAULT[] = "AnalysePlay input error"; - -// Returned from a number of places if a PBN string is faulty. -constexpr int RETURN_PBN_FAULT = -99; -constexpr const char TEXT_PBN_FAULT[] = "PBN string error"; - -// SolveBoard() and AnalysePlay*() -constexpr int RETURN_TOO_MANY_BOARDS = -101; -constexpr const char TEXT_TOO_MANY_BOARDS[] = - "Too many Boards requested"; - -// Returned from multi-threading functions. -constexpr int RETURN_THREAD_CREATE = -102; -constexpr const char TEXT_THREAD_CREATE[] = - "Could not create threads"; - -// Returned from multi-threading functions when something went -// wrong while waiting for all threads to complete. -constexpr int RETURN_THREAD_WAIT = -103; -constexpr const char TEXT_THREAD_WAIT[] = - "Something failed waiting for thread to end"; - -// Tried to set a multi-threading system that is not present in DLL. -constexpr int RETURN_THREAD_MISSING = -104; -constexpr const char TEXT_THREAD_MISSING[] = - "Multi-threading system not present"; - -// CalcAllTables*() -constexpr int RETURN_NO_SUIT = -201; -constexpr const char TEXT_NO_SUIT[] = - "Denomination filter vector has no entries"; - -// CalcAllTables*() -constexpr int RETURN_TOO_MANY_TABLES = -202; -constexpr const char TEXT_TOO_MANY_TABLES[] = - "Too many DD tables requested"; - -// SolveAllChunks*() -constexpr int RETURN_CHUNK_SIZE = -301; -constexpr const char TEXT_CHUNK_SIZE[] = "Chunk size is less than 1"; - -// Par(), SidesPar(), SidesParBin(), DealerPar(), DealerParBin() -constexpr int RETURN_PAR_TABLE_FAULT = -401; -constexpr const char TEXT_PAR_TABLE_FAULT[] = - "Missing double dummy table, or an entry outside the range 0 to 13"; - - - -/** - * @brief Stores the result of a double dummy analysis for a single position. - * - * Contains the number of nodes searched, the number of cards in the result, - * and arrays for each card's suit, rank, equality group, and score. - */ -struct FutureTricks -{ - int nodes; - int cards; - int suit[13]; - int rank[13]; - int equals[13]; - int score[13]; -}; - -/** - * @brief Represents a bridge Deal for double dummy analysis. - * - * @param trump The trump suit (0 = NT, 1 = Spades, ...) - * @param first The hand to play first (0 = N, 1 = E, ...) - * @param currentTrickSuit Suits of cards played in the current trick - * @param currentTrickRank Ranks of cards played in the current trick - * @param remainCards Remaining cards in each hand and suit - */ -struct Deal -{ - int trump; - int first; - int currentTrickSuit[3]; - int currentTrickRank[3]; - unsigned int remainCards[DDS_HANDS][DDS_SUITS]; -}; - - -/** - * @brief Represents a bridge Deal in PBN (Portable Bridge Notation) format. - * - * @param trump The trump suit - * @param first The hand to play first - * @param currentTrickSuit Suits of cards played in the current trick - * @param currentTrickRank Ranks of cards played in the current trick - * @param remainCards PBN string describing remaining cards. Only the first hand may have a compass letter (N/E/S/W); later hands follow clockwise with no extra directions. - */ -struct DealPBN -{ - int trump; - int first; - int currentTrickSuit[3]; - int currentTrickRank[3]; - char remainCards[80]; -}; - - -/** - * @brief Represents multiple bridge deals for batch analysis. - * - * @param noOfBoards Number of deals - * @param deals Array of deals - * @param target Array of targets for each Deal - * @param solutions Array of solution modes for each Deal - * @param mode Array of modes for each Deal - */ -struct Boards -{ - int no_of_boards; - struct Deal deals[MAXNOOFBOARDS]; - int target[MAXNOOFBOARDS]; - int solutions[MAXNOOFBOARDS]; - int mode[MAXNOOFBOARDS]; -}; - -/** - * @brief Multiple boards in PBN format for batch solving. - * - * Similar to Boards but uses PBN (Portable Bridge Notation) format - * for deal representation. Used for solving multiple boards efficiently. - * - * @see Boards - */ -struct BoardsPBN -{ - int no_of_boards; ///< Number of boards to solve - struct DealPBN deals[MAXNOOFBOARDS]; ///< Array of deals in PBN format - int target[MAXNOOFBOARDS]; ///< Target tricks for each board - int solutions[MAXNOOFBOARDS]; ///< Solution mode for each board - int mode[MAXNOOFBOARDS]; ///< Solve mode for each board -}; - -/** - * @brief Solutions for multiple boards. - * - * Container for results from batch board solving operations. - * Each entry contains the complete future tricks analysis for one board. - * - * @see FutureTricks - */ -struct SolvedBoards -{ - int no_of_boards; ///< Number of solved boards - struct FutureTricks solved_board[MAXNOOFBOARDS]; ///< Array of solutions -}; - -struct DdTableDeal -{ - unsigned int cards[DDS_HANDS][DDS_SUITS]; -}; - -struct DdTableDeals -{ - int no_of_tables; - struct DdTableDeal deals[MAXNOOFTABLES * DDS_STRAINS]; -}; - -struct DdTableDealPBN -{ - char cards[80]; -}; - -struct DdTableDealsPBN -{ - int no_of_tables; - struct DdTableDealPBN deals[MAXNOOFTABLES * DDS_STRAINS]; -}; - -struct DdTableResults -{ - int res_table[DDS_STRAINS][DDS_HANDS]; -}; - -struct DdTablesRes -{ - int no_of_boards; - struct DdTableResults results[MAXNOOFTABLES * DDS_STRAINS]; -}; - -struct ParResults -{ - /* index = 0 is NS view and index = 1 - is EW view. By 'view' is here meant - which side that starts the bidding. */ - char par_score[2][16]; - char par_contracts_string[2][128]; -}; - -struct AllParResults -{ - struct ParResults par_results[MAXNOOFTABLES]; -}; - -struct ParResultsDealer -{ - /* number: Number of contracts yielding the par score. - score: Par score for the specified dealer hand. - contracts: Par contract text strings. The first contract - is in contracts[0], the last one in contracts[number-1]. - The detailed text format is is given in the DLL interface - document. - */ - int number; - int score; - char contracts[10][10]; -}; - -struct ContractType -{ - int under_tricks; /* 0 = make 1-13 = sacrifice */ - int over_tricks; /* 0-3, e.g. 1 for 4S + 1. */ - int level; /* 1-7 */ - int denom; /* 0 = No Trumps, 1 = trump Spades, 2 = trump Hearts, - 3 = trump Diamonds, 4 = trump Clubs */ - int seats; /* One of the cases N, E, W, S, NS, EW; - 0 = N 1 = E, 2 = S, 3 = W, 4 = NS, 5 = EW */ -}; - -struct ParResultsMaster -{ - int score; /* Sign according to the NS view */ - int number; /* Number of contracts giving the par score */ - struct ContractType contracts[10]; /* Par contracts */ -}; - -struct ParTextResults -{ - char par_text[2][128]; /* Short text for par information, e.g. - Par -110: EW 2S EW 2D+1 */ - bool equal; /* true in the normal case when it does not matter who - starts the bidding. Otherwise, false. */ -}; - - -struct PlayTraceBin -{ - int number; - int suit[52]; - int rank[52]; -}; - -struct PlayTracePBN -{ - int number; - char cards[106]; -}; - -struct SolvedPlay -{ - int number; - int tricks[53]; -}; - -struct PlayTracesBin -{ - int no_of_boards; - struct PlayTraceBin plays[MAXNOOFBOARDS]; -}; - -struct PlayTracesPBN -{ - int no_of_boards; - struct PlayTracePBN plays[MAXNOOFBOARDS]; -}; - -struct SolvedPlays -{ - int no_of_boards; - struct SolvedPlay solved[MAXNOOFBOARDS]; -}; - -struct DDSInfo -{ - // Version 2.8.0 has 2, 8, 0 and a string of 2.8.0 - int major, minor, patch; - char version_string[10]; - - // Currently 0 = unknown, 1 = Windows, 2 = Cygwin, 3 = Linux, 4 = Apple - int system; - - // We know 32 and 64-bit systems. - int numBits; - - // Currently 0 = unknown, 1 = Microsoft Visual C++, 2 = mingw, - // 3 = GNU g++, 4 = clang - int compiler; - - // Currently 0 = none, 1 = DllMain, 2 = Unix-style - int constructor; - - int numCores; - - // Currently - // 0 = none, - // 1 = Windows (native), - // 2 = OpenMP, - // 3 = GCD, - // 4 = Boost, - // 5 = STL, - // 6 = TBB, - // 7 = STLIMPL (for_each), experimental only - // 8 = PPLIMPL (for_each), experimental only - int threading; - - // The actual number of threads configured - int noOfThreads; - - // This will break if there are > 128 threads... - // The string is of the form LLLSSS meaning 3 large TT memories - // and 3 small ones. - char threadSizes[128]; - - char systemString[1024]; -}; - - +/// @file dll.h +/// @brief The flat legacy C API: the historical Haglund/Hein entry points. +/// +/// This is the public function-declaration surface. It is included only by API +/// consumers (examples, bindings, tests) and by the API implementation files +/// that define these symbols — never by internal solver code, which takes the +/// data model from and the constants from +/// directly. + +#include // DLLEXPORT / STDCALL / EXTERN_C, DDS_VERSION, + // MAXNOOFBOARDS, MAXNOOFTABLES, RETURN_* / TEXT_* +#include // struct Deal, Boards, FutureTricks, DdTable*, Par*, ... /** * @brief Initialize the solver's static memory. @@ -798,7 +369,7 @@ EXTERN_C DLLEXPORT auto STDCALL DealerPar( EXTERN_C DLLEXPORT auto STDCALL DealerParBin( struct DdTableResults const * tablep, struct ParResultsMaster * presp, - int dealer, + int dealer, int vulnerable) -> int; EXTERN_C DLLEXPORT auto STDCALL SidesParBin( diff --git a/library/src/api/solve_board.hpp b/library/src/api/solve_board.hpp index 50f056f1f..a7e3bcb75 100644 --- a/library/src/api/solve_board.hpp +++ b/library/src/api/solve_board.hpp @@ -11,7 +11,7 @@ #pragma once -#include +#include #include /** diff --git a/library/src/calc_tables.cpp b/library/src/calc_tables.cpp index 7e69f831f..7d1f8a2dc 100644 --- a/library/src/calc_tables.cpp +++ b/library/src/calc_tables.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/library/src/calc_tables.hpp b/library/src/calc_tables.hpp index 249c3b5b2..939791f61 100644 --- a/library/src/calc_tables.hpp +++ b/library/src/calc_tables.hpp @@ -11,7 +11,7 @@ #include -#include +#include #include diff --git a/library/src/dump.hpp b/library/src/dump.hpp index a2bcd247f..f75779fb2 100644 --- a/library/src/dump.hpp +++ b/library/src/dump.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include #include diff --git a/library/src/heuristic_sorting/heuristic_sorting.hpp b/library/src/heuristic_sorting/heuristic_sorting.hpp index ced35abfc..53fce940b 100644 --- a/library/src/heuristic_sorting/heuristic_sorting.hpp +++ b/library/src/heuristic_sorting/heuristic_sorting.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include /// @brief Track information for maintaining position state during move generation. /// diff --git a/library/src/init.cpp b/library/src/init.cpp index 17feb0f29..fa3b9efaf 100644 --- a/library/src/init.cpp +++ b/library/src/init.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include System sysdep; diff --git a/library/src/init.hpp b/library/src/init.hpp index 0c84da692..0cda60511 100644 --- a/library/src/init.hpp +++ b/library/src/init.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include #include #include diff --git a/library/src/later_tricks.hpp b/library/src/later_tricks.hpp index 952105323..506d03cc8 100644 --- a/library/src/later_tricks.hpp +++ b/library/src/later_tricks.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include diff --git a/library/src/moves/moves.hpp b/library/src/moves/moves.hpp index a798a9c5f..196310cd2 100644 --- a/library/src/moves/moves.hpp +++ b/library/src/moves/moves.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include /** diff --git a/library/src/par.cpp b/library/src/par.cpp index a40f4d3ec..878c32eb5 100644 --- a/library/src/par.cpp +++ b/library/src/par.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include using namespace std; diff --git a/library/src/par_validate.hpp b/library/src/par_validate.hpp index d324b57e3..fd1c58468 100644 --- a/library/src/par_validate.hpp +++ b/library/src/par_validate.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include /** diff --git a/library/src/pbn.cpp b/library/src/pbn.cpp index 4ec56fec7..625ad8367 100644 --- a/library/src/pbn.cpp +++ b/library/src/pbn.cpp @@ -8,7 +8,7 @@ */ #include "pbn.hpp" -#include +#include #include constexpr int PbnBufferSize = static_cast(sizeof(DealPBN::remainCards)); diff --git a/library/src/pbn.hpp b/library/src/pbn.hpp index 994c84a4e..4ba65cafa 100644 --- a/library/src/pbn.hpp +++ b/library/src/pbn.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include /** diff --git a/library/src/play_analyser.cpp b/library/src/play_analyser.cpp index d9c8e916f..8848a2edf 100644 --- a/library/src/play_analyser.cpp +++ b/library/src/play_analyser.cpp @@ -8,6 +8,7 @@ */ #include "play_analyser.hpp" +#include #include #include #include diff --git a/library/src/play_analyser.hpp b/library/src/play_analyser.hpp index 80560a1c0..a649d0756 100644 --- a/library/src/play_analyser.hpp +++ b/library/src/play_analyser.hpp @@ -11,7 +11,7 @@ #include -#include +#include void detect_play_duplicates( diff --git a/library/src/quick_tricks.hpp b/library/src/quick_tricks.hpp index f775d9572..5b28eafee 100644 --- a/library/src/quick_tricks.hpp +++ b/library/src/quick_tricks.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include #include diff --git a/library/src/solve_board.cpp b/library/src/solve_board.cpp index 575d141f7..089110973 100644 --- a/library/src/solve_board.cpp +++ b/library/src/solve_board.cpp @@ -11,6 +11,7 @@ #include "solve_board.hpp" #include +#include #include #include #include diff --git a/library/src/solve_board.hpp b/library/src/solve_board.hpp index 5032aea06..cb8011d81 100644 --- a/library/src/solve_board.hpp +++ b/library/src/solve_board.hpp @@ -11,7 +11,7 @@ #include -#include +#include auto solve_all_boards_n( diff --git a/library/src/solver_context/solver_context.cpp b/library/src/solver_context/solver_context.cpp index 8344caff3..ad866c035 100644 --- a/library/src/solver_context/solver_context.cpp +++ b/library/src/solver_context/solver_context.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include //#include #include #include diff --git a/library/src/solver_if.cpp b/library/src/solver_if.cpp index 544b0375d..f935f004e 100644 --- a/library/src/solver_if.cpp +++ b/library/src/solver_if.cpp @@ -12,6 +12,7 @@ #include #include "solver_if.hpp" #include +#include #include #include #include diff --git a/library/src/solver_if.hpp b/library/src/solver_if.hpp index 332a0f4c0..e5b6fcb0f 100644 --- a/library/src/solver_if.hpp +++ b/library/src/solver_if.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include #include #include diff --git a/library/src/system/deal_fanout.hpp b/library/src/system/deal_fanout.hpp index 48fc5956e..adbbecbd6 100644 --- a/library/src/system/deal_fanout.hpp +++ b/library/src/system/deal_fanout.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace dds { diff --git a/library/src/system/memory.hpp b/library/src/system/memory.hpp index 1edd6030d..ff8112f31 100644 --- a/library/src/system/memory.hpp +++ b/library/src/system/memory.hpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include diff --git a/library/src/system/parallel_boards.cpp b/library/src/system/parallel_boards.cpp index 306336f4b..7ab1c68ed 100644 --- a/library/src/system/parallel_boards.cpp +++ b/library/src/system/parallel_boards.cpp @@ -21,10 +21,7 @@ #include #include -#if defined(__EMSCRIPTEN__) -#include -#endif -#include +#include namespace diff --git a/library/src/system/scheduler.hpp b/library/src/system/scheduler.hpp index 772357ca7..d226be4a3 100644 --- a/library/src/system/scheduler.hpp +++ b/library/src/system/scheduler.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include // TimeStatList is required when DDS_SCHEDULER is enabled. #ifdef DDS_SCHEDULER diff --git a/library/src/system/system.hpp b/library/src/system/system.hpp index 0851033c4..a8e758ba4 100644 --- a/library/src/system/system.hpp +++ b/library/src/system/system.hpp @@ -18,7 +18,7 @@ #include #include -#include +#include using namespace std; diff --git a/library/src/system/thread_data.hpp b/library/src/system/thread_data.hpp index 19d4646b1..a9b1035d0 100644 --- a/library/src/system/thread_data.hpp +++ b/library/src/system/thread_data.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include diff --git a/library/src/table_deal_validate.hpp b/library/src/table_deal_validate.hpp index 3c8e28c49..bd065141b 100644 --- a/library/src/table_deal_validate.hpp +++ b/library/src/table_deal_validate.hpp @@ -9,7 +9,7 @@ #pragma once -#include +#include /** diff --git a/library/src/trans_table/trans_table.hpp b/library/src/trans_table/trans_table.hpp index 8e84b1d5d..88e64c119 100644 --- a/library/src/trans_table/trans_table.hpp +++ b/library/src/trans_table/trans_table.hpp @@ -16,7 +16,7 @@ #pragma once #include -#include +#include /// \brief Enumeration of reasons that triggered a transposition table memory reset. /// diff --git a/library/src/trans_table/trans_table_s.cpp b/library/src/trans_table/trans_table_s.cpp index 7eac75708..f51980b83 100644 --- a/library/src/trans_table/trans_table_s.cpp +++ b/library/src/trans_table/trans_table_s.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include "trans_table_s.hpp" diff --git a/library/src/utility/BUILD.bazel b/library/src/utility/BUILD.bazel index 214f0e9fc..86682357d 100644 --- a/library/src/utility/BUILD.bazel +++ b/library/src/utility/BUILD.bazel @@ -16,6 +16,6 @@ cc_library( "//library/src:__subpackages__", "//library/tests:__subpackages__" ], - deps = [], + deps = ["//library/src/api:dds_constants"], ) diff --git a/library/src/utility/constants.h b/library/src/utility/constants.h index 322cc0772..8f5f7e113 100644 --- a/library/src/utility/constants.h +++ b/library/src/utility/constants.h @@ -10,15 +10,15 @@ #pragma once /// @file constants.h -/// @brief Utility constants and lookup tables for card representation. +/// @brief Utility lookup tables for card representation. /// @defgroup utility_constants Utility Constants /// @{ -/// Global bridge game dimensions -constexpr int DDS_STRAINS = 5; ///< Number of strains (4 suits + no trump) -constexpr int DDS_HANDS = 4; ///< Number of hands (N/E/S/W) -constexpr int DDS_SUITS = 4; ///< Number of suits (S/H/D/C) -constexpr int DDS_NOTRUMP = 4; ///< No trump strain index +/// The fixed bridge dimensions (DDS_STRAINS / DDS_HANDS / DDS_SUITS / +/// DDS_NOTRUMP) now live in alongside the other +/// compile-time constants; this header only declares the card-representation +/// lookup tables. +#include /// @name Hand Relationship Arrays /// Precomputed lookup tables for hand relationships. Each array maps diff --git a/library/tests/solve_board/analyse_play_consistency.cpp b/library/tests/solve_board/analyse_play_consistency.cpp index 217e0e956..bb7a37ace 100644 --- a/library/tests/solve_board/analyse_play_consistency.cpp +++ b/library/tests/solve_board/analyse_play_consistency.cpp @@ -21,6 +21,7 @@ // Project headers #include +#include namespace { diff --git a/library/tests/solve_board/trick_three_bug.cpp b/library/tests/solve_board/trick_three_bug.cpp index 2e5652377..0f6e6acdd 100644 --- a/library/tests/solve_board/trick_three_bug.cpp +++ b/library/tests/solve_board/trick_three_bug.cpp @@ -11,6 +11,7 @@ // Project headers #include +#include class TrickThreeBugTests : public ::testing::Test { diff --git a/solution/DDS.vcxproj b/solution/DDS.vcxproj index 00dd562eb..94b0338c6 100644 --- a/solution/DDS.vcxproj +++ b/solution/DDS.vcxproj @@ -112,6 +112,9 @@ + + + diff --git a/solution/DDS.vcxproj.filters b/solution/DDS.vcxproj.filters index 6d0f00db1..ed80854ad 100644 --- a/solution/DDS.vcxproj.filters +++ b/solution/DDS.vcxproj.filters @@ -212,6 +212,18 @@ library\src\api + + library\src\api + + + + library\src\api + + + + library\src\api + + library\src\api diff --git a/specs/constants-and-debug.md b/specs/constants-and-debug.md index 0a1f3db83..85fe29a06 100644 --- a/specs/constants-and-debug.md +++ b/specs/constants-and-debug.md @@ -29,7 +29,9 @@ single, authoritative definition of "how a card/hand/strain is represented" and - **Fixed dimensions.** `DDS_STRAINS = 5` (4 suits + NT), `DDS_HANDS = 4`, `DDS_SUITS = 4`, `DDS_NOTRUMP = 4`. These are `constexpr` and are treated as immutable across the codebase — array sizes and loop bounds everywhere assume - them. + them. They are defined in `` (alongside the other + compile-time constants); `constants.h` includes it and only declares the + lookup tables. - **Hand-relationship arrays** (`lho`, `rho`, `partner`) map an absolute hand 0–3 to its left-hand opponent / right-hand opponent / partner. Consumers rely on the seating convention: hands are ordered N(0)/E(1)/S(2)/W(3) going @@ -56,8 +58,12 @@ single, authoritative definition of "how a card/hand/strain is represented" and ## Key entry points -- `library/src/utility/constants.h` — dimensions, hand-relationship arrays, and - card lookup tables (declarations). Doxygen: group `utility_constants`. +- `library/src/api/dds_constants.hpp` — the fixed bridge dimensions plus the + rest of the solver's compile-time constants and export macros. Build target: + `//library/src/api:dds_constants` (dependency-free). +- `library/src/utility/constants.h` — hand-relationship arrays and card lookup + tables (declarations); includes `` for the dimensions. + Doxygen: group `utility_constants`. - `library/src/utility/constants.cpp` — the single definition of the `extern const` tables. - `library/src/utility/debug.h` — compile-time diagnostic flags, their file-name diff --git a/specs/dds-public-api.md b/specs/dds-public-api.md index bb6bf9f0a..9baeeb484 100644 --- a/specs/dds-public-api.md +++ b/specs/dds-public-api.md @@ -26,10 +26,24 @@ capability defines what crosses the boundary and promises to stay stable. > The exact per-function contracts are in doxygen. These are the whole-surface > facts. +- **Data model and constants are split out from the entry points.** The + compile-time constants and macros (bridge dimensions, `DDS_VERSION`, + `MAXNOOFBOARDS` / `MAXNOOFTABLES`, the `RETURN_*` / `TEXT_*` status codes, + `DLLEXPORT` / `STDCALL` / `EXTERN_C`) live in `dds_constants.hpp`; the plain + data structures live in `dds_c_data_types.h` (the six POD structs that cross + the pure-C shim: `Deal`, `FutureTricks`, `DdTableDeal`, `DdTableDealPBN`, + `DdTableResults`, `ParResults`) and `dds_data_types.hpp` (everything else — + the batch/PBN/par/play-trace structs, `DDSInfo`, and the internal search + structures). `dds_data_types.hpp` includes `dds_c_data_types.h`. Internal + solver code includes these headers directly; the function-declaration headers + (`dll.h`, `dds_api.hpp`, `dds_c_api.h`) are included only by API consumers and + by the API implementation files that define those symbols. - **Three layers, one library:** 1. **Flat legacy C API** — `dll.h`: historical Haglund/Hein ABI - (`EXTERN_C DLLEXPORT … STDCALL`), kept for backward compatibility. Full - symbol list is in the header / doxygen, not here. + (`EXTERN_C DLLEXPORT … STDCALL`), kept for backward compatibility. It now + carries only the function declarations and pulls its types/constants from + `dds_constants.hpp` + `dds_data_types.hpp`. Full symbol list is in the + header / doxygen, not here. 2. **Modern context C++ API** — `dds_api.hpp`: context-handle entry points taking `DDS_SOLVER_CTX` (= `SolverContext*`) with C++ types (`const Deal&`, `SolverConfig`, `TTKind`). See [solver-context](solver-context.md) and the @@ -92,6 +106,11 @@ capability defines what crosses the boundary and promises to stay stable. surface). Guarded by `//library/tests:dds_c_api_test`. - `library/src/api/{solve_board,calc_dd_table,calc_par}.hpp`, `PBN.h`, `portab.h`, `dds.h` — supporting public headers (`api_definitions`). +- `library/src/api/{dds_constants.hpp,dds_c_data_types.h,dds_data_types.hpp}` — + the shared constants and data model, with no function declarations. + `dds_constants.hpp` has its own dependency-free build target + (`//library/src/api:dds_constants`) so `//library/src/utility:constants` can + fold its bridge dimensions in without a cycle. - Build targets: `//library/src/api:dds_c_api`, `:api_definitions`, `//:dds` (façade), `//:testable_dds`, plus the logging/stats variants `//library/src:{testable_dds_util_log,testable_dds_util_stats}` — same sources,