| 384 | } |
| 385 | |
| 386 | auto register_calc_par_bindings(py::module_& module) -> void |
| 387 | { |
| 388 | module.def( |
| 389 | "calc_par", |
| 390 | [](const py::dict& table_deal, const int vulnerable) { |
| 391 | if (vulnerable < 0 || vulnerable > 3) { |
| 392 | throw py::value_error( |
| 393 | "vulnerable has invalid value " + std::to_string(vulnerable) + |
| 394 | " (expected 0=none, 1=both, 2=NS, 3=EW)"); |
| 395 | } |
| 396 | |
| 397 | const DdTableDeal native_deal = dds3_python::dict_to_dd_table_deal(table_deal); |
| 398 | DdTableResults table_results{}; |
| 399 | ParResults par_results{}; |
| 400 | int code = RETURN_NO_FAULT; |
| 401 | { |
| 402 | py::gil_scoped_release release; |
| 403 | code = calc_par( |
| 404 | native_deal, |
| 405 | vulnerable, |
| 406 | &table_results, |
| 407 | &par_results); |
| 408 | } |
| 409 | throw_on_dds_error(code); |
| 410 | |
| 411 | // Return both DD table and par results |
| 412 | py::dict result; |
| 413 | result["dd_table"] = dds3_python::dd_table_results_to_dict(table_results); |
| 414 | result["par_results"] = dds3_python::par_results_to_dict(par_results); |
| 415 | return result; |
| 416 | }, |
| 417 | py::arg("table_deal"), |
| 418 | py::arg("vulnerable") = 0, |
| 419 | "Calculate double-dummy table and par contracts for a deal.\n\n" |
| 420 | "Combines CalcDDtable and Par operations in a single call. Creates a temporary\n" |
| 421 | "solver context internally for each call. For repeated calculations, prefer\n" |
| 422 | "calc_par_from_table if DD tables are already available, to avoid redundant\n" |
| 423 | "table computation.\n\n" |
| 424 | "Args:\n" |
| 425 | " table_deal (dict): Deal dict with key 'cards' (4x4 nested list of card bitmasks).\n" |
| 426 | " cards[hand][suit] where hand=0-3 (N,E,S,W), suit=0-3 (♠,♥,♦,♣)\n" |
| 427 | " Each card bitmask has bits 2-14 set for present ranks (2-A).\n" |
| 428 | " vulnerable (int): Vulnerability (0=none, 1=both, 2=NS, 3=EW). Default: 0\n\n" |
| 429 | "Returns:\n" |
| 430 | " dict: Result dict with two keys:\n" |
| 431 | " 'dd_table': DD table results (key 'res_table' = 5x4 nested list)\n" |
| 432 | " 'par_results': Par results (keys 'par_score' and 'par_contracts_string')\n\n" |
| 433 | "Raises:\n" |
| 434 | " ValueError: If input validation fails (invalid cards or vulnerability).\n" |
| 435 | " RuntimeError: If DDS solver returns error code."); |
| 436 | |
| 437 | module.def( |
| 438 | "calc_par_from_table", |
| 439 | [](const py::dict& table_results, const int vulnerable) { |
| 440 | if (vulnerable < 0 || vulnerable > 3) { |
| 441 | throw py::value_error( |
| 442 | "vulnerable has invalid value " + std::to_string(vulnerable) + |
| 443 | " (expected 0=none, 1=both, 2=NS, 3=EW)"); |
no test coverage detected