def refresh_table(self): """ Execute callback for every card on the table. """ for i, t_card in enumerate(self._stack): self._callback( t_card, common.TableLocation(area=common.TableArea.STACK, visible=False, card_id=i)) for i, t_card in enumerate(self._waste): pile_id = min(len(self._waste) - i - 1, 3) self._callback( t_card, common.TableLocation(area=common.TableArea.WASTE, visible=True, pile_id=pile_id, card_id=i)) for i, pile in enumerate(self._tableau.piles): for j, t_card in enumerate(pile): self._callback( t_card, common.TableLocation(area=common.TableArea.TABLEAU, visible=t_card.visible, pile_id=i, card_id=j)) for i, pile in enumerate(self._foundation.piles): for j, t_card in enumerate(pile): self._callback( t_card, common.TableLocation(area=common.TableArea.FOUNDATION, visible=True, pile_id=i, card_id=j))
def __flip(self, pile: int) -> bool: """ Tries to flip the top most card of the specified pile. Args: pile: pile index. Returns: True if a move is performed otherwise False. """ res = self._tableau.flip(pile) if res: self._history.append( Move(from_area=common.TableArea.TABLEAU, from_pile_id=pile, pile_count=1, to_area=common.TableArea.TABLEAU, to_pile_id=pile)) self._callback( self._tableau.top_card(pile), common.TableLocation(area=common.TableArea.TABLEAU, visible=True, pile_id=pile, card_id=len(self._tableau.piles[pile]) - 1)) return False
def _update_tableau_pile(self, pile_id: int) -> None: """Make sure all cards in a tableau pile get updated.""" for i, t_card in enumerate(self._tableau.piles[pile_id]): self._callback( t_card, common.TableLocation(area=common.TableArea.TABLEAU, visible=t_card.visible, pile_id=pile_id, card_id=i))
def _reset_waste(self) -> None: """Make sure all waste card callbacks are executed.""" w_len = len(self._waste) for i in range(min(5, w_len)): card_id = w_len - i - 1 self._callback( self._waste[card_id], common.TableLocation(area=common.TableArea.WASTE, visible=True, pile_id=min(i, 3), card_id=card_id))
def refresh_all(self): """Force refresh all card nodes.""" table = self._table.table for i, t_card in enumerate(table.stack): self._cards[t_card.index[0]].location = common.TableLocation( common.TableArea.STACK, False, card_id=i) w_len = len(table.waste) for i, t_card in enumerate(table.waste): pile_id = min(3, w_len - i - 1) self._cards[t_card.index[0]].location = common.TableLocation( common.TableArea.WASTE, True, pile_id=pile_id, card_id=i) for i, pile in enumerate(table.foundation): for j, t_card in enumerate(pile): self._cards[t_card.index[0]].location = common.TableLocation( common.TableArea.FOUNDATION, True, pile_id=i, card_id=j) for i, pile in enumerate(table.tableau): for j, t_card in enumerate(pile): self._cards[t_card.index[0]].location = common.TableLocation( common.TableArea.TABLEAU, t_card.index[1] == 0, pile_id=i, card_id=j) meths = { common.TableArea.STACK: self._callback_stack, common.TableArea.WASTE: self._callback_waste, common.TableArea.FOUNDATION: self._callback_foundation, common.TableArea.TABLEAU: self._callback_tableau, common.TableArea.NONE: None } c_loc = common.TableLocation(common.TableArea.NONE) for k in self._cards: card_node = self._cards[k] if meths[card_node.location.area] is None: continue meths[card_node.location.area](c_loc, card_node.location, card_node)
def __draw(self) -> Union[bool, int]: """ Try to draw from stack. Returns: Union[bool, int] -> 1 = draw, 2 = reset stack, False = empty. """ if not self._stack: if not self._waste: logger.debug('no more cards') return False self._stack = list(reversed(self._waste)) self._waste = [] for i, s_card in enumerate(self._stack): s_card.visible = False self._callback( s_card, common.TableLocation(area=common.TableArea.STACK, visible=False, card_id=i)) self._state.points -= 100 if self._state.draw_count == 1 else 0 self._state.points = max(self._state.points, 0) logger.info('reset stack') self._history.append( Move(from_area=common.TableArea.WASTE, to_area=common.TableArea.STACK)) self._state.points -= 100 if self.draw_count == 1 else 0 self._state.points = max(0, self._state.points) return 2 card_count = min(self._state.draw_count, len(self._stack)) for _ in range(self._state.draw_count): if self._stack: self._waste.append(self._stack.pop()) self._waste[-1].visible = True else: break self._history.append( Move(from_area=common.TableArea.STACK, to_area=common.TableArea.WASTE, pile_count=card_count)) self._reset_waste() logger.info('draw successful') return 1
def __tableau_to_foundation(self, tableau_pile: Optional[int] = None, foundation_pile: Optional[int] = None) -> bool: """ Tries to move a card from Tableau to Foundation. Args: tableau_pile: pile index on Tableau. foundation_pile: pile index on Foundation. Returns: True if a move is performed otherwise False. """ if tableau_pile is None: test_cards = [(i, self._tableau.top_card(i)) for i in range(7)] else: test_cards = [(tableau_pile, self._tableau.top_card(tableau_pile))] for from_pile, t_card in test_cards: if t_card is None: continue dest_pile = self._foundation.add_card(t_card, foundation_pile) if dest_pile > -1: self._history.append( Move(from_area=common.TableArea.TABLEAU, from_pile_id=from_pile, pile_count=1, to_area=common.TableArea.FOUNDATION, to_pile_id=dest_pile)) self._tableau.remove(from_pile) logger.debug('valid move found') self._state.points += 10 self._callback( self._foundation.top_card(dest_pile), common.TableLocation( area=common.TableArea.FOUNDATION, visible=True, pile_id=dest_pile, card_id=len(self._foundation.piles[dest_pile]) - 1)) self._update_tableau_pile(from_pile) return True logger.debug('no valid move found') return False
def __undo_draw(self, move: Move) -> bool: """ Undo a draw operation. Args: move: Move Returns: bool -> True if successful otherwise False. """ for _ in range(move.pile_count): w_card = self._waste.pop() w_card.visible = False self._stack.append(w_card) self._callback( w_card, common.TableLocation(area=common.TableArea.STACK, visible=False, card_id=len(self._stack) - 1)) self._reset_waste() return True
def __undo_foundation_to(self, move: Move) -> bool: """ Undo a Foundation to Tableau operation. Args: move: Move Returns: bool -> True if successful otherwise False. """ f_card = self._tableau.top_card(move.to_pile_id) self._foundation.add_card_force(f_card, move.from_pile_id) self._tableau.remove(move.to_pile_id) self._callback( self._foundation.top_card(move.from_pile_id), common.TableLocation( area=common.TableArea.FOUNDATION, visible=True, pile_id=move.from_pile_id, card_id=len(self._foundation.piles[move.from_pile_id]) - 1)) self._update_tableau_pile(move.to_pile_id) return True
def __undo_tableau_to(self, move: Move) -> bool: """ Undo a Tableau to ... operation. Args: move: Move Returns: bool -> True if successful otherwise False. """ if move.to_area == common.TableArea.TABLEAU and \ move.from_pile_id != move.to_pile_id: self._tableau.move_pile_force(move.to_pile_id, move.pile_count, move.from_pile_id) self._update_tableau_pile(move.to_pile_id) self._update_tableau_pile(move.from_pile_id) elif move.to_area == common.TableArea.TABLEAU and \ move.from_pile_id == move.to_pile_id: self._tableau.top_card(move.from_pile_id).visible = False self._callback( self._tableau.top_card(move.from_pile_id), common.TableLocation( area=common.TableArea.TABLEAU, visible=False, pile_id=move.from_pile_id, card_id=len(self._tableau.piles[move.from_pile_id]) - 1)) move = self._history.pop() self.__undo_tableau_to(move) elif move.to_area == common.TableArea.FOUNDATION: t_card = self._foundation.top_card(move.to_pile_id) self._tableau.add_card_force(t_card, move.from_pile_id) self._foundation.remove(move.to_pile_id) self._update_tableau_pile(move.from_pile_id) else: return False return True
def __undo_waste_to(self, move: Move) -> bool: """ Undo a Waste to ... operation. Args: move: Move Returns: bool -> True if successful otherwise False. """ if move.to_area == common.TableArea.TABLEAU: w_card = self._tableau.top_card(move.to_pile_id) self._waste.append(w_card) self._tableau.remove(move.to_pile_id) self._update_tableau_pile(move.to_pile_id) elif move.to_area == common.TableArea.FOUNDATION: w_card = self._foundation.top_card(move.to_pile_id) self._waste.append(w_card) self._foundation.remove(move.to_pile_id) elif move.to_area == common.TableArea.STACK: self._waste = list(reversed(self._stack)) self._stack = [] w_len = len(self._waste) for i, w_card in enumerate(self._waste): pile_id = min(3, w_len - i - 1) w_card.visible = True self._callback( w_card, common.TableLocation(area=common.TableArea.WASTE, visible=True, pile_id=pile_id, card_id=i)) else: return False self._reset_waste() return True
def __waste_to_foundation(self, pile: Optional[int] = None) -> bool: """ Tries to move a card from Waste to Foundation. Args: pile: pile index. Returns: True if a move is performed otherwise False. """ w_card = self.waste_card if w_card is None: logger.debug('no waste card') return False dest_pile = self._foundation.add_card(w_card, pile) if dest_pile < 0: logger.debug('no valid move found') return False logger.debug('valid move found') self._history.append( Move(from_area=common.TableArea.WASTE, from_pile_id=-1, pile_count=1, to_area=common.TableArea.FOUNDATION, to_pile_id=dest_pile)) self._waste.pop() self._state.points += 10 self._callback( self._foundation.top_card(dest_pile), common.TableLocation( area=common.TableArea.FOUNDATION, visible=True, pile_id=dest_pile, card_id=len(self._foundation.piles[dest_pile]) - 1)) self._reset_waste() return True
def __init__(self, card_ratio: float, padding: float, status_size: Tuple[float, float], toolbar_size: Tuple[float, float]) -> None: card_size = (1 / (7 + 8 * padding), card_ratio * (1 / (7 + 8 * padding))) self._cfg = TableConfig(card_size=card_size, padding=(card_size[0] * padding, card_size[1] * padding), status_size=status_size, toolbar_size=toolbar_size) root = node.Node('Table Root') root.distance_relative = True root.depth = -100 self._nodes = TableNodes( root=root, stack=root.attach_image_node('Stack', common.STACK), waste=root.attach_node('Waste Root'), foundation=root.attach_node('Foundation Root'), tableau=root.attach_node('Tableau Root'), status=root.attach_node('Status'), toolbar=root.attach_node('Toolbar')) self._children = ChildNodes( waste=[ self._nodes.waste.attach_image_node(f'Waste {i}', common.WASTE) if not i else self._nodes.waste.attach_node(f'Waste {i}') for i in range(4) ], foundation=[ self._nodes.foundation.attach_image_node( f'Foundation {i}', common.FOUNDATION) for i in range(4) ], tableau=[ self._nodes.tableau.attach_image_node(f'Tableau {i}', common.TABLEAU) for i in range(7) ]) # Background background = self._nodes.root.attach_node('BG Root') background.depth = -500 offset = .1 for x_pos in range(26): for y_pos in range(26): tmp_node = background.attach_image_node( image=common.BACKGROUND) tmp_node.pos = x_pos * offset, y_pos * offset self._v_offset = (0.0, self._cfg.card_size[1] / 3) # Cards card_dummy = self._nodes.root.attach_node('Card Layer') card_dummy.depth = 99 self._cards: Dict[Tuple[int, int], CardNode] = { (suit, value): CardNode(k=(suit, value), node=card_dummy.attach_image_node( f'{suit},{value}', f'images/{common.COLORS[suit]}' f'{common.DENOMINATIONS[value]}.png'), location=common.TableLocation(area=common.TableArea.NONE, visible=False)) for suit in range(4) for value in range(13) } for k in self._cards: self._cards[k].node.add_image(common.CARDBACK) self._cards[k].node.index = 1 self._drag_info: DragInfo = DragInfo() self._depth_queue = DepthQueue() self._relative_positions = RelativePositions( stack=vec2.Vec2(), waste=[vec2.Vec2() for _ in range(4)], foundation=[vec2.Vec2() for _ in range(4)], tableau=[vec2.Vec2() for _ in range(7)]) self._table: Optional[Table] = None