【4日目】Fletでソリティアサンプルアプリ作成 ~UI構築の実践編③~

この記事は広告を含みます。

kunio-ud-zatta.hatenablog.com

本日も、上記の続きです。 クライアント側も時間かかりますね。。 普段、サーバー開発が多いので、忘れがちです。。

ソリティアルールを作る

現在は、どのカードも動かせる。 移動できるのは表向きのカードだけにする。

def start_drag(self, e: ft.DragStartEvent):
    if self.face_up:
        self.move_on_top()
        self.solitaire.update()

def drag(self, e: ft.DragUpdateEvent):
    if self.face_up:
        for card in self.draggable_pile:
            card.top = max(0, self.top + e.delta_y) + self.draggable_pile.index(card) * CARD_OFFSET
            card.left = max(0, self.left + e.delta_x)
            card.solitaire.update()

def drop(self, e: ft.DragEndEvent):
    if self.face_up:
        for slot in self.solitaire.tableau:
            if (
                abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY
            and abs(self.left - slot.left) < DROP_PROXIMITY
        ):
                self.place(slot)
                return
        
        for slot in self.solitaire.foundations:
            if (
                    abs(self.top - slot.top) < DROP_PROXIMITY
            and abs(self.left - slot.left) < DROP_PROXIMITY
        ):
                self.place(slot)
                return
        
    self.bounce_back()

if self.face_up:これですね。

  • カードクラスにclickの追加
def click(self, e):
    if self.slot in self.solitaire.tableau:
        if not self.face_up and self == self.slot.get_top_card():
            self.turn_face_up()
            self.solitaire.update()
def check_foundations_rules(self, card, slot):
    top_card = slot.get_top_card()
    if top_card is not None:
        return (
            card.suite.name == top_card.suite.name
            and card.rank.value - top_card.rank.value == 1
        )
    else:
        return card.rank.name == "Ace"
  • ダブルクリックイベントをカードクラスに追加
   def double-click(self, e):
       self.get_draggable_pile()
       if self.face_up and len(self.draggable_pile == 1):
           self.move_on_top()
           for slot in self.solitaire.foundations:
               if self.solitaire.check_foundations_rules(self, slot):
                   self.place(slot)
                   return
  • テーブルルールを作成
def check_tableau_rules(self, card, slot):
    top_card = slot.get_top_card()
    if top_card is not None:
        return (
            card.suite.color != top_card.suite.color
            and top_card.rank.value - card.rank.value == 1
            and top_card.face_up
        )
    else:
        return card.rank.name == "King"

-- ドロップを修正

def drop(self, e: ft.DragEndEvent):
    if self.face_up:
        for slot in self.solitaire.tableau:
            if (
                abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY
            and abs(self.left - slot.left) < DROP_PROXIMITY
        ) and self.solitaire.check_tableau_rules(self, slot):
                self.place(slot)
                return
        
        if len(self.draggable_pile) == 1:
            for slot in self.solitaire.foundations:
                if (
                    abs(self.top - slot.top) < DROP_PROXIMITY
            and abs(self.left - slot.left) < DROP_PROXIMITY
        ) and self.solitaire.check_foundations_rules(self, slot):
                    self.place(slot)
                    return
        
        self.bounce_back()

さすがに、ここら辺まで来ると、Gitで差分を見ながらの方が楽ですね。

あと、少し公式をみて、記述をすると、以下のようなゲーム画面になりました。

ちょっと移動がしょぼいPCだとしんどいです、、、

クリアならず。。。

Winの実装

    def check_win(self):
        cards_num = 0
        for slot in self.foundations:
            cards_num += len(slot.pile)
        if cards_num == 52:
            return True
        return False

    def winning_sequence(self):
        for slot in self.foundations:
            for card in slot.pile:
                card.animate_position = 2000
                card.move_on_top()
                card.top = random.randint(0, SOLITAIRE_HEIGHT)
                card.left = random.randint(0, SOLITAIRE_WIDTH)
                self.update()
        self.controls.append(
            ft.AlertDialog(title=ft.Text("Congratulations! You won!"), open=True)
        )
  • debugがんばります。

今日はここまでにします。