From 518bdba985a913044e84e82713a8e76f5ddd3301 Mon Sep 17 00:00:00 2001 From: Michał Klichowicz Date: Sat, 30 Sep 2023 12:40:40 +0200 Subject: Initial import script --- src/bcdd/DDTable.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/bcdd/DDTable.py (limited to 'src/bcdd/DDTable.py') diff --git a/src/bcdd/DDTable.py b/src/bcdd/DDTable.py new file mode 100644 index 0000000..651aec3 --- /dev/null +++ b/src/bcdd/DDTable.py @@ -0,0 +1,98 @@ +from ctypes import c_char_p +from copy import copy + +from .BCalcWrapper import BCalcWrapper +from .Exceptions import DDTableInvalidException, FieldNotFoundException + + +class DDTable(object): + + def _get_empty_table(self): + table = [] + row = [-1] * 5 + for col in range(0, 4): + table.append(copy(row)) + return table + + def _validate_table(self, table): + for row in table: + for t in row: + if (t > 13) or (t < 0): + raise DDTableInvalidException( + 'Invalid number of tricks: %d' % (t) + ) + return table + + _banner_displayed = False + + def __init__(self, board): + self._board = board; + self._wrapper = BCalcWrapper() + + def _check_for_error(self, solver): + error = self._wrapper.getLastError(solver) + if error: + raise DDTableInvalidException( + 'BCalc error: %s' % (c_char_p(error).value.decode('ascii'))) + + def get_bcalc_table(self, show_banner=True): + if not DDTable._banner_displayed and show_banner: + print('Double dummy analysis provided by BCalc.') + print('BCalc is awesome, check it out: http://bcalc.w8.pl') + DDTable._banner_displayed = True + result = self._get_empty_table() + deal = self._board.get_layout() + solver = self._wrapper.new(b"PBN", deal.encode(), 0, 0) + self._check_for_error(solver) + for denom in range(0, 5): + self._wrapper.setTrumpAndReset(solver, denom) + for player in range(0, 4): + leader = self._wrapper.declarerToLeader(player) + self._wrapper.setPlayerOnLeadAndReset(solver, leader) + result[player][denom] = 13 - self._wrapper.getTricksToTake( + solver) + self._check_for_error(solver) + self._wrapper.delete(solver); + return self._validate_table(result) + + def get_jfr_table(self): + result = self._get_empty_table() + ability = self._board.get_ability() + abilities = self._board.validate_ability(ability) + for player_ability in abilities: + player = player_ability[0] + player_id = BCalcWrapper.PLAYERS.index(player) + denom_id = 4 + for tricks in player_ability[1]: + result[player_id][denom_id] = int(tricks, 16) + denom_id -= 1 + return self._validate_table(result) + + def get_pbn_table(self): + table = self._board.get_optimum_result_table() + parsed_table = self._board.validate_optimum_result_table(table) + result = self._get_empty_table() + for line_match in parsed_table: + player = line_match.group(1)[0] + denom = line_match.group(2)[0] + tricks = int(line_match.group(3)) + player_id = BCalcWrapper.PLAYERS.index(player) + denom_id = BCalcWrapper.DENOMINATIONS.index(denom) + result[player_id][denom_id] = tricks + return self._validate_table(result) + + def get_dd_table(self, show_banner=True): + try: + return self.get_jfr_table() + except FieldNotFoundException: + try: + return self.get_pbn_table() + except FieldNotFoundException: + return self.get_bcalc_table(show_banner) + + def print_table(self, dd_table): + print('\t' + '\t'.join(BCalcWrapper.DENOMINATIONS)) + for i in range(0, 4): + print('%s%s' % ( + self._wrapper.PLAYERS[i], + ''.join(['\t' + str(tricks) for tricks in dd_table[i]]))) -- cgit v1.2.3