Skip to content

kirtr/gd-solver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grim Dawn Gear Optimizer

A genetic algorithm solver for finding optimal gear combinations in Grim Dawn. This project models gear optimization as a variation of the knapsack problem, maximizing a "benefit score" based on gear stats across 11 equipment slots with components and augments.

Highlights:

  • Fast convergence - Typically finds optimal solutions in 6-8 seconds
  • Parallel execution - 7-8x speedup on multi-core systems (enabled by default)
  • Massive search space - Efficiently handles combinatorial explosions across gear/component/augment possibilities
  • Lock specific items - Build around items with unique bonuses (+skills, set bonuses)
  • Live progress - Real-time updates every 2 seconds with Ctrl+C support

Usage

# Run with defaults (parallel mode, auto-stop)
python3 solver.py
# Output:
# [2.0s] Best: 2148 pts | Gen 37 | 45k evals/s
# [4.0s] Best: 2159 pts | Gen 80 | 48k evals/s
# [6.0s] Best: 2159 pts | Gen 128 | 51k evals/s
# No improvement after 2s plateau. Terminating search.

# Single-core mode (slower, lower CPU usage)
python3 solver.py --single-core

# Customize time limit (default: unlimited, stops on 2s plateau)
python3 solver.py --time-limit 10

# Verbose output (show generation progress and item counts)
python3 solver.py -v

# Show only gear slots with changes (default shows all gear)
python3 solver.py --swaps-only

# Press Ctrl+C anytime to stop and see best results found so far

How It Works

The Goal

The solver finds the combination of gear that maximizes a "benefit score" by:

  • Selecting one base item for each of 11 gear slots (helm, chest, shoulders, gloves, pants, boots, belt, amulet, medal, ring 1, ring 2)
  • Attaching one component and one augment to each base item (when compatible options exist)
  • Calculating total benefit points based on weighted stat contributions with configurable caps

The Spreadsheet (grim_items.ods)

A spreadsheet contains all available gear, components, and augments with the following structure:

  • Header Row: Defines the stats available from gear (e.g., rFire for Fire Resistance)
  • points_per_unit Row: Specifies the benefit score awarded for each point of a given stat
  • baseline Row: Starting stat values from skills and difficulty (e.g., -50 for resistances)
  • max Row: Defines the cap for benefit scoring, NOT a hard limit on gear stats
    • Example: If rFire has max of 80 and points_per_unit of 2:
      • 30 rFire from gear scores 60 points (30 × 2)
      • 50 rFire from gear scores 80 points (benefit capped at 80)
    • Gear stats can exceed the max value; excess doesn't contribute to score
  • type Column: Specifies the item category (e.g., Helm, Chest, Component, Augment)
  • tf Column: A '1' indicates the gear is currently equipped
  • name Column: Item name (prefix with * to lock, see Locking Gear section)

Components and Augments

The game allows one "Component" and one "Augment" to be attached to each base gear piece:

  • Represented in the spreadsheet with type of "Component" or "Augment"
  • applies_to Column: Specifies which gear types they can attach to (e.g., "Helm,Chest" or "armor" for all armor pieces)
  • The solver creates virtual items combining base + component + augment stats
  • Goal: Find the best combination of all three for every slot

Multiple-Slot Items

Some gear types can be equipped in multiple slots:

  • Rings use separate types (Ring 1 and Ring 2) for two independent slots
  • The same ring cannot be equipped in both slots

Solver Strategy

The solver uses a Multi-Gene Genetic Algorithm as its only optimization method:

Performance:

  • Adaptive termination (runs until plateau), typically 6-8 seconds
  • 100% optimal on current dataset, evaluates millions of combinations per second
  • Island model parallelization enabled by default (7-8x speedup on 16 cores)

Why Genetic Algorithm?

  • The search space is astronomically large: each of 11 gear slots can be filled with (base × component × augment) combinations
  • With typical datasets, total combinations range from billions to trillions, making brute force completely infeasible
  • Multi-gene representation allows evolution of building blocks (base/component/augment) independently
  • Efficiently explores trillion-scale search spaces through intelligent sampling
  • Finds optimal or near-optimal solutions in seconds (typically 6-8s to convergence)
  • Scales well as dataset grows

Key Features:

  • Adaptive termination stops after 2s without improvement (no arbitrary timeout)
  • Live progress updates every 2 seconds (score, generation, eval rate)
  • Ctrl+C support for graceful interruption at any time
  • Multi-gene chromosome: Each slot has 3 independent genes (base item, component, augment)
  • Operators: Tournament selection, multi-gene crossover, granular mutation
  • Scales population by CPU cores for better exploration (150 per core)
  • Island model parallelization (enabled by default, -s for single-core): True multi-core execution with migration
    • 7-8x speedup on 16 cores (16k → 128k comparisons/sec)
    • Ring topology migration every 2 seconds (adaptive to search progress)
    • Each island evolves independently, sharing best solutions periodically

Parameters:

  • Population: 150 per core (auto-calculated based on CPU count)
  • Mutation rate: 15% (applies to each gene independently)
  • Crossover rate: 70% (can mix genes from different parents)
  • Elitism: Top 10% preserved each generation

Features

Locking Gear

Lock specific items to force them into all optimal builds (useful for items with unique bonuses like +skills that aren't captured in stat columns):

  1. Open grim_items.csv (or edit grim_items.ods and reconvert)
  2. Find the item you want to lock
  3. Add a * prefix to its name (e.g., thread of mortality*thread of mortality)
  4. Save and run the solver

Use cases:

  • Items with unique skill bonuses (e.g., +3 to all skills) not in stat columns
  • Set items you want to keep for set bonuses
  • Items you like aesthetically or for specific build requirements
  • Testing "what's the best build around this specific item?"

How it works:

  • Locked items are forced into every individual during population initialization
  • The genetic algorithm never mutates locked slots
  • The solver optimizes everything else around the locked items
  • Components and augments can still be optimized for locked gear pieces
  • The * prefix remains visible in all output displays
  • At startup, the solver displays a message listing all locked items detected

Example output:

Locked items detected (1 items will be forced into all builds):
  amulet: *thread of mortality

AMULET
  Base:       *thread of mortality
  Component:  dread skull
  Augment:    boneback spine → breath of life (rov)

Note: You can lock base items, components, AND augments independently. For example, you could lock a base helm while allowing the solver to optimize its component and augment.

Output Format

The solver displays the optimal gear configuration with:

  • Gear recommendations showing all slots with stats for each item (sorted by benefit value)
  • Full stat comparison table (current vs recommended with benefit points)
  • Execution summary (evaluations, time, benefit improvement)

Example Output:

========================================================================================================================
RECOMMENDED GEAR CONFIGURATION
========================================================================================================================

HELM
  Base:       overseers vitality  rStun(52), aAbsorb(25), hlth(891), da(78)
  Component:  runestone → leathery hide (hs)  rStun(25)
  Augment:    (none) → outcasts warding pow.  rAeth(12)

CHEST
  Base:       shrewd menhirs → impenetrable vitality  rPrc(91), hlth(947), rChs(22)
  Component:  hallowed ground → chains of oleron  oa(60), move(6)
  Augment:    (none) → outcasts warding pow.  rAeth(12)

========================================================================================================================
BASELINE STATS (from skills + difficulty)
========================================================================================================================
rPhys: -50 | rPrc: -50 | rVit: -50 | rAeth: -50 | rChs: -50 | rEle: -50 | rBld: -50 | rStun: -50

========================================================================================================================
STAT COMPARISON
========================================================================================================================
Stat      Wgt      Cur → Opt          Points Sources (optimal)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
dam       0.02     3805 → 3805          76   ring 1(3805)
dAll      0.33      108 → 49            16   gloves(49)
LS        7.00       11 → 13            91   belt(8), comp(5)
hlth      0.05     3940 → 4579         247   chest(947), helm(891), medal(619), gloves(344), boots(372), +2
%hlth     3.22       14 → 32           103   comp(12), boots(5), medal(5), pants(5), ring 2(5)
move      3.00       16 → 35 / 66      105   boots(19), comp(16)
+as%      5.00       15 → 24           120   gloves(17), ring 2(7)
rPhys     3.00       27 → 77 / 105     231   chest(44), amulet(33), ring 1(25), ring 2(21), helm(4)
rPrc      1.00       27 → 84 / 105      84   chest(49), amulet(33), ring 1(25), ring 2(21), comp(6)
rVit      1.00       15 → 27 / 80       27   comp(35), medal(17), aug(15)
rAeth     1.00       -2 → 20 / 80       20   aug(27), amulet(25), shoulders(18)
rChs      1.00       62 → 86 / 80       80   chest(22), ring 1(22), medal(21), ring 2(21)
rBld      1.00       59 → 74 / 80       74   pants(22), medal(20), ring 2(17), comp(15)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
TOTAL:  1501 → 1666 (+165 points, +11.0%)

Gear display format:

  • Shows all gear slots by default (use --swaps-only to show only changes)
  • Each item displays its stats sorted by benefit contribution (highest first)
  • Format: item name stat(value), stat(value), ...
  • Changed items show: old → new stat(value), ...
  • Unchanged items show: name stat(value), ... (for verification)
  • Stats truncate with +N if too many to fit on one line

Stat table column descriptions:

  • Stat: Stat name from CSV header
  • Wgt: Benefit points awarded per unit (shows 2 decimal places)
  • Cur → Opt: Current value → Optimal value / Cap (cap shown only when present)
  • Points: Total benefit points contributed by this stat in optimal build
  • Sources: Items contributing to this stat (with values in parentheses)

Future Work

User Features:

  • Display top-N alternative builds (diversity selection code exists but output not shown to user)
  • Gear culling recommendations (identify items safe to discard based on top solutions)
  • Minimum stat constraints (e.g., "must have at least 80% rAether")

Optimization Ideas:

  • Seed initial population with current gear (guarantees never worse than equipped)
  • Local search / hill climbing post-processing (try all single-item swaps after GA convergence)
  • Smart mutation strategy (prioritize swaps that meet minimum thresholds)
  • Better migration strategy (synchronous barriers, track migration success rate)
  • Adaptive population sizing based on search space size

About

Grim Dawn Gear Solver

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages