[SOLVED] Cardgame Framework help: vertical and horizontal scoring checks?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

[SOLVED] Cardgame Framework help: vertical and horizontal scoring checks?

#1 Post by thexerox123 »

I'd made a previous thread seeking advice on how to set up a custom game using the Cardgame Framework. I've recently made progress beyond that issue, and have the basic setup working. However, I'm struggling to get the scoring system for the game set up.

Image

So, I need a method that will check for 5 consecutive cards of the same suit in any of the rows or columns. If there are 5 of a kind, all 5 of those cards are moved to the claimed pile.

Every turn, I need the scoring method to get each of the 5 rows and 5 columns, along with their corresponding cards from the tableau list. For each row and column, it needs to check to see if all 5 have cards in them, and if so, whether all 5 suits for the top cards are the same. If yes, those 5 top cards are moved to claimed from their respective stacks. If no, then nothing is done.

I've tried approaching it a few different ways, but I keep getting index errors. I added a print statement to see what is contained within my tableau list, and I think I'm probably not extracting the value of the cards correctly.

So, here's my code as it currently stands, minus my attempts at the scoring logic:

script.rpy:

Code: Select all

# The script of the game goes in this file.

# The game starts here.

label start:
    scene bg felt

    python:
        e = ElfJack()
        e.set_sensitive(True)
        e.show()

label continual:
    while True:

        python:
        
            # ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
            # e.set_sensitive(True)
            event = e.interact()

            if event:
                renpy.checkpoint()
            
        if event == "win":
            jump win

label win:
    "YOU WIN!"
    return
Elfjack.rpy:

Code: Select all

init python:

    class ElfJack(object):

        BAUBLE = 0
        SNOW = 1
        GINGER = 2
        REINDEER = 3
        STAR = 4
        SANTA = 5
        GRUMP = 6
        CANE = 7   

        def __init__(self):
            # Constants that let us easily change where the game is
            # located.
            LEFT=700
            TOP=158
            COL_SPACING = 150
            ROW_SPACING = 180
            CARD_XSPACING = 0.5
            CARD_YSPACING = 0.5

            # Create the table, stock, discard, and claim.
            self.table = t = Table(base="images/base.png", back="images/back.png")
            self.stock = t.stack(LEFT + 900, TOP, xoff=0.5, yoff=0.2, show=50, click=True)
            self.claim = t.stack(LEFT + 950, TOP + 700, xoff=CARD_XSPACING, drag=DRAG_NONE, click=True)
            self.hand = t.stack(LEFT + 105, TOP + 900, xoff=100, yoff=0, drag=DRAG_CARD, click=True)

            self.discard = []
            d = t.stack(LEFT + 790, TOP + 700, xoff=CARD_XSPACING, yoff=CARD_YSPACING, show=50, drag=DRAG_NONE, click=True, drop=True)
            self.discard.append(d)

            # The 25 tableau stacks.
            self.tableau = [ ]
            for row in range(5):
                for col in range(5):
                    s = t.stack(LEFT + COL_SPACING * col, TOP + ROW_SPACING * row, xoff=0, yoff=CARD_YSPACING, show=10, drag=DRAG_NONE, click=True, drop=True)
                    self.tableau.append(s)

            # Create the stock and shuffle it.
            for rank in range(0, 12):
                for suit in range(0, 5):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)


            self.stock.shuffle()

            # Deal out the initial tableau.
            for i in range(0, 1):
                for j in range(0, 25):
                    c = self.stock.deal()
                    self.tableau[j].append(c)
                    self.table.set_faceup(c, True)

            for rank in range(0, 3):
                for suit in range(6, 7):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)

            self.stock.shuffle()

            for i in range(0, 5):
                c = self.stock.deal()
                self.hand.append(c)
                self.table.set_faceup(c, True)


        def show(self):
            self.table.show()

        def hide(self):
            self.table.hide()

        def tableau_drag(self, evt):
            # We can only drag one card at a time to a tableau space.
            if len(evt.drag_cards) != 1:
                return False

            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "tableau_drag"

        def discard_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "discard_drag"



        def stock_click(self, evt):
            if len(self.hand) == 5:
                return False

            else:
                if self.stock:
                    c = self.stock.deal()
                    self.table.set_faceup(c, True)
                    self.hand.append(c)
        
        def interact(self):        

            evt = ui.interact()
            rv = False        

            # Check the various events, and dispatch them to the methods
            # that handle them.
            if evt.type == "drag":
                if evt.drop_stack in self.tableau:
                    rv = self.tableau_drag(evt)        

                elif evt.drop_stack in self.discard:
                    rv = self.discard_drag(evt)        

            elif evt.type == "click":
                if evt.stack == self.stock:
                    rv = self.stock_click(evt)        

            # Check for the win condition when all tableau stacks are empty.
            if all(len(stack) == 0 for stack in self.tableau):
                return "win"        

            return rv

        # Sets things as sensitive (or not).
        def set_sensitive(self, value):
            self.table.set_sensitive(value)

   
If anybody has any suggestions for how to approach this, it would be greatly appreciated!
Last edited by thexerox123 on Sat Feb 03, 2024 10:36 pm, edited 3 times in total.

thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

Re: Cardgame Framework help: vertical and horizontal scoring checks?

#2 Post by thexerox123 »

Here's my most recent attempt to figure out the scoring methods, called in the interact method.

Code: Select all

        def check_for_scoring(self):
            # Check rows
            for row in range(5):
                top_cards = [stack[-1] for stack in self.tableau[row] if stack]
                self.check_and_claim(top_cards, 'horizontal', row)        

            # Check columns
            for col in range(5):
                column_stacks = (stack[col] for stack in self.tableau)
                top_cards = [stack[-1] for stack in column_stacks if stack]
                self.check_and_claim(top_cards, 'vertical', col)

                  
        def check_and_claim(self, top_cards, direction, index):
            if len(top_cards) == 5 and all(top_cards[0].suit == card.suit for card in top_cards if card is not None):
                # All 5 top cards in the row/column have the same suit
                self.move_cards_to_claimed(index, direction)



        def move_cards_to_claimed(self, start_index, direction):
            # Move the 5 cards to the claimed stack
            if direction == 'horizontal':
                for i in range(5):
                    card = self.tableau[start_index][i]
                    self.tableau[start_index][i] = None  # Or remove the card from the tableau in your implementation
                    self.claim.append(card)
            elif direction == 'vertical':
                for i in range(5):
                    card = self.tableau[i][start_index]
                    self.tableau[i][start_index] = None  # Or remove the card from the tableau in your implementation
                    self.claim.append(card)                

As soon as I play a card, I get this error:
```
I'm sorry, but an uncaught exception occurred.

While running game code:
File "game/script.rpy", line 16, in script
python:
File "game/script.rpy", line 20, in <module>
event = e.interact()
File "game/Elfjack.rpy", line 163, in interact
self.check_for_scoring()
File "game/Elfjack.rpy", line 116, in check_for_scoring
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 116, in <lambda>
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 116, in <listcomp>
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 115, in <genexpr>
column_stacks = (stack[col] for stack in self.tableau)
File "game/cardgame.rpy", line 516, in __getitem__
return self.cards[idx].value
IndexError: list index out of range

-- Full Traceback ------------------------------------------------------------

Full traceback:
File "game/script.rpy", line 16, in script
python:
File "C:\Users\thexe\Downloads\renpy-8.0.3-sdk\renpy\ast.py", line 1138, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "C:\Users\thexe\Downloads\renpy-8.0.3-sdk\renpy\python.py", line 1122, in py_exec_bytecode
exec(bytecode, globals, locals)
File "game/script.rpy", line 20, in <module>
event = e.interact()
File "game/Elfjack.rpy", line 163, in interact
self.check_for_scoring()
File "game/Elfjack.rpy", line 116, in check_for_scoring
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 116, in <lambda>
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 116, in <listcomp>
top_cards = [stack[-1] for stack in column_stacks if stack]
File "game/Elfjack.rpy", line 115, in <genexpr>
column_stacks = (stack[col] for stack in self.tableau)
File "game/cardgame.rpy", line 516, in __getitem__
return self.cards[idx].value
File "C:\Users\thexe\Downloads\renpy-8.0.3-sdk\renpy\revertable.py", line 217, in __getitem__
rv = list.__getitem__(self, index)
IndexError: list index out of range

Windows-10-10.0.22621 AMD64
Ren'Py 8.1.3.23091805
Elfjack 1.0
Thu Feb 1 13:41:15 2024
```

thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

Re: Cardgame Framework help: vertical and horizontal scoring checks?

#3 Post by thexerox123 »

I've altered my scoring method to just see if I can have it print the integer that corresponds with the suit of each top card in the tableau, and have had success in doing that, at least:

Code: Select all

        def check_for_scoring(self):
            for row in range(5):
                for col in range(5):
                    stack = self.tableau[row * 5 + col]  # Access the stack in the 5x5 grid
                    if stack and len(stack) > 0:
                        top_card = stack[-1]
                        suit = top_card[0]  # Access the first element of the tuple
                        print(f"Card at Row {row + 1}, Column {col + 1}: Suit - {suit}")
                    else:
                        print(f"No card at Row {row + 1}, Column {col + 1}")    

     
Card at Row 1, Column 1: Suit - 4
Card at Row 1, Column 2: Suit - 1
Card at Row 1, Column 3: Suit - 0
Card at Row 1, Column 4: Suit - 4
Card at Row 1, Column 5: Suit - 3
Card at Row 2, Column 1: Suit - 1
Card at Row 2, Column 2: Suit - 4
Card at Row 2, Column 3: Suit - 0
Card at Row 2, Column 4: Suit - 2
Card at Row 2, Column 5: Suit - 1
Card at Row 3, Column 1: Suit - 3
Card at Row 3, Column 2: Suit - 3
Card at Row 3, Column 3: Suit - 4
Card at Row 3, Column 4: Suit - 4
Card at Row 3, Column 5: Suit - 2
Card at Row 4, Column 1: Suit - 0
Card at Row 4, Column 2: Suit - 3
Card at Row 4, Column 3: Suit - 3
Card at Row 4, Column 4: Suit - 0
Card at Row 4, Column 5: Suit - 2
Card at Row 5, Column 1: Suit - 4
Card at Row 5, Column 2: Suit - 2
Card at Row 5, Column 3: Suit - 4
Card at Row 5, Column 4: Suit - 0
Card at Row 5, Column 5: Suit - 2
Card at Row 1, Column 1: Suit - 4
Card at Row 1, Column 2: Suit - 1
Card at Row 1, Column 3: Suit - 0
Card at Row 1, Column 4: Suit - 4
Card at Row 1, Column 5: Suit - 3
Card at Row 2, Column 1: Suit - 1
Card at Row 2, Column 2: Suit - 4
Card at Row 2, Column 3: Suit - 0
Card at Row 2, Column 4: Suit - 2
Card at Row 2, Column 5: Suit - 2
Card at Row 3, Column 1: Suit - 3
Card at Row 3, Column 2: Suit - 3
Card at Row 3, Column 3: Suit - 4
Card at Row 3, Column 4: Suit - 4
Card at Row 3, Column 5: Suit - 2
Card at Row 4, Column 1: Suit - 0
Card at Row 4, Column 2: Suit - 3
Card at Row 4, Column 3: Suit - 3
Card at Row 4, Column 4: Suit - 0
Card at Row 4, Column 5: Suit - 2
Card at Row 5, Column 1: Suit - 4
Card at Row 5, Column 2: Suit - 2
Card at Row 5, Column 3: Suit - 4
Card at Row 5, Column 4: Suit - 0
Card at Row 5, Column 5: Suit - 2
Card at Row 1, Column 1: Suit - 4
Card at Row 1, Column 2: Suit - 1
Card at Row 1, Column 3: Suit - 0
Card at Row 1, Column 4: Suit - 4
Card at Row 1, Column 5: Suit - 2
Card at Row 2, Column 1: Suit - 1
Card at Row 2, Column 2: Suit - 4
Card at Row 2, Column 3: Suit - 0
Card at Row 2, Column 4: Suit - 2
Card at Row 2, Column 5: Suit - 2
Card at Row 3, Column 1: Suit - 3
Card at Row 3, Column 2: Suit - 3
Card at Row 3, Column 3: Suit - 4
Card at Row 3, Column 4: Suit - 4
Card at Row 3, Column 5: Suit - 2
Card at Row 4, Column 1: Suit - 0
Card at Row 4, Column 2: Suit - 3
Card at Row 4, Column 3: Suit - 3
Card at Row 4, Column 4: Suit - 0
Card at Row 4, Column 5: Suit - 2
Card at Row 5, Column 1: Suit - 4
Card at Row 5, Column 2: Suit - 2
Card at Row 5, Column 3: Suit - 4
Card at Row 5, Column 4: Suit - 0
Card at Row 5, Column 5: Suit - 2
So maybe now I can work from this towards checking the suits against each other per row and column.


Edit: And now I have it successfully identifying when I get 5 in a row/column as confirmed by a print statement... I guess I just need to sort out how to have it move them over to the claim stack now. (Then I need to figure out my wild cards, which is a whole other kettle of fish.)

Code: Select all

        def check_for_scoring(self):
            row_suits = [[] for _ in range(5)]  # Initialize lists for each row
            col_suits = [[] for _ in range(5)]  # Initialize lists for each column        

            for row in range(5):
                for col in range(5):
                    stack = self.tableau[row * 5 + col]  # Access the stack in the 5x5 grid
                    if stack and len(stack) > 0:
                        top_card = stack[-1]
                        suit = top_card[0]  # Access the first element of the tuple
                        row_suits[row].append(suit)
                        col_suits[col].append(suit)        

            # Check for a run of five in rows
            for row, suits in enumerate(row_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Row {row}!")
                    # self.move_cards_to_claim(row, 'row')        

            # Check for a run of five in columns
            for col, suits in enumerate(col_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Column {col}!")
                    # self.move_cards_to_claim(col, 'col')
            

        def check_run_of_five(self, suits):
            # Check if there is a run of five of the same suit, including 0
            for suit in set(suits):
                if suits.count(suit) == 5:
                    return True
            return False        

thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

Re: Cardgame Framework help: vertical and horizontal scoring checks?

#4 Post by thexerox123 »

Sorry for just spamming my own thread, but I think I've got it mostly figured out!

Code: Select all

init python:

    class ElfJack(object):

        BAUBLE = 0
        SNOW = 1
        GINGER = 2
        REINDEER = 3
        STAR = 4
        SANTA = 5
        GRUMP = 6
        CANE = 7   

        def __init__(self):
            # Constants that let us easily change where the game is
            # located.
            LEFT=700
            TOP=158
            COL_SPACING = 150
            ROW_SPACING = 180
            CARD_XSPACING = 0.5
            CARD_YSPACING = 0.5

            # Create the table, stock, discard, and claim.
            self.table = t = Table(base="images/base.png", back="images/back.png")
            self.stock = t.stack(LEFT + 900, TOP, xoff=0.5, yoff=0.2, show=50, click=True)
            self.claim = t.stack(LEFT + 950, TOP + 700, xoff=CARD_XSPACING, drag=DRAG_NONE, click=True)
            self.hand = t.stack(LEFT + 105, TOP + 900, xoff=100, yoff=0, drag=DRAG_CARD, click=True)

            self.discard = []
            d = t.stack(LEFT + 790, TOP + 700, xoff=CARD_XSPACING, yoff=CARD_YSPACING, show=50, drag=DRAG_NONE, click=True, drop=True)
            self.discard.append(d)

            # The 25 tableau stacks.
            self.tableau = [ ]
            for row in range(5):
                for col in range(5):
                    s = t.stack(LEFT + COL_SPACING * col, TOP + ROW_SPACING * row, xoff=0, yoff=CARD_YSPACING, show=10, drag=DRAG_NONE, click=True, drop=True)
                    self.tableau.append(s)

            # Create the stock and shuffle it.
            for rank in range(0, 12):
                for suit in range(0, 5):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)


            self.stock.shuffle()

            # Deal out the initial tableau.
            for i in range(0, 1):
                for j in range(0, 25):
                    c = self.stock.deal()
                    self.tableau[j].append(c)
                    self.table.set_faceup(c, True)

            for rank in range(0, 3):
                for suit in range(5, 7):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)

            self.stock.shuffle()

            for i in range(0, 5):
                c = self.stock.deal()
                self.hand.append(c)
                self.table.set_faceup(c, True)


        def show(self):
            self.table.show()

        def hide(self):
            self.table.hide()

        def tableau_drag(self, evt):
            # We can only drag one card at a time to a tableau space.
            if len(evt.drag_cards) != 1:
                return False

            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "tableau_drag"

        def discard_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "discard_drag"

        def claim_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "claim drag"


        def stock_click(self, evt):
            if len(self.hand) == 5:
                return False

            else:
                if self.stock:
                    c = self.stock.deal()
                    self.table.set_faceup(c, True)
                    self.hand.append(c)

        def check_for_scoring(self):
            row_suits = [[] for _ in range(5)]  # Initialize lists for each row
            col_suits = [[] for _ in range(5)]  # Initialize lists for each column                

            for row in range(5):
                for col in range(5):
                    stack = self.tableau[row * 5 + col]  # Access the stack in the 5x5 grid
                    if stack and len(stack) > 0:
                        top_card = stack[-1]
                        suit = top_card[0]  # Access the first element of the tuple
                        row_suits[row].append(suit)
                        col_suits[col].append(suit)                

            # Check for a run of five in rows
            for row, suits in enumerate(row_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Row {row}!")
                    self.move_cards_to_claim(row, 'row')                

            # Check for a run of five in columns
            for col, suits in enumerate(col_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Column {col}!")
                    self.move_cards_to_claim(col, 'col')

            

        def check_run_of_five(self, suits):
            # Check if there is a run of five of the same suit, including 0
            for suit in set(suits):
                if suits.count(suit) == 5:
                    return True
            return False        

        def move_cards_to_claim(self, index, direction):
            if direction == 'row':
                for col_idx in range(5):
                    stack = self.tableau[(index - 1) * 5 + col_idx]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)
            elif direction == 'col':
                for row_idx in range(5):
                    stack = self.tableau[row_idx * 5 + index - 1]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)        

            return "claim_drag"        
        






        def interact(self):        

            evt = ui.interact()
            rv = False        

            # Check the various events, and dispatch them to the methods
            # that handle them.
            if evt.type == "drag":
                if evt.drop_stack in self.tableau:
                    rv = self.tableau_drag(evt)        

                elif evt.drop_stack in self.discard:
                    rv = self.discard_drag(evt)     

                elif evt.drop_stack in self.claim:
                    rv = self.claim_drag(evt)   

            elif evt.type == "click":
                if evt.stack == self.stock:
                    rv = self.stock_click(evt)        

            # elif evt.type == "doubleclick":
            #     if (evt.stack in self.tableau) or (evt.stack is self.waste):
            #         rv = self.tableau_doubleclick(evt)   
            self.check_for_scoring()     

            # Check for the win condition when all tableau stacks are empty.
            if all(len(stack) == 0 for stack in self.tableau):
                return "win"        

            return rv

        # Sets things as sensitive (or not).
        def set_sensitive(self, value):
            self.table.set_sensitive(value)

Now I just need to figure out how to get my wild cards working.

thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

Re: Cardgame Framework help: vertical and horizontal scoring checks?

#5 Post by thexerox123 »

So, I actually did manage to get both of my wild cards working!

Image

I've also added an auto-deal function/toggle.

Currently trying to get the restart and undo buttons that I've added working!

The current state of my script:

script.rpy:

Code: Select all

init:
    default btn_selected = False

    screen santa_suit_selection:
        hbox:
            spacing 20
            xalign 0.5
            yalign 0.5    

            imagebutton:
                idle "images/B0.png" 
                action Function(e.select_suit, 0)
            imagebutton:
                idle "images/B1.png" 
                action Function(e.select_suit, 1)
            imagebutton:
                idle "images/B2.png" 
                action Function(e.select_suit, 2)
            imagebutton:
                idle "images/B3.png" 
                action Function(e.select_suit, 3)
            imagebutton:
                idle "images/B4.png" 
                action Function(e.select_suit, 4)    

    screen grump_suit_selection:
        hbox:
            spacing 20
            xalign 0.5
            yalign 0.5    

            imagebutton:
                idle "images/B0.png" 
                action Function(e.select_grump_suit, 0)
            imagebutton:
                idle "images/B1.png" 
                action Function(e.select_grump_suit, 1)
            imagebutton:
                idle "images/B2.png" 
                action Function(e.select_grump_suit, 2)
            imagebutton:
                idle "images/B3.png" 
                action Function(e.select_grump_suit, 3)
            imagebutton:
                idle "images/B4.png" 
                action Function(e.select_grump_suit, 4)    

    screen autotoggle:
        hbox:
            imagebutton:
                idle "images/SwitchOff.png"
                hover "images/SwitchOff.png"
                selected_idle "images/SwitchOn.png"
                selected_hover "images/SwitchOn.png"
                action [ToggleVariable("e.auto_deal_mode", True, False)]
                selected e.auto_deal_mode
                xpos 1800 ypos 100
        hbox:
            text "Auto-Deal":
                color "#FFFFFF"
                size 12
                xpos 1795 ypos 200


    screen elfjack_interface:
        vbox:  

            textbutton "Restart Game" action Function(e.restart_game)
            
            textbutton "Undo Last Move" action Function(e.undo_last_move)


label start:
    scene bg felt

    python:
        e = ElfJack()
        e.set_sensitive(True)
        e.show()

    # Show the autodeal toggle button
    show screen autotoggle

    show screen elfjack_interface

label continual:
    while True:

        python:
        
            # ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
            # e.set_sensitive(True)
            event = e.interact()

            if event:
                renpy.checkpoint()
            
        if event == "win":
            jump win

label win:
    "YOU WIN!"
    return
Elfjack.rpy:

Code: Select all

init python:

    class ElfJack(object):

        BAUBLE = 0
        SNOW = 1
        GINGER = 2
        REINDEER = 3
        STAR = 4
        SANTA = 5
        GRUMP = 6
        CANE = 7   

        def __init__(self):
            # Constants that let us easily change where the game is
            # located.
            LEFT=700
            TOP=158
            COL_SPACING = 150
            ROW_SPACING = 180
            CARD_XSPACING = 0.5
            CARD_YSPACING = 0.5


            # Create the table, stock, discard, and claim.
            self.table = t = Table(base="images/base.png", back="images/back.png")
            self.stock = t.stack(LEFT + 900, TOP, xoff=0.5, yoff=0.2, show=50, click=True)
            self.claim = t.stack(LEFT + 950, TOP + 700, xoff=CARD_XSPACING, drag=DRAG_NONE, click=True)
            self.hand = t.stack(LEFT + 105, TOP + 900, xoff=100, yoff=0, drag=DRAG_CARD, click=True)

            self.last_card_event = None  # Variable to store information about the last card event
            
            self.auto_deal_mode = True
            self.discard = []
            d = t.stack(LEFT + 790, TOP + 700, xoff=CARD_XSPACING, yoff=CARD_YSPACING, show=50, drag=DRAG_NONE, click=True, drop=True)
            self.discard.append(d)

            # The 25 tableau stacks.
            self.tableau = [ ]
            for row in range(5):
                for col in range(5):
                    s = t.stack(LEFT + COL_SPACING * col, TOP + ROW_SPACING * row, xoff=0, yoff=CARD_YSPACING, show=10, drag=DRAG_NONE, click=True, drop=True)
                    self.tableau.append(s)

            # Create the stock and shuffle it.
            for rank in range(0, 13):
                for suit in range(0, 5):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)


            self.stock.shuffle()

            # Deal out the initial tableau.
            for i in range(0, 1):
                for j in range(0, 25):
                    c = self.stock.deal()
                    self.tableau[j].append(c)
                    self.table.set_faceup(c, True)

            for rank in range(0, 3):
                for suit in range(5, 7):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)

            self.stock.shuffle()

            for i in range(0, 5):
                c = self.stock.deal()
                self.hand.append(c)
                self.table.set_faceup(c, True)


        def show(self):
            self.table.show()

        def hide(self):
            self.table.hide()

        def restart_game(self):
            # Reset the game state
            self.__init__()

        def undo_last_move(self):
            # Check if there's a move to undo
            if self.last_card_event:
                move_type = self.last_card_event["type"]
                
                if move_type == "drag":
                    # Undo the drag move
                    self.undo_drag()    

                # Update last move information after undo
                self.last_card_event = None    

        def undo_drag(self):
            # Check if there's a drag event in the last move
            if self.last_card_event and self.last_card_event["type"] == "drag":
                # Check if the 'drag_cards' key is present in the last card event
                if "drag_cards" in self.last_card_event:
                    card = self.last_card_event["drag_cards"][0]
                    self.hand.append(card)        

                    # If auto-deal mode is on, return the card to the stock
                    if self.auto_deal_mode:
                        self.stock.append(card)        

            # Reset last_card_event
            self.last_card_event = None



        def show_santa_suit_selection(self, tableau_stack):
            renpy.call_screen("santa_suit_selection", tableau_stack)         

        def select_suit(self, button_index):
            # Mapping button index to suit index
            suit_index = button_index                

            # Iterate through all tableau stacks
            for stack in self.tableau:
                # Find Santa cards in the stack with the specified suit
                santa_cards = [card for card in stack if card[0] == 5]
                
                if santa_cards:
                    # Calculate the next rank based on the Santa card's index
                    next_rank = 13 + stack[-1][1]
                
                    # Update the suit and rank of any Santa cards in the tableau
                    for card in santa_cards:
                        value = (suit_index, next_rank)
                        self.table.card(value, "images/%d.png" % suit_index)
                        stack.remove(card)  # Remove the old Santa card from the tableau
                        stack.append(value)  # Add the updated card to the tableau
                      

            # After updating the Santa card, hide the santa_suit_selection screen
            renpy.hide_screen("santa_suit_selection")    
                
            # You can return a value indicating the result, or None if not needed
            return "suit_selected"

        def toggle_auto_deal_mode(self):
            # Toggle the auto-deal mode
            self.auto_deal_mode = not self.auto_deal_mode

        def show_grump_suit_selection(self, grump_stack):
            renpy.call_screen("grump_suit_selection", grump_stack)    


        def select_grump_suit(self, button_index):
            # Mapping button index to suit index
            suit_index = button_index    

            # Get the index of the Grump stack
            grump_stack_index = self.tableau.index([stack for stack in self.tableau if stack and stack[-1][0] == 6][0])    

            # Claim the Grump card
            grump_stack = self.tableau[grump_stack_index]
            grump_card = grump_stack[-1]
            grump_stack.remove(grump_card)
            self.claim.append(grump_card)    

            # Iterate through adjacent stacks of the chosen suit
            for stack in self.tableau:
                if stack and stack[-1][0] == suit_index and self.are_adjacent_stacks(grump_stack, stack):
                    card = stack.deal()
                    if card:
                        self.claim.append(card)    

            # After updating, hide the grump_suit_selection screen
            renpy.hide_screen("grump_suit_selection")   

            return "grump_selected"

        def are_adjacent_stacks(self, stack1, stack2):
            # Check if two stacks are adjacent (orthogonal or diagonal)
            row1, col1 = divmod(self.tableau.index(stack1), 5)
            row2, col2 = divmod(self.tableau.index(stack2), 5)    

            return (
                abs(row1 - row2) <= 1 and abs(col1 - col2) <= 1 and (row1 != row2 or col1 != col2)
            )  



        def tableau_drag(self, evt):
            # We can only drag one card at a time to a tableau space.
            if len(evt.drag_cards) != 1:
                return False        

            card = suit, rank = evt.drag_cards[0]
            if card[0] == 5:  # Check if it's a Santa card
                evt.drop_stack.append(evt.drag_cards[0])
                # Show suit selection buttons and pass the stack to select_suit
                self.show_santa_suit_selection(evt.drop_stack)
                return "tableau_drag"  # Return after showing the suit selection buttons  

            if card[0] == 6:  # Check if it's a Grump card
                evt.drop_stack.append(evt.drag_cards[0])
                # Show suit selection buttons and pass the stack to select_grump_suit
                self.show_grump_suit_selection(evt.drop_stack)
                return "tableau_drag"  # Return after showing the suit selection buttons


            evt.drop_stack.append(evt.drag_cards[0])        

            return "tableau_drag"



        def discard_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "discard_drag"

        def claim_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "claim drag"


        def stock_click(self, evt):
            if len(self.hand) == 5:
                return False

            else:
                if self.stock:
                    c = self.stock.deal()
                    self.table.set_faceup(c, True)
                    self.hand.append(c)

        def auto_deal_to_hand(self):
            # Auto-deal cards from the stock to the hand until it reaches 5 cards
            while len(self.hand) < 5 and self.stock:
                c = self.stock.deal()
                self.table.set_faceup(c, True)
                self.hand.append(c)


        def check_for_scoring(self):
            row_suits = [[] for _ in range(5)]  # Initialize lists for each row
            col_suits = [[] for _ in range(5)]  # Initialize lists for each column                

            for row in range(5):
                for col in range(5):
                    stack = self.tableau[row * 5 + col]  # Access the stack in the 5x5 grid
                    if stack and len(stack) > 0:
                        top_card = stack[-1]
                        suit = top_card[0]  # Access the first element of the tuple
                        row_suits[row].append(suit)
                        col_suits[col].append(suit)                

            # Check for a run of five in rows
            for row, suits in enumerate(row_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Row {row}!")
                    self.move_cards_to_claim(row, 'row')                

            # Check for a run of five in columns
            for col, suits in enumerate(col_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Column {col}!")
                    self.move_cards_to_claim(col, 'col')

            

        def check_run_of_five(self, suits):
            # Check if there is a run of five of the same suit, including 0
            for suit in set(suits):
                if suits.count(suit) == 5:
                    return True
            return False        

        def move_cards_to_claim(self, index, direction):
            if direction == 'row':
                for col_idx in range(5):
                    stack = self.tableau[(index - 1) * 5 + col_idx]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)
            elif direction == 'col':
                for row_idx in range(5):
                    stack = self.tableau[row_idx * 5 + index - 1]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)        

            return "claim_drag"        
    

        def interact(self):        
            evt = ui.interact()
            rv = False        

            # Check the various events, and dispatch them to the methods
            # that handle them.
            if evt.type == "drag":
                self.last_card_event = {"type": "drag", "data": evt, "stack": evt.drop_stack}
                if evt.drop_stack in self.tableau:
                    rv = self.tableau_drag(evt)     
                elif evt.drop_stack in self.discard:
                    rv = self.discard_drag(evt)     
                elif evt.drop_stack in self.claim:
                    rv = self.claim_drag(evt)   
            elif evt.type == "click":
                if evt.stack == self.stock:
                    rv = self.stock_click(evt)                

            # Save game state after each interaction
            renpy.checkpoint()

            if self.auto_deal_mode == True:
                self.auto_deal_to_hand()

            self.check_for_scoring()     
            self.check_for_scoring()    

            if self.auto_deal_mode == True:
                self.auto_deal_to_hand()

            # Check for the win condition when all tableau stacks are empty.
            if all(len(stack) == 0 for stack in self.tableau):
                return "win"        

            return rv

        # Sets things as sensitive (or not).
        def set_sensitive(self, value):
            self.table.set_sensitive(value)
   
The undo feature is proving pretty tricky to implement, but it sucks to drop the card on the wrong spot on the tableau and then just be out of luck, so gotta try to get that figured out.

thexerox123
Regular
Posts: 134
Joined: Fri Jan 20, 2023 3:21 pm
itch: thexerox123
Contact:

Re: [SOLVED] Cardgame Framework help: vertical and horizontal scoring checks?

#6 Post by thexerox123 »

Well, I'm going to mark this solved, I've figured out pretty well everything I wanted to do with the game!

Image

https://thexerox123.itch.io/elfjack-solitaire

script.rpy:

Code: Select all

init:
    default btn_selected = False

    transform zoomy:
        zoom 0.4

    transform zoommid:
        zoom 0.6
    transform zoomnice:
        zoom 0.69
    transform zoomless:
        zoom 0.7

    screen santa_suit_selection:
        hbox:
            spacing 20
            xalign 0.5
            yalign 0.5    

            imagebutton:
                idle "images/B0.png" 
                action Function(e.select_suit, 0)
            imagebutton:
                idle "images/B1.png" 
                action Function(e.select_suit, 1)
            imagebutton:
                idle "images/B2.png" 
                action Function(e.select_suit, 2)
            imagebutton:
                idle "images/B3.png" 
                action Function(e.select_suit, 3)
            imagebutton:
                idle "images/B4.png" 
                action Function(e.select_suit, 4)    

    screen grump_suit_selection:
        hbox:
            spacing 20
            xalign 0.5
            yalign 0.5    

            imagebutton:
                idle "images/B0.png" 
                action Function(e.select_grump_suit, 0)
            imagebutton:
                idle "images/B1.png" 
                action Function(e.select_grump_suit, 1)
            imagebutton:
                idle "images/B2.png" 
                action Function(e.select_grump_suit, 2)
            imagebutton:
                idle "images/B3.png" 
                action Function(e.select_grump_suit, 3)
            imagebutton:
                idle "images/B4.png" 
                action Function(e.select_grump_suit, 4)    

    screen autotoggle:
        hbox:
            imagebutton:
                idle "images/SwitchOff.png"
                hover "images/SwitchOff.png"
                selected_idle "images/SwitchOn.png"
                selected_hover "images/SwitchOn.png"
                action [ToggleVariable("e.auto_deal_mode", True, False)]
                selected e.auto_deal_mode
                xpos 1800 ypos 100
        hbox:
            text "Auto-Deal":
                color "#FFFFFF"
                size 12
                xpos 1795 ypos 200


    screen elfjack_interface:
        vbox:  
            textbutton "Rules" action Show("rulebook1")

            textbutton "Restart Game" action Function(e.restart_game)

            textbutton "Undo Last Move" action Function(e.undo_drag)

            textbutton "Change Setting" action ToggleVariable("e.current_location", 0, 1)

            # textbutton "Change Card Back" action ToggleVariable("e.current_back", 0, 1, 2, 3, 4)

            textbutton "Exit" action MainMenu(confirm=False)

    screen background_table:
        if e.current_location == 0:
            add "images/bg/bg felt.png"
        if e.current_location == 1:
            add "images/bg/bg tabletop2.png"

    screen winner:
        vbox:
            imagebutton:
                idle "images/YouWin.png"
                action MainMenu(confirm=False)
                xpos 220 ypos 370

    screen rulebook1:
            vbox:
                add "images/bg/bg darken.png"
            vbox:
                add "images/ElfjackOnlineRules.png"
                xalign 0.5 yalign 0.33 
            vbox:
                imagebutton:
                    idle "images/Right_idle.png"
                    hover "images/Right_Hover.png"
                    action [Show("rulebook2"), Hide("rulebook1")]
                    xpos 1700 ypos 780
                    at zoomy
            vbox:
                imagebutton:
                    idle "images/Exit.png"
                    action Hide("rulebook1")
                    xpos 900 ypos 930
                    at zoommid

    screen rulebook2:
            vbox:
                add "images/bg/bg darken.png"
            vbox:
                add "images/ElfjackOnlineRules2.png"
                xalign 0.5 yalign 0.33 
            vbox:
                imagebutton:
                    idle "images/Left_Idle.png"
                    hover "images/Left_Hover.png"
                    action [Show("rulebook1"), Hide("rulebook2")]
                    xpos 40 ypos 780
                    at zoomy
            vbox:
                imagebutton:
                    idle "images/Exit.png"
                    action Hide("rulebook2")
                    xpos 900 ypos 930
                    at zoommid

label start:
    scene bg transparency
    show screen background_table onlayer bglayer

    python:
        e = ElfJack()
        e.set_sensitive(True)
        e.show()

    # Show the autodeal toggle button
    show screen autotoggle

    show screen elfjack_interface

label continual:
    while True:
        python:

            # ui.textbutton("Give Up", ui.jumps("giveup"), xalign=.02, yalign=.98)
            # e.set_sensitive(True)
            event = e.interact()

            # e.update_table_images()

            if event:
                renpy.checkpoint()
            
        if event == "win":
            jump win

label win:
    show screen winner 
    $ renpy.pause(hard=True)
    return
Elfjack.rpy:

Code: Select all

init python:

    class ElfJack(object):

        BAUBLE = 0
        SNOW = 1
        GINGER = 2
        REINDEER = 3
        STAR = 4
        SANTA = 5
        GRUMP = 6
        CANE = 7   

        def __init__(self):
            # Constants that let us easily change where the game is
            # located.
            LEFT=700
            TOP=158
            COL_SPACING = 150
            ROW_SPACING = 180
            CARD_XSPACING = 0.5
            CARD_YSPACING = 0.5


            # Create the table, stock, discard, and claim.
            self.table = t = Table(base="images/base.png", back="images/back.png")
            self.stock = t.stack(LEFT + 900, TOP, xoff=0.5, yoff=0.2, show=50, click=True)
            self.claim = t.stack(LEFT + 950, TOP + 700, xoff=CARD_XSPACING, drag=DRAG_NONE, click=True)
            self.hand = t.stack(LEFT + 105, TOP + 900, xoff=100, yoff=0, drag=DRAG_CARD, click=True)

            self.current_location = 0

            self.current_back = 0

            self.last_card_event = None  # Variable to store information about the last card event
            
            self.auto_deal_mode = True
            self.discard = []
            d = t.stack(LEFT + 790, TOP + 700, xoff=CARD_XSPACING, yoff=CARD_YSPACING, show=50, drag=DRAG_NONE, click=True, drop=True)
            self.discard.append(d)

            # The 25 tableau stacks.
            self.tableau = [ ]
            for row in range(5):
                for col in range(5):
                    s = t.stack(LEFT + COL_SPACING * col, TOP + ROW_SPACING * row, xoff=0, yoff=CARD_YSPACING, show=10, drag=DRAG_NONE, click=True, drop=True)
                    self.tableau.append(s)

            # Create the stock and shuffle it.
            for rank in range(0, 13):
                for suit in range(0, 5):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit, back=None)
                    t.set_faceup(value, False)
                    self.stock.append(value)


            self.stock.shuffle()

            # Deal out the initial tableau.
            for i in range(0, 1):
                for j in range(0, 25):
                    c = self.stock.deal()
                    self.tableau[j].append(c)
                    self.table.set_faceup(c, True)

            for rank in range(0, 3):
                for suit in range(5, 7):
                    value = (suit, rank)
                    t.card(value, "images/%d.png" % suit)
                    t.set_faceup(value, False)
                    self.stock.append(value)

            self.stock.shuffle()

            for i in range(0, 5):
                c = self.stock.deal()
                self.hand.append(c)
                self.table.set_faceup(c, True)


        def show(self):
            self.table.show()

        def hide(self):
            self.table.hide()

        def restart_game(self):
            # Reset necessary game state variables
            self.tableau = []
            self.discard = []
            self.claim = []
            self.hand = []    

            # Show the starting screen
            renpy.jump("start")     
         

        def undo_drag(self):
            # Check if there's a drag event in the last move
            if self.last_card_event and self.last_card_event["type"] == "drag":
                # Check if the 'drag_cards' key is present in the last card event
                if "drag_cards" in self.last_card_event:
                    card = self.last_card_event["drag_cards"][0]        

                    # Check if auto-deal mode is on
                    if self.auto_deal_mode:
                        # Return the auto-dealt card from the hand to the stock
                        auto_dealt_card = self.hand[-1]  # Access the top card of the stack
                        self.table.set_faceup(auto_dealt_card, False)
                        self.stock.append(auto_dealt_card) 



                    # Return the dragged card from the tableau or discard to the hand
                    self.hand.append(card)  # Move the card to the hand        

            # Reset last_card_event
            self.last_card_event = None




        # def update_table_images(self):
        #     # Get the current state of your current_location variable
        #     current_location = self.current_location    

        #     # Set the base and back images based on the current_location variable
        #     if current_location == 0:  # Chateau
        #         # Change appearance for tableau stacks
        #         for stack in self.tableau:
        #             stack.base = "images/base.png"
        #             for card in stack:
        #                 card.back = "images/back5.png"   

        #         # Change appearance for other stacks
        #         for stack in [self.stock, self.discard, self.claim, self.hand]:
        #             stack.base = "images/base.png"
        #             for card in stack:
        #                 card.back = "images/back5.png"

        #     elif current_location == 1:  # Pub
        #         # Change appearance for tableau stacks
        #         for stack in self.tableau:
        #             stack.base = "images/base2.png"
        #             for card in stack:
        #                 card.back = "images/back.png"   

        #         # Change appearance for other stacks
        #         for stack in [self.stock, self.discard, self.claim, self.hand]:
        #             stack.base = "images/base2.png"
        #             for card in stack:
        #                 card.back = "images/back.png"

        def change_card_appearance(self, new_base, new_back):
            # Change appearance for tableau stacks
            for stack in self.tableau:
                stack.base = new_base
                for card in stack:
                    card.back = new_back    

            # Change appearance for other stacks
            for stack in [self.stock, self.discard, self.claim, self.hand]:
                stack.base = new_base
                for card in stack:
                    card.back = new_back

        def show_santa_suit_selection(self, tableau_stack):
            renpy.call_screen("santa_suit_selection", tableau_stack)         

        def select_suit(self, button_index):
            # Mapping button index to suit index
            suit_index = button_index                

            # Iterate through all tableau stacks
            for stack in self.tableau:
                # Find Santa cards in the stack with the specified suit
                santa_cards = [card for card in stack if card[0] == 5]
                
                if santa_cards:
                    # Calculate the next rank based on the Santa card's index
                    next_rank = 13 + stack[-1][1]
                
                    # Update the suit and rank of any Santa cards in the tableau
                    for card in santa_cards:
                        value = (suit_index, next_rank)
                        self.table.card(value, "images/%d.png" % suit_index)
                        stack.remove(card)  # Remove the old Santa card from the tableau
                        stack.append(value)  # Add the updated card to the tableau
                      

            # After updating the Santa card, hide the santa_suit_selection screen
            renpy.hide_screen("santa_suit_selection")    
                
            # You can return a value indicating the result, or None if not needed
            return "suit_selected"

        def toggle_auto_deal_mode(self):
            # Toggle the auto-deal mode
            self.auto_deal_mode = not self.auto_deal_mode

        def show_grump_suit_selection(self, grump_stack):
            renpy.call_screen("grump_suit_selection", grump_stack)    


        def select_grump_suit(self, button_index):
            # Mapping button index to suit index
            suit_index = button_index    

            # Get the index of the Grump stack
            grump_stack_index = self.tableau.index([stack for stack in self.tableau if stack and stack[-1][0] == 6][0])    

            # Claim the Grump card
            grump_stack = self.tableau[grump_stack_index]
            grump_card = grump_stack[-1]
            grump_stack.remove(grump_card)
            self.claim.append(grump_card)    

            # Iterate through adjacent stacks of the chosen suit
            for stack in self.tableau:
                if stack and stack[-1][0] == suit_index and self.are_adjacent_stacks(grump_stack, stack):
                    card = stack.deal()
                    if card:
                        self.claim.append(card)    

            # After updating, hide the grump_suit_selection screen
            renpy.hide_screen("grump_suit_selection")   

            return "grump_selected"

        def are_adjacent_stacks(self, stack1, stack2):
            # Check if two stacks are adjacent (orthogonal or diagonal)
            row1, col1 = divmod(self.tableau.index(stack1), 5)
            row2, col2 = divmod(self.tableau.index(stack2), 5)    

            return (
                abs(row1 - row2) <= 1 and abs(col1 - col2) <= 1 and (row1 != row2 or col1 != col2)
            )  



        def tableau_drag(self, evt):
            # We can only drag one card at a time to a tableau space.
            if len(evt.drag_cards) != 1:
                return False        

            card = suit, rank = evt.drag_cards[0]
            if card[0] == 5:  # Check if it's a Santa card
                evt.drop_stack.append(evt.drag_cards[0])
                # Show suit selection buttons and pass the stack to select_suit
                self.show_santa_suit_selection(evt.drop_stack)
                return "tableau_drag"  # Return after showing the suit selection buttons  

            if card[0] == 6:  # Check if it's a Grump card
                evt.drop_stack.append(evt.drag_cards[0])
                # Show suit selection buttons and pass the stack to select_grump_suit
                self.show_grump_suit_selection(evt.drop_stack)
                return "tableau_drag"  # Return after showing the suit selection buttons


            evt.drop_stack.append(evt.drag_cards[0])        

            return "tableau_drag"



        def discard_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "discard_drag"

        def claim_drag(self, evt):
            card = suit, rank = evt.drag_cards[0]
            evt.drop_stack.append(evt.drag_cards[0])
            return "claim drag"


        def stock_click(self, evt):
            if len(self.hand) == 5:
                return False

            else:
                if self.stock:
                    c = self.stock.deal()
                    self.table.set_faceup(c, True)
                    self.hand.append(c)

        def auto_deal_to_hand(self):
            # Auto-deal cards from the stock to the hand until it reaches 5 cards
            while len(self.hand) < 5 and self.stock:
                c = self.stock.deal()
                self.table.set_faceup(c, True)
                self.hand.append(c)


        def check_for_scoring(self):
            row_suits = [[] for _ in range(5)]  # Initialize lists for each row
            col_suits = [[] for _ in range(5)]  # Initialize lists for each column                

            for row in range(5):
                for col in range(5):
                    stack = self.tableau[row * 5 + col]  # Access the stack in the 5x5 grid
                    if stack and len(stack) > 0:
                        top_card = stack[-1]
                        suit = top_card[0]  # Access the first element of the tuple
                        row_suits[row].append(suit)
                        col_suits[col].append(suit)                

            # Check for a run of five in rows
            for row, suits in enumerate(row_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Row {row}!")
                    self.move_cards_to_claim(row, 'row')                

            # Check for a run of five in columns
            for col, suits in enumerate(col_suits, start=1):
                if self.check_run_of_five(suits):
                    print(f"Five of a kind in Column {col}!")
                    self.move_cards_to_claim(col, 'col')

            

        def check_run_of_five(self, suits):
            # Check if there is a run of five of the same suit, including 0
            for suit in set(suits):
                if suits.count(suit) == 5:
                    return True
            return False        

        def move_cards_to_claim(self, index, direction):
            if direction == 'row':
                for col_idx in range(5):
                    stack = self.tableau[(index - 1) * 5 + col_idx]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)
            elif direction == 'col':
                for row_idx in range(5):
                    stack = self.tableau[row_idx * 5 + index - 1]
                    if stack:
                        card = stack.deal()
                        if card:
                            self.claim.append(card)        

            return "claim_drag"        
    

        def interact(self):        
            evt = ui.interact()
            rv = False        

            # Check the various events, and dispatch them to the methods
            # that handle them.
            if evt.type == "drag":
                dragged_cards = getattr(evt, "drag_cards", [])  # Get dragged cards if available
                self.last_card_event = {"type": "drag", "data": evt, "stack": evt.drop_stack, "drag_cards": dragged_cards}
                if evt.drop_stack in self.tableau:
                    rv = self.tableau_drag(evt)     
                elif evt.drop_stack in self.discard:
                    rv = self.discard_drag(evt)     
                elif evt.drop_stack in self.claim:
                    rv = self.claim_drag(evt)   
            elif evt.type == "click":
                if evt.stack == self.stock:
                    rv = self.stock_click(evt)                

            # Save game state after each interaction
            renpy.checkpoint()

            # Print the content of self.last_card_event
            print(f"self.last_card_event: {self.last_card_event}")


            if self.auto_deal_mode == True:
                self.auto_deal_to_hand()

            self.check_for_scoring()     
            self.check_for_scoring()    

            if self.auto_deal_mode == True:
                self.auto_deal_to_hand()

            # Check for the win condition when all tableau stacks are empty.
            if all(len(stack) == 0 for stack in self.tableau):
                return "win"        

            return rv

        # Sets things as sensitive (or not).
        def set_sensitive(self, value):
            self.table.set_sensitive(value)

The only thing I couldn't figure out in the end was how to dynamically change the base and back images used for the table... I wanted them to change along with the setting change, but kept getting errors. If anybody has any suggestions for how to implement that, I'd be very grateful! And if I ever figure it out, I'll post an update.

Post Reply

Who is online

Users browsing this forum: chesarty, Google [Bot], jeffster, limpciabatta, Majestic-12 [Bot], Semrush [Bot]