Bug fixes: - Remove "TEMPORARY FIX" that stopped search after finding first suit - Add armor level as lowest-priority tiebreaker in scoring Scoring formula now: - Set completion: +1000 per complete set - Missing pieces: -200 penalty each - Crit damage: +10/20 per item - Damage rating (clothes): +10/20/30 - Spell coverage: +100 per fulfilled spell - Base item score: +5 per item - Armor level: +1 per 100 AL (tiebreaker) Updated design doc with audit findings - most features were already working correctly. The magsuitalgo.md analysis was outdated. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.5 KiB
Suitbuilder Design Document
Date: 2026-01-30
Status: In Progress
Reference: magsuitalgo.md (detailed MagSuitBuilder algorithm analysis)
Section 1: Problem Statement & Goals
What is Suitbuilder?
Suitbuilder helps players find the best equipment combination from their inventory across multiple "mule" characters. In Asheron's Call, players have many characters storing thousands of armor pieces, jewelry, and accessories. Finding the optimal combination manually is impractical.
Why is this hard?
The naive approach would check every possible combination: if you have 50 items per slot across 17 equipment slots, that's 50^17 combinations - more than atoms in the universe. MagSuitBuilder solved this with smart algorithms, and we're replicating that approach.
Main Goal - Priority Order
Given user constraints, find equipment combinations that:
- Complete armor set bonuses (5 pieces primary set + 4 pieces secondary set) - HIGHEST PRIORITY
- Cover all required spells/cantrips without duplicates
- Maximize armor protection - LOWEST PRIORITY (tiebreaker)
Why we're doing this
The original MagSuitBuilder is a Windows desktop app. We want this functionality in our web-based Dereth Tracker so players can search their inventories from any browser.
Section 2: Algorithm Overview
The Bucket Approach
Instead of checking all item combinations, we organize items into "buckets" by equipment slot (Head, Chest, Hands, etc.). Then we search through buckets one at a time using recursion with backtracking.
How it works
- Create buckets - One bucket per equipment slot (11 armor slots + jewelry slots)
- Sort buckets - Process smallest buckets first (fewer branches to explore)
- Recursive search - Try each item in bucket 1, then recurse to bucket 2, etc.
- Backtrack - When a branch fails constraints, undo and try next item
- Skip allowed - Can skip a slot entirely (incomplete suit better than constraint violation)
Why this is fast
- Bucket with 20 items × bucket with 15 items × bucket with 10 items = 3,000 combinations
- vs. checking every item against every other item = millions of combinations
Two-Phase Search (from MagSuitBuilder)
- Phase 1 - ArmorSearcher: Find optimal armor combinations (enforces set constraints)
- Phase 2 - AccessorySearcher: Add jewelry to complete spell coverage
Key Data Structures
- Spell Bitmap: 32-bit integer where each bit = one spell. Overlap detection is instant via bitwise OR
- Coverage Mask: Tracks which body areas are covered to prevent conflicts
- Set Counter: Tracks pieces per armor set (max 5 primary, 4 secondary)
Section 3: Current Implementation State
Updated after Task 1 Audit (2026-01-30)
What's Working ✅
| Feature | Location | Status |
|---|---|---|
| Bucket creation (all 17 slots) | Lines 1006-1135 | ✅ Working |
| Bucket sorting (armor first, smallest first) | Lines 1127-1130 | ✅ Working |
| ItemPreFilter (surpassing logic) | Lines 503-583, used at 969 | ✅ Working |
| Item sorting (by spell count/ratings) | Lines 971-991 | ✅ Working |
| Spell bitmap system | SpellBitmapIndex class | ✅ Working |
| Set constraints (5+4 logic) | can_add_item() | ✅ Working |
| Coverage mask with reductions | Lines 1137-1240 | ✅ Working |
| API Endpoints | /search, /characters, /sets |
✅ Working |
| Streaming Results (SSE) | recursive_search() | ✅ Working |
| Frontend | suitbuilder.html, suitbuilder.js |
✅ Working |
What's Broken ❌
| Bug | Location | Issue |
|---|---|---|
| Early termination | Lines 1326-1329 | "TEMPORARY FIX" stops after finding 1 suit |
| Armor level not scored | _calculate_score() |
Not included as tiebreaker |
Current Scoring Formula
score = set_completion_bonus (1000 per complete set)
+ set_missing_penalty (-200 per missing piece)
+ crit_damage (10-20 per item)
+ damage_rating on clothes (10-30)
+ spell_coverage (100 per fulfilled spell)
+ base_item_score (5 per item)
MISSING: + armor_level as lowest-priority tiebreaker
Code Structure
suitbuilder.py: 1,847 lines- Main solver class (
ConstraintSatisfactionSolver): ~1,130 lines
Note: magsuitalgo.md Analysis Was Outdated
The analysis document incorrectly stated:
- ❌ "Only creates 2 buckets" → Actually creates all 17
- ❌ "No item pre-filtering" → ItemPreFilter exists and is used
- ❌ "No item sorting" → Items are sorted by spell count/ratings
The code is in much better shape than documented. Only 2 bugs need fixing.
Section 4: Implementation Plan
Updated after audit - most tasks already done!
Task 1: Audit & Document Current Search Flow ✅ COMPLETE
Findings:
- Bucket creation: ✅ All 17 slots created correctly
- Pre-filtering: ✅ ItemPreFilter.remove_surpassed_items() used at line 969
- Sorting: ✅ Items sorted by spell count (armor/jewelry) and damage rating (clothes)
- Set constraints: ✅ 5+4 logic in can_add_item()
Bugs Found:
- Early termination at lines 1326-1329 ("TEMPORARY FIX")
- Armor level missing from scoring
Task 2: Fix Bucket Creation ✅ ALREADY WORKING
No changes needed - all 17 slots are created at lines 1006-1135.
Task 3: Fix Search Completion ✅ COMPLETE
Goal: Remove early termination so search finds multiple suits
The Bug (was at lines 1326-1329):
# TEMPORARY FIX: Stop search after finding first suit to test completion
if len(self.best_suits) >= 1:
logger.info(f"[DEBUG] EARLY TERMINATION...")
return
Fix Applied: Removed this block entirely.
Task 4: Add Item Sorting ✅ ALREADY WORKING
No changes needed - items sorted at lines 971-991.
Task 5: Add Armor Level to Scoring ✅ COMPLETE
Goal: Add armor_level as lowest-priority tiebreaker
Location: _calculate_score() method
Fix Applied: Added armor level scoring after base item score:
# 6. Armor level as tiebreaker (LOWEST PRIORITY)
# Scale down significantly so it only matters when other scores are equal
armor_score = state.total_armor // 100 # ~5 points per 500 AL
score += armor_score
Task 6: Add Item Pre-Filtering ✅ ALREADY WORKING
No changes needed - ItemPreFilter used at line 969.
Task 7: Add AccessorySearcher Phase (Future)
Goal: After armor search, optimize jewelry slots
Scope: Separate task, do after core search is verified working
How to Use This Document
For Claude (AI assistant):
- Read this document at the start of each session
- Work on ONE task at a time
- Verify before moving to next task
- If confused, re-read the relevant section
- Do NOT make changes outside the current task scope
For the developer:
- Update "Status" at top when tasks complete
- Add notes under each task as we learn things
- Reference
magsuitalgo.mdfor detailed algorithm explanations
Progress Tracking
| Task | Status | Notes |
|---|---|---|
| Task 1: Audit Current Flow | ✅ Complete | Found 2 bugs, most features working |
| Task 2: Fix Bucket Creation | ✅ Already Working | No changes needed |
| Task 3: Fix Search Completion | ✅ Complete | Removed early termination at lines 1326-1329 |
| Task 4: Add Item Sorting | ✅ Already Working | No changes needed |
| Task 5: Add Armor Level Scoring | ✅ Complete | Added armor_score = total_armor // 100 |
| Task 6: Add Item Pre-Filtering | ✅ Already Working | No changes needed |
| Task 7: AccessorySearcher | Not Started | Future |