ddss-sys 0.1.0

Generated bindings to ddss, a performance-oriented fork of the DDS double dummy solver for bridge
docs.rs failed to build ddss-sys-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

ddss-sys

Generated bindings to bsalita/ddss, a performance-oriented fork of DDS, the C++ double dummy solver for contract bridge. The fork is based on DDS 2.9.0 and its headline addition is CalcAllTablesPBNx, a dynamic-size batch API that accepts any number of deals in one call and internally chunks and schedules across a persistent thread pool. The author reports ~1.44× batched throughput over the same-version upstream.

This is a separate crate from dds-bridge-sys and is not a drop-in replacement for it:

  • ddss is based on DDS 2.9 (global state + internal thread pool), not DDS 3.x. There is no SolverContext C++ class and no per-thread context C shim.
  • ddss bumps MAXNOOFTABLES (40→1000) and MAXNOOFBOARDS (200→5000), so the legacy batch structs (boards, boardsPBN, ddTablesDealsPBN, solvedBoards, …) have larger sizes here than in upstream DDS and are not ABI-compatible.

Linking both dds-bridge-sys and ddss-sys into the same binary is not supported — they export the same C symbols (SetMaxThreads, SolveBoard, CalcDDtable, …) and will collide.

Status

ddss is a single-maintainer fork (1 star, 0 forks at the time of writing). The vendored submodule is pinned to a specific commit on the develop branch. Treat this crate as experimental.

Usage

The library needs manual initialization — call SetMaxThreads once before any other API:

// 0 stands for automatic configuration based on available cores
unsafe { ddss_sys::SetMaxThreads(0) };

ddss inherits DDS 2.9's threading model: the legacy entry points are not reentrant. If you call them from multiple threads, serialize the calls with a mutex.

The fork-specific batch API

// PBN deal: "<dealer>:<N hand> <E hand> <S hand> <W hand>",
// each hand as "spades.hearts.diamonds.clubs". The cards[80] buffer
// is null-terminated. Here N has all clubs, E all diamonds, S all
// hearts, W all spades.
const PBN: &[u8] = b"N:...AKQJT98765432 ..AKQJT98765432. .AKQJT98765432.. AKQJT98765432...\0";

let mut deal = ddss_sys::ddTableDealPBN::default();
assert!(PBN.len() <= deal.cards.len());
for (dst, &b) in deal.cards.iter_mut().zip(PBN.iter()) {
    *dst = b as _;
}

unsafe { ddss_sys::SetMaxThreads(0) };

let mut deals = [deal];
let mut trump_filter = [0; ddss_sys::DDS_STRAINS as usize]; // 0 = solve every strain
let mut results = [ddss_sys::ddTableResults::default(); 1];

let status = unsafe {
    ddss_sys::CalcAllTablesPBNx(
        deals.len() as i32,
        deals.as_mut_ptr(),
        -1, // no par; pass 0..=3 to compute par with the given vulnerability
        trump_filter.as_mut_ptr(),
        results.as_mut_ptr(),
        core::ptr::null_mut(), // par output (null is fine when mode == -1)
    )
};
assert_eq!(status, ddss_sys::RETURN_NO_FAULT as i32);

CalcAllTablesPBNx accepts batches of any size: it splits internally into fixed-size chunks bounded by MAXNOOFTABLES per call to the worker.

Cargo features

All features are off by default. The debug-* features each gate the corresponding DDS_* C++ macro in the ddss vendor; enabling them causes the solver to write .txt diagnostic files into the current working directory at runtime. Intended for solver development, not production use.

  • debug-dump — let DDS write dump.txt on solver errors
  • debug-top-level — top-level AB call info → toplevel*.txt (per thread)
  • debug-ab-stats — alpha-beta search stats → ABstats*.txt (per thread)
  • debug-tt-stats — transposition-table memory usage → TTstats*.txt (per thread)
  • debug-timing — function timings → timer*.txt (per thread)
  • debug-moves — move-generation quality → movestats*.txt (per thread)

License

Apache-2.0, matching upstream DDS and ddss.