dds-bridge-sys 3.0.0

Generated bindings to DDS, the double dummy solver for bridge
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/*
   DDS, a bridge double dummy solver.

   Scaffolding for an instance-scoped API. This is a no-behavior-change
   adapter that allows driving the solver with an explicit context,
   while internally delegating to existing code paths.
*/

#pragma once

#include <cstddef>
#include <memory>
#include <string>
#include <vector>

#include <system/thread_data.hpp>
#include <system/util/utilities.hpp>
#include <trans_table/trans_table.hpp>

// Minimal configuration scaffold for future expansion.
// TT configuration without depending on Memory headers.
enum class TTKind { Small, Large };

/**
 * @brief Configuration options for SolverContext instances.
 *
 * Provides per-context configuration for transposition tables.
 * Values are applied when creating or reconfiguring
 * a SolverContext and persist across lazy TT creation.
 */
struct SolverConfig
{
  TTKind tt_kind_ = TTKind::Large;
  int tt_mem_default_mb_ = 0;
  int tt_mem_maximum_mb_ = 0;
};

/**
 * @brief Instance-scoped solver context for DDS.
 *
 * Owns or references ThreadData and exposes lightweight facades for search
 * state, move generation, and utilities. The context manages an instance-owned
 * transposition table (TT) and provides explicit reset and configuration hooks.
 *
 * @note Thread safety: not inherently thread-safe. Use one SolverContext per thread.
 */
class SolverContext
{
public:
  explicit SolverContext(std::shared_ptr<ThreadData> thread, SolverConfig cfg = {})
  : thr_(std::move(thread)), cfg_(cfg)
  {
    // Bind the persistent facades to the underlying ThreadData.
    search_.set_thread(thr_);
    search_.set_owner(this);
  }

  // NOTE: constructors that accepted raw ThreadData* were removed as part
  // of the ownership migration. Callers should pass a
  // std::shared_ptr<ThreadData> (non-owning wrappers can be created with
  // std::shared_ptr<ThreadData>(ptr, [](ThreadData*){})).

  // Construct a context that owns its ThreadData instance. This is the
  // preferred mode for the new instance-scoped API: callers can create a
  // SolverContext at the top of the call-stack and pass it downwards.
  explicit SolverContext(SolverConfig cfg = {});

  ~SolverContext();

  /**
   * @brief Access the underlying ThreadData shared pointer.
   *
   * @return Shared ownership of the ThreadData used by this context.
   */
  auto thread() const -> std::shared_ptr<ThreadData>
  {
    return thr_;
  }

  /**
   * @brief Access the current configuration snapshot.
   *
   * @return Const reference to the configuration stored in this context.
   */
  auto config() const -> const SolverConfig&
  {
    return cfg_;
  }

  // --- Utilities facade ---
  class UtilitiesContext
  {
  public:
    explicit UtilitiesContext(::dds::Utilities* util)
      : util_(util)
    {
    }

    auto util() -> ::dds::Utilities&
    {
      return *util_;
    }

    auto util() const -> const ::dds::Utilities&
    {
      return *util_;
    }

    auto log_append(const std::string& s) -> void
    {
      util_->log_append(s);
    }

    auto log_buffer() const -> const std::vector<std::string>&
    {
      return util_->log_buffer();
    }

    auto log_clear() -> void
    {
      util_->log_clear();
    }

  private:
    ::dds::Utilities* util_ = nullptr;
  };

  /**
   * @brief Access utilities facade for logging and stats.
   */
  /**
   * @brief Access utilities facade for mutable contexts.
   */
  auto utilities() -> UtilitiesContext
  {
    return UtilitiesContext(&utils_);
  }

  /**
   * @brief Access utilities facade for const contexts.
   * @note Returns a const-only wrapper to preserve const-correctness.
   */
  auto utilities() const -> UtilitiesContext
  {
    return UtilitiesContext(const_cast<dds::Utilities*>(&utils_));
  }

  // Developer note — TT lifecycle (instance-scoped)
  //
  // - Ownership: Each SolverContext::SearchContext owns its TransTable (TT)
  //   via a std::unique_ptr created lazily on first access. There is no
  //   global TT registry and no ThreadData-owned TT.
  // - Configuration: The effective TT kind and memory sizes are determined by
  //   the SolverContext's SolverConfig (tt_kind_, tt_mem_default_mb_, tt_mem_maximum_mb_),
  //   with optional environment overrides:
  //     DDS_TT_DEFAULT_MB  — overrides default MB if > 0
  //     DDS_TT_LIMIT_MB    — caps maximum MB if > 0
  //   Call configure_tt(...) at runtime to persist a new configuration and apply
  //   it to an existing TT (resize in place) or recreate if the kind changes.
  // - Reset semantics:
  //     reset_for_solve()      — clears a subset of search state and calls
  //                               tt->reset_memory(FreeMemory) when a TT exists;
  //                               preserves the TT allocation for reuse.
  //     reset_best_moves_lite() — clears only best-move ranks and updates memUsed.
  //     clear_tt()              — returns all TT memory to the system; preserves
  //                               future config and recreates lazily on demand.
  //     dispose_trans_table()  — destroys the owned TT immediately.
  // - Diagnostics: When built with DDS_UTILITIES_LOG / DDS_UTILITIES_STATS, TT
  //   lifecycle events append compact log entries and bump small counters.

  // Returns the owned transposition table instance (creates if null)
  /**
   * @brief Get or create the transposition table.
   *
   * @return Pointer to the owned TT instance.
   */
  auto trans_table() const -> TransTable*;
  // Returns the TT instance if it exists, or nullptr
  /**
   * @brief Get the transposition table if already created.
   *
   * @return Pointer to the TT instance or nullptr.
   */
  auto maybe_trans_table() const -> TransTable*;

  // Dispose and erase the TT instance associated with this thread, if any.
  /**
   * @brief Dispose the owned transposition table immediately.
   */
  auto dispose_trans_table() const -> void;

  // Lightweight facades used by tests and call sites; no-ops if no TT exists.
  /**
   * @brief Reset search state for a new solve.
   *
   * Calls TT reset with ResetReason::FreeMemory when applicable.
   */
  auto reset_for_solve() const -> void;   // Calls reset_memory(ResetReason::FreeMemory)
  // Lightweight per-iteration reset matching legacy ResetBestMoves semantics.
  // Only clears bestMove[*].rank and bestMoveTT[*].rank, updates memUsed and ABStats.
  /**
   * @brief Lightweight reset used inside search iterations.
   */
  auto reset_best_moves_lite() const -> void;
  /**
   * @brief Return all TT memory to the system without destroying the TT.
   */
  auto clear_tt() const -> void;         // Calls ReturnAllMemory()
  /**
   * @brief Resize TT memory defaults and limits in-place if TT exists.
   */
  auto resize_tt(int defMB, int maxMB) const -> void; // Updates sizes if TT exists
  // Explicit runtime configuration of TT kind and memory limits. Applies to
  // existing TT (resize or recreate) and persists for future creations.
  /**
   * @brief Configure TT kind and memory limits.
   */
  auto configure_tt(TTKind kind, int defMB, int maxMB) -> void;

  // --- Search state facade ---
  /**
   * @brief Facade for per-solve search state.
   */
  class SearchContext
  {
  public:
    SearchContext() = default;

    explicit SearchContext(std::shared_ptr<ThreadData> thr)
      : thr_(std::move(thr))
    {
    }

    // Returns the owned transposition table instance (creates if null)
    auto trans_table() -> TransTable*;
    // Returns the TT instance if it exists, or nullptr
    auto maybe_trans_table() const -> TransTable*;
    // Dispose and erase the TT instance owned by this context, if any.
    auto dispose_trans_table() -> void;
    // analysis flag used to control incremental analysis behavior
    auto analysis_flag() -> bool&;
    auto analysis_flag() const -> bool;
    auto lowest_win(int depth, int suit) -> unsigned short&;
    auto lowest_win(int depth, int suit) const -> const unsigned short&;
    auto best_move(int depth) -> MoveType&;
    auto best_move(int depth) const -> const MoveType&;
    auto best_move_tt(int depth) -> MoveType&;
    auto best_move_tt(int depth) const -> const MoveType&;
    auto winners(int trickIndex) -> WinnersType&;
    auto winners(int trickIndex) const -> const WinnersType&;
    // Node type store for each hand (MAXNODE/MINNODE)
    auto node_type_store(int hand) -> int&;
    auto node_type_store(int hand) const -> const int&;
    // Access to forbidden moves buffer used by Moves::Purge and solver loops
    auto forbidden_moves() -> MoveType*;
    auto forbidden_moves() const -> const MoveType*;
    auto forbidden_move(int index) -> MoveType&;
    auto forbidden_move(int index) const -> const MoveType&;
    auto clear_forbidden_moves() -> void;
    auto nodes() -> int&;
    auto nodes() const -> const int&;
    auto trick_nodes() -> int&;
    auto trick_nodes() const -> const int&;
    auto ini_depth() -> int&;
    auto ini_depth() const -> int;

  public:
    // Allow SolverContext to bind or rebind the underlying ThreadData
    // after construction (useful when SolverContext owns the ThreadData
    // and sets it up after default construction).
    auto set_thread(const std::shared_ptr<ThreadData>& thr) -> void
    {
      thr_ = thr;
    }

    // Bind the owning SolverContext instance for access to config/utilities/arena
    auto set_owner(SolverContext* owner) -> void
    {
      owner_ = owner;
    }

  private:
    std::shared_ptr<ThreadData> thr_;
    // Instance-owned transposition table, created lazily on first access.
    std::unique_ptr<TransTable> tt_;
    // Back-reference to the owning SolverContext (for config and utilities).
    SolverContext* owner_ = nullptr;
  };

  // Expose a persistent SearchContext owned by the SolverContext.
  /**
   * @brief Access the persistent search-state facade.
   */
  auto search() -> SearchContext&
  {
    return search_;
  }

  /**
   * @brief Access the persistent search-state facade (const).
   */
  auto search() const -> const SearchContext&
  {
    return search_;
  }

  // --- Move generation facade ---
  /**
   * @brief Facade for move generation utilities bound to ThreadData.
   */
  class MoveGenContext
  {
  public:
    explicit MoveGenContext(std::shared_ptr<ThreadData> thr)
      : thr_(std::move(thr))
    {
    }

    auto move_gen_0(
      const int tricks,
      const Pos& tpos,
      const MoveType& bestMove,
      const MoveType& bestMoveTT,
      const RelRanksType thrp_rel[]) -> int;

    auto move_gen_123(
      const int tricks,
      const int relHand,
      const Pos& tpos) -> int;

    auto purge(
      const int tricks,
      const int relHand,
      const MoveType forbiddenMoves[]) -> void;

    auto make_next(
      const int trick,
      const int relHand,
      const unsigned short win_ranks[]) -> const MoveType*;

    // Simpler variant without win_ranks used in several SolverIF paths
    auto make_next_simple(
      const int trick,
      const int relHand) -> const MoveType*;

    auto get_length(
      const int trick,
      const int relHand) const -> int;

    auto rewind(
      const int tricks,
      const int relHand) -> void;

    auto register_hit(
      const int tricks,
      const int relHand) -> void;

    // Reinitialize move generation for a new lead hand at a given trick
    auto reinit(
      const int tricks,
      const int leadHand) -> void;

    // Initialize move generation state for a given trick and starting hand
    auto init(
      const int tricks,
      const int relStartHand,
      const int initialRanks[],
      const int initialSuits[],
      const unsigned short rank_in_suit[DDS_HANDS][DDS_SUITS],
      const int trump,
      const int leadHand) -> void;

  // Diagnostics (no behavior change; passthrough to Moves)
  // Note: Emission is controlled by DDS_MOVES / DDS_MOVES_DETAILS.
    auto print_trick_stats(std::ofstream& fout) const -> void;
    auto print_trick_details(std::ofstream& fout) const -> void;
    auto print_function_stats(std::ofstream& fout) const -> void;

    // Read-only access to per-trick generated metadata
    auto get_trick_data(const int tricks) -> const TrickDataType&;

 // Read-only textual dump helper
    auto trick_to_text(const int trick) const -> std::string;

    // Specify a particular move at a trick/hand position
    auto make_specific(
      const MoveType& mply,
      const int trick,
      const int relHand) -> void;

  private:
    std::shared_ptr<ThreadData> thr_;
  };

  /**
   * @brief Access move generation facade.
   */
  auto move_gen() const -> MoveGenContext
  {
    return MoveGenContext(thr_);
  }

private:
  // Shared ownership of per-context ThreadData. Callers can construct
  // a context with an externally-owned std::shared_ptr<ThreadData> or
  // let the context create/own one via the default constructor.
  std::shared_ptr<ThreadData> thr_;
  // Persistent facade objects bound to this context. `search_` is
  // initialized after `thr_` is set in constructors.
  SearchContext search_;
  SolverConfig cfg_{};
  mutable ::dds::Utilities utils_{};
  // Arena removed.
  // NOTE: `owned_thr_` removed; `thr_` now represents the shared ownership
  // (if any) for this context.
  // Transposition table is now owned per SearchContext and created lazily.
  //
  // See the developer note above for details on TT lifecycle and resets.
};

auto ThreadMemoryUsed() -> double;