bridgehandscanner / bridge_util.py
vincentlui's picture
update ui
743c074
from bridgebots import Suit, Direction, Card, Rank
from bridgebots.pbn import from_pbn_deal
from pbn_util import pbn_deal_string
from collections import Counter
DEALER_LIST = ['N', 'E', 'S', 'W']
VULNERABILITY_LIST = ["None","NS","EW","All","NS","EW","All","None","EW","All","None","NS","All","None","NS","EW"]
SUITS = [Suit.SPADES, Suit.HEARTS, Suit.DIAMONDS, Suit.CLUBS]
RANKS = [r.abbreviation() for r in Rank]
def get_vulnerabilty_from_board_number(board_no: int) -> str:
# Get vulnerability from board number
return VULNERABILITY_LIST[(board_no-1) % 16]
def get_dealer_from_board_number(board_no: int) -> str:
return DEALER_LIST[(board_no-1) % 4]
def validate_dataframe(df) -> None:
""" validate submitted dataframe before saving pbn """
# Check column names to be NESW
missing_direction = [direction.abbreviation() for direction in Direction if not direction.abbreviation() in df.columns]
assert len(missing_direction) == 0, f"Expect directions in table to be {','.join([d.abbreviation() for d in Direction])}" + \
f" missing {','.join(missing_direction)}"
err_msg = ''
# Check each direction to have 13 cards
invalid_num_cards_direction = [direction.name for direction in Direction if len((''.join(df[direction.abbreviation()].tolist()))) != 13]
if invalid_num_cards_direction:
err_msg += f'Expect 13 cards in each hand, received invalid number of cards in {",".join(invalid_num_cards_direction)}. '
# Check card values in RANKS
cards = []
invalid_values = set()
for direction in Direction:
for ranks, suit in zip(df[direction.abbreviation()], SUITS):
for r in ranks:
try:
Rank.from_str(r)
except:
invalid_values.add(r)
assert not invalid_values, f'Expect card values in {",".join(RANKS)}, received {invalid_values}'
for direction in Direction:
for ranks, suit in zip(df[direction.abbreviation()], SUITS):
cards.extend([Card(rank=Rank.from_str(v), suit=suit) for v in ranks])
# Check duplicated and missing cards
duplicated, missing = get_invalid_cards(cards)
if len(duplicated) > 0:
err_msg += f'Duplicated cards: {duplicated}. '
if len(missing) > 0:
err_msg += f'Missing cards: {missing}. '
assert not err_msg, err_msg
def df_info(df):
# missing_direction = [direction.abbreviation() for direction in Direction if not direction.abbreviation() in df.columns]
num_cards_direction = {direction.name: len((''.join(df[direction.abbreviation()].tolist()))) for direction in Direction}
invalid_values = set()
for direction in Direction:
for ranks, suit in zip(df[direction.abbreviation()], SUITS):
for r in ranks:
try:
Rank.from_str(r)
except:
invalid_values.add(r)
if invalid_values:
return f'Expect card values in {",".join(RANKS)}, received {invalid_values}'
cards = []
for direction in Direction:
for ranks, suit in zip(df[direction.abbreviation()], SUITS):
cards.extend([Card(rank=Rank.from_str(v), suit=suit) for v in ranks])
# Check duplicated and missing cards
duplicated, missing = get_invalid_cards(cards)
if (not duplicated) and (not missing) and not [True for n in num_cards_direction.values() if n!=13]:
return f'It looks good!'
print_info = f'Number of cards: {num_cards_direction} \n'
print_info += f'Duplicated cards: {",".join(sorted(map(Card.__repr__,duplicated)))} \n'
print_info += f'Missing cards: {",".join(sorted(map(Card.__repr__,missing)))}'
return print_info
def get_invalid_cards(cards: list[Card]) -> tuple[set, set]:
"""Get duplicated and missing cards"""
counter_cards = Counter(cards)
duplicated = {c for c, cnt in counter_cards.items() if cnt > 1}
missing = {Card(s,r) for r in Rank for s in Suit if not Card(s,r) in counter_cards.keys()}
return duplicated, missing
def roll_direction(df, idx):
new_df = df.copy(deep=True)
for i, direction in enumerate(DEALER_LIST):
new_direction = DEALER_LIST[(idx+i)%4]
new_df[direction] = df[new_direction]
return new_df