Pathfinding and Path Costs
Overviewโ
Brobot uses a cost-based pathfinding system to navigate between states. When multiple paths exist between two states, Brobot automatically selects the path with the lowest total cost. Understanding how path costs work is essential for building efficient and predictable automation.
Default Path Costsโ
As of version 1.1.0, Brobot uses the following defaults:
| Component | Default Cost | Description |
|---|---|---|
| State | 1 | Cost of being in a state |
| Transition | 1 | Cost of executing a transition |
Why Default to 1?โ
The default of 1 (instead of 0) makes cost calculations more intuitive:
- Every state visit and transition has a base cost
- The total cost naturally represents the complexity of a path
- You can explicitly set 0 for "free" states or transitions
- Higher values (5, 10, 20+) clearly indicate expensive operations
How Path Costs Are Calculatedโ
The total cost of a path is the sum of:
- All state costs in the path
- All transition costs in the path
Formulaโ
Total Path Cost = ฮฃ(State Costs) + ฮฃ(Transition Costs)
Example Calculationโ
Consider navigating from LoginPage to UserDashboard:
Path 1: Direct Route
LoginPage (cost: 1)
โ [transition: login] (cost: 1)
Dashboard (cost: 1)
Total = 1 + 1 + 1 = 3
Path 2: Through Welcome Screen
LoginPage (cost: 1)
โ [transition: login] (cost: 1)
WelcomeScreen (cost: 1)
โ [transition: continue] (cost: 2)
Dashboard (cost: 1)
Total = 1 + 1 + 1 + 2 + 1 = 6
Result: Path 1 is chosen (cost: 3 < 6)
Setting Custom Path Costsโ
State Path Costsโ
Set in the @State annotation:
Example (Conceptual Snippets):
import io.github.jspinak.brobot.annotations.State;
@State // Default pathCost = 1
public class NormalPage {
// Standard page with default cost
}
@State(pathCost = 0) // Free state
public class SplashScreen {
// No cost to be in this state (e.g., automatic/transient states)
}
@State(pathCost = 5) // Expensive state
public class SlowLoadingPage {
// Higher cost discourages routing through this state
}
@State(pathCost = 10) // Very expensive
public class ErrorRecoveryState {
// High cost - only use as last resort
}
Transition Path Costsโ
Set in the @OutgoingTransition annotation:
Example (Conceptual Snippet):
import io.github.jspinak.brobot.action.Action;
import io.github.jspinak.brobot.annotations.OutgoingTransition;
import io.github.jspinak.brobot.annotations.TransitionSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@TransitionSet(state = HomePage.class)
@Component
public class HomePageTransitions {
@Autowired
private Action action;
@Autowired
private HomePage homePage; // Contains profileLink, menuButton, etc.
@OutgoingTransition(activate = {ProfilePage.class}) // Default pathCost = 1
public boolean toProfile() {
// Normal transition with default cost
return action.click(homePage.getProfileLink()).isSuccess();
}
@OutgoingTransition(
activate = {ProfilePage.class},
pathCost = 0 // Free transition
)
public boolean quickProfile() {
// Keyboard shortcut - no cost
return action.type("{CTRL+P}").isSuccess();
}
@OutgoingTransition(
activate = {ProfilePage.class},
pathCost = 10 // Expensive fallback
)
public boolean toProfileViaMenu() {
// Slower route through menu - discouraged
action.click(homePage.getMenuButton());
action.click(homePage.getProfileMenuItem());
return true;
}
}
Path Selection Algorithmโ
Brobot's pathfinding follows these rules:
- Find all possible paths from current state(s) to target state
- Calculate total cost for each path
- Sort paths by total cost (ascending order)
- Select and execute the lowest cost path
- If the selected path fails, try the next lowest cost path
Path Selection Exampleโ
Consider multiple routes from HomePage to SettingsPage:
// Path A: Direct navigation
HomePage (1) โ [click settings] (1) โ SettingsPage (1)
Total: 3
// Path B: Through menu
HomePage (1) โ [open menu] (2) โ Menu (1) โ [click settings] (1) โ SettingsPage (1)
Total: 6
// Path C: Keyboard shortcut
HomePage (1) โ [press Alt+S] (0) โ SettingsPage (1)
Total: 2
Winner: Path C (cost: 2) - The keyboard shortcut wins due to its 0-cost transition
Common Path Cost Patternsโ
1. Preferred vs Fallback Routesโ
Example (Conceptual Snippet):
import io.github.jspinak.brobot.action.Action;
import io.github.jspinak.brobot.annotations.OutgoingTransition;
import io.github.jspinak.brobot.annotations.TransitionSet;
import org.springframework.beans.factory.annotation.Autowired;
@TransitionSet(state = SearchPage.class)
public class SearchTransitions {
@Autowired
private Action action;
@Autowired
private SearchPage searchPage; // Contains searchButton, advancedButton
@OutgoingTransition(
activate = {ResultsPage.class},
pathCost = 1 // Preferred: direct search
)
public boolean search() {
return action.click(searchPage.getSearchButton()).isSuccess();
}
@OutgoingTransition(
activate = {ResultsPage.class},
pathCost = 10 // Fallback: advanced search
)
public boolean advancedSearch() {
action.click(searchPage.getAdvancedButton());
// ... more complex steps
return action.click(searchPage.getSearchButton()).isSuccess();
}
}
2. Free Transitions for Instant Operationsโ
Example (Conceptual Snippet):
import io.github.jspinak.brobot.action.Action;
import io.github.jspinak.brobot.annotations.OutgoingTransition;
import io.github.jspinak.brobot.model.state.special.CurrentState;
import io.github.jspinak.brobot.model.state.special.PreviousState;
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
private Action action;
@OutgoingTransition(
activate = {CurrentState.class},
pathCost = 0 // Free - no actual navigation
)
public boolean refresh() {
// Instant operation, no cost
return action.type("{F5}").isSuccess();
}
@OutgoingTransition(
activate = {PreviousState.class},
pathCost = 0 // Free - closing overlay
)
public boolean closeModal() {
// Modal closes instantly, no navigation cost
return action.type("{ESC}").isSuccess();
}
3. Expensive States to Avoidโ
Example (Conceptual Snippet):
import io.github.jspinak.brobot.annotations.State;
@State(pathCost = 20) // Very expensive
public class MaintenancePage {
// High cost prevents routing through this state
// Only accessed when explicitly targeted
}
@State(pathCost = 100) // Prohibitive cost
public class CrashRecoveryState {
// Emergency state - never route through
// Only used for error recovery
}
4. Progressive Cost Increase for Retriesโ
Example (Conceptual Snippet):
import io.github.jspinak.brobot.annotations.OutgoingTransition;
import io.github.jspinak.brobot.annotations.TransitionSet;
@TransitionSet(state = LoginPage.class)
public class LoginTransitions {
@OutgoingTransition(activate = {Dashboard.class}, pathCost = 1)
public boolean normalLogin() {
// First attempt - lowest cost
return performLogin(); // Your implementation
}
@OutgoingTransition(activate = {Dashboard.class}, pathCost = 5)
public boolean retryLogin() {
// Second attempt - higher cost
clearFields(); // Your implementation
return performLogin();
}
@OutgoingTransition(activate = {Dashboard.class}, pathCost = 20)
public boolean recoveryLogin() {
// Last resort - highest cost
refreshPage(); // Your implementation
clearCookies();
return performLogin();
}
}
Cost Guidelinesโ
Recommended Cost Rangesโ
| Cost | Use Case | Example |
|---|---|---|
| 0 | Free/instant operations | Keyboard shortcuts, closing overlays, already visible elements |
| 1 | Standard operations (default) | Normal clicks, typical navigation |
| 2-4 | Slightly slower operations | Operations with animations, short waits |
| 5-9 | Noticeably slower operations | Multi-step processes, operations with loading |
| 10-19 | Fallback routes | Alternative paths when primary fails |
| 20-49 | Recovery operations | Error recovery, cleanup paths |
| 50-99 | Last resort operations | Major recovery, restart sequences |
| 100+ | Prohibitive | States/transitions to avoid unless explicitly required |
Best Practicesโ
-
Keep default costs for normal operations - Most states and transitions should use the default cost of 1
-
Use 0 for truly free operations - Only when there's no time cost or complexity:
- Keyboard shortcuts that instantly navigate
- Closing overlays with ESC
- States that are transient/automatic
-
Reserve high costs for fallbacks - Use 10+ for alternative routes that should only be used when necessary
-
Be consistent across your application - Similar operations should have similar costs
-
Consider total path cost - Remember that costs accumulate across the entire path
Debugging Path Selectionโ
To understand why Brobot chose a particular path:
Enable Path Loggingโ
Brobot uses standard SLF4J logging. Enable DEBUG level for pathfinding classes:
Option 1: application.properties
# application.properties
logging.level.io.github.jspinak.brobot.navigation.path=DEBUG
Option 2: logback.xml
<logger name="io.github.jspinak.brobot.navigation.path" level="DEBUG"/>
Sample Debug Outputโ
INFO - Finding path from [HomePage] to SettingsPage
INFO - Found 3 path(s) from [HomePage] to SettingsPage
INFO - Paths found (3)
DEBUG - Path 1: HomePage -> Menu -> SettingsPage (cost: 6)
DEBUG - Path 2: HomePage -> SettingsPage (cost: 3)
DEBUG - Path 3: HomePage -> SettingsPage (cost: 2, via keyboard shortcut)
INFO - Best path (score 2): HomePage -> SettingsPage
Advanced Scenariosโ
Dynamic Cost Adjustmentโ
While Brobot doesn't support runtime cost changes, you can achieve similar effects with multiple transitions:
Example (Conceptual Snippet):
import io.github.jspinak.brobot.annotations.OutgoingTransition;
import io.github.jspinak.brobot.annotations.TransitionSet;
import org.springframework.beans.factory.annotation.Autowired;
@TransitionSet(state = DataPage.class)
public class DataPageTransitions {
@Autowired
private SystemLoad systemLoad; // Your custom service
@OutgoingTransition(activate = {ReportPage.class}, pathCost = 1)
public boolean fastGenerate() {
if (systemLoad.isHigh()) return false; // Fail if load is high
return generateReport(); // Your implementation
}
@OutgoingTransition(activate = {ReportPage.class}, pathCost = 10)
public boolean slowGenerate() {
// Always works but with higher cost
return generateReport();
}
}
Cost-Based Load Balancingโ
Distribute load across multiple paths:
Example (Conceptual Snippet):
import io.github.jspinak.brobot.annotations.State;
@State(pathCost = 1)
public class Server1Page { }
@State(pathCost = 2) // Slightly discourage
public class Server2Page { }
@State(pathCost = 3) // Further discourage
public class Server3Page { }
// Brobot naturally prefers Server1, falls back to others
Migration Guideโ
If upgrading to version 1.1.0 or later:
Version 1.1.0 Changesโ
New Defaults:
- State pathCost: 1 (unchanged)
- Transition pathCost: 1 (changed from 0 in pre-1.1.0 versions)
Migration Stepsโ
-
Review existing pathCost = 0 transitions - These are now explicitly free (intentional)
-
Check path selection changes - Paths may change due to different default transition costs
-
Update tests - Path selection tests may need updating
-
Explicit costs for critical paths - Add explicit pathCost values where path selection is critical:
// Before (relied on old default 0 for transitions)
@OutgoingTransition(activate = {CriticalState.class})
// After (explicit to ensure it remains free)
@OutgoingTransition(activate = {CriticalState.class}, pathCost = 0)
Summaryโ
The path cost system in Brobot provides fine-grained control over navigation paths:
- Default costs of 1 make calculations intuitive
- Total cost = Sum of state costs + Sum of transition costs
- Lower costs are preferred in pathfinding
- Use 0 for free operations, higher values for expensive ones
- Consistent cost assignment leads to predictable navigation
By understanding and properly configuring path costs, you can ensure your automation takes the most efficient routes through your application's state space.
Related Documentationโ
- States Guide - Understanding states and the @State annotation
- Transitions Guide - Defining transitions between states
- Pathfinding & Multi-State Activation - Introduction to pathfinding concepts
- Annotations Guide - Complete reference for @State, @TransitionSet, and transition annotations
- Dynamic Transitions and Hidden States - Using PreviousState and CurrentState special markers
- Core Concepts - Overview of Brobot's architecture
Example Projectsโ
See path costs in action in these tutorials:
- Tutorial Basics - Basic state and transition setup
- Special States Tutorial - Using CurrentState and PreviousState with path costs