Skip to content

Conversation

@stirby
Copy link
Collaborator

@stirby stirby commented Jul 22, 2025

Adds rearrange hand functionality. Expects indexes for every card in hand.

I.E. for eight cards in hand: [0, 1, 2, 3, 4, 5, 6, 7], [7, 6, 5, 4, 3, 2, 1, 0].

Method

Sets card.order to provided sequence, then uses Balatro-native set_ranks() and align_cards() to update the ordering.

Tasks

  • Functionality
  • Types
  • Tests
  • Docs
  • Logging Hooks

@S1M0N38 S1M0N38 linked an issue Jul 22, 2025 that may be closed by this pull request
@stirby stirby marked this pull request as ready for review July 23, 2025 02:13
@stirby
Copy link
Collaborator Author

stirby commented Jul 23, 2025

I didn't add logging hooks because I believe the set_ranks() and align_cards() functions are called in the natural game flow. Looking into this now.

@stirby
Copy link
Collaborator Author

stirby commented Jul 23, 2025

I can confirm that set_ranks() and align_cards() are called extensively in CardArea.lua - including on load.

Open to advice on how to do the logging hooks.

function CardArea:load(cardAreaTable)

    if self.cards then remove_all(self.cards) end
    self.cards = {}
    if self.children then remove_all(self.children) end
    self.children = {}

    self.config = cardAreaTable.config

    for i = 1, #cardAreaTable.cards do
        loading = true
        local card = Card(0, 0, G.CARD_W, G.CARD_H, G.P_CENTERS.j_joker, G.P_CENTERS.c_base)
        loading = nil
        card:load(cardAreaTable.cards[i])
        self.cards[#self.cards + 1] = card
        if card.highlighted then 
            self.highlighted[#self.highlighted + 1] = card
        end
        card:set_card_area(self)
    end
    self:set_ranks()
    self:align_cards()
    self:hard_set_cards()
end

@S1M0N38
Copy link
Collaborator

S1M0N38 commented Jul 23, 2025

Thanks! I'll checkout this PR and see if there a simple way to implement the hook

@S1M0N38 S1M0N38 requested a review from Copilot July 23, 2025 12:20

This comment was marked as outdated.

@S1M0N38
Copy link
Collaborator

S1M0N38 commented Jul 23, 2025

---Hooks into CardArea:align_cards for hand reordering detection
function LOG.hook_hand_rearrange()
  local original_function = CardArea.align_cards
  CardArea.align_cards = function(self, dt, is_immediate)
    -- Only monitor hand cards
    ---@diagnostic disable-next-line: undefined-field
    if self.config and self.config.type == "hand" and self.cards then
      -- Capture card order before alignment
      local cards_before = {}
      ---@diagnostic disable-next-line: undefined-field
      for i, card in ipairs(self.cards) do
        cards_before[i] = card.sort_id
      end

      -- Call the original function
      local result = original_function(self, dt, is_immediate)

      -- Capture card order after alignment
      local cards_after = {}
      ---@diagnostic disable-next-line: undefined-field
      for i, card in ipairs(self.cards) do
        cards_after[i] = card.sort_id
      end

      -- Check if the order changed
      local order_changed = false
      for i = 1, #cards_before do
        if cards_before[i] ~= cards_after[i] then
          order_changed = true
          break
        end
      end

      if order_changed then
        sendInfoMessage("Hand rearranged - cards reordered", "LOG")
        sendInfoMessage("Before: " .. json.encode(cards_before), "LOG")
        sendInfoMessage("After: " .. json.encode(cards_after), "LOG")
      end

      return result
    else
      -- For non-hand card areas, just call the original function
      return original_function(self, dt, is_immediate)
    end
  end
  sendInfoMessage("Hooked into CardArea:align_cards for hand rearrange logging", "LOG")
end

I've added sort_id to cards in game state which is a unique id for each card in the hand.
This hook works when interacting with the game manually but it is not trigger when interacting with our Lua API.

Maybe there is some issue when calling G.hand:align_cards in line 559 in api.lua

@S1M0N38 S1M0N38 requested a review from Copilot July 23, 2025 15:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds hand rearrangement functionality to the BalatroBot API, allowing users to reorder cards in their hand by providing a complete index sequence. The implementation includes parameter validation, Lua game state integration, comprehensive testing, and documentation updates.

  • Adds rearrange_hand API function with validation for card indices and game state
  • Implements hand reordering using Balatro's native card management system
  • Includes logging hooks to track hand rearrangement events for debugging

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/lua/api.lua Implements the core rearrange_hand API function with validation and hand reordering logic
src/lua/types.lua Adds RearrangeHandArgs type definition for the new API function
src/lua/utils.lua Adds sort_id field to card serialization and implements sets_equal utility function
src/lua/log.lua Implements logging hook for hand rearrangement detection via CardArea:align_cards
tests/lua/test_api_functions.py Comprehensive test suite covering success scenarios and error conditions
docs/protocol-api.md Updates API documentation with new function details and parameters
docs/developing-bots.md Updates state machine documentation to include rearrange_hand
.github/workflows/release_please.yml Removes pull request trigger from workflow configuration

@S1M0N38
Copy link
Collaborator

S1M0N38 commented Jul 23, 2025

I've solved it! I'm storing the previous card ordering and comparing it with the new order.

There is still a final step: compute the "card" argument (in the API format) from the old order and new order list (feel free to carry on to complete this PR).

I think it's safe to remove set_ranks and align_cards because they are called frequently by the game loop.

@S1M0N38
Copy link
Collaborator

S1M0N38 commented Jul 23, 2025

btw I think we need to test hooks as well. They start to be fairly complex. See #38

@stirby stirby requested a review from Copilot July 23, 2025 22:09
@stirby
Copy link
Collaborator Author

stirby commented Jul 23, 2025

I finished the rearrange index computation:

-- function LOG.hook_hand_rearrange() ...
        if order_changed then
          -- Compute rearrangement to interpret the action
          -- Map every card-id → its position in the old list
          local lookup = {}
          for pos, card_id in ipairs(previous_order) do
            lookup[card_id] = pos - 1 -- zero-based for the API
          end

          -- Walk the new order and translate
          local cards = {}
          for pos, card_id in ipairs(current_order) do
            cards[pos] = lookup[card_id]
          end

          LOG.write("rearrange_hand", { cards = cards })
        end
      end
      ```

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@S1M0N38
Copy link
Collaborator

S1M0N38 commented Jul 24, 2025

I'm not merging yet. I'm still debugging the hook.

@S1M0N38 S1M0N38 self-assigned this Jul 24, 2025
@S1M0N38 S1M0N38 merged commit b7df1f1 into coder:main Jul 25, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: rearrange_hand

2 participants