Randy Coulman
March 09, 2015
1.4k

# Solving Ricochet Robots

Ricochet Robots is a puzzle board game for any number of players. While being a very fun game to play with some fascinating properties, it is also interesting to think about writing a program to play the game.

Let’s discuss a computerized player for Ricochet Robots that finds the optimal solution to any board in a reasonable amount of time. Along the way, we’ll learn about graph search techniques, data representation, algorithms, heuristics, pruning, and optimization.

March 09, 2015

## Transcript

1. ### www .codingzeal.com @codingzeal Randy Coulman Solving Ricochet Robots Senior Software

Engineer @randycoulman

get to
10. ### 1 2 3 1. Blue Right 2. Blue Down 3.

Blue Left Moves to get to
11. ### 1 2 3 4 1. Blue Right 2. Blue Down

3. Blue Left 4. Green Right Moves to get to
12. ### 1 2 3 4 5 1. Blue Right 2. Blue

Down 3. Blue Left 4. Green Right 5. Green Down Moves to get to
13. ### 1 2 3 4 5 6 1. Blue Right 2.

Blue Down 3. Blue Left 4. Green Right 5. Green Down 6. Green Left Moves to get to
14. ### 1 2 3 4 5 6 7 1. Blue Right

2. Blue Down 3. Blue Left 4. Green Right 5. Green Down 6. Green Left 7. Green Down Moves to get to
15. ### Characterizing the Problem Possible Board States (size of state space):

252 * 251 * 250 * 249 * 248 = 976,484,376,000
16. ### Characterizing the Problem Branching Factor: 9 - 20 possible moves

from each state

18. ### Representing the Board • Board (Static: 16 x 16) •

Walls & Targets (changes each game)
19. ### Representing the Board • Board (Static: 16 x 16) •

Walls & Targets (changes each game) • Goal (changes each turn)
20. ### Representing the Board • Board (Static: 16 x 16) •

Walls & Targets (changes each game) • Goal (changes each turn) • Robot Positions (changes each move)

Ways Through

9

9 10

9 10 11

9 10 11 12
37. ### Depth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13
38. ### Depth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14
39. ### Depth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14 15
40. ### Depth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14 15 16
41. ### Depth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14 15 16
42. ### Depth-First Search def solve solve_recursively(Path.initial(state)) candidates.min_by(&:length) || Outcome.no_solution(state) end def

solve_recursively(path) return candidates << path.to_outcome if path.solved? path.allowable_successors.each do |successor| solve_recursively(successor) end end

9

9 10

9 10 11

9 10 11 12
75. ### Breadth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13
76. ### Breadth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14
77. ### Breadth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14 15
78. ### Breadth-First Search 1 2 3 4 5 6 7 8

9 10 11 12 13 14 15 16
79. ### Breadth-First Search 1 2 5 3 7 8 4 9

10 11 6 12 13 14 15 16
80. ### Breadth-First Search def solve paths = [Path.initial(initial_state)] until paths.empty? path

= paths.shift return path.to_outcome if path.solved? paths += path.allowable_successors end Outcome.no_solution(initial_state) end

82. ### Optimization Do Less Things: Reduce the size of the state

space by pruning branches from the graph

84. ### Optimization Heuristics: Rules of Thumb Less certain; may work in

some circumstances, but not others
85. ### Heuristic: Move Active Robot First States Considered 0 350000 700000

1050000 1400000 Original Algorithm Active First
86. ### Do Less Things: Check for Solutions at Generation Time def

solve paths = [Path.initial(initial_state)] until paths.empty? path = paths.shift return path.to_outcome if path.solved? paths += path.allowable_successors end Outcome.no_solution(initial_state) end
87. ### Do Less Things: Check for Solutions at Generation Time 1

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
88. ### Do Less Things: Check for Solutions at Generation Time def

solve paths = [Path.initial(initial_state)] until paths.empty? path = paths.shift successors = path.allowable_successors solution = successors.find(&:solved?) return solution.to_outcome if solution paths += successors end Outcome.no_solution(initial_state) end
89. ### Do Less Things: Check for Solutions at Generation Time 1

2 3 4 5 6 X X X X X X X X X 16
90. ### Do Less Things: Check for Solutions at Generation Time 0

800,000 1,600,000 2,400,000 3,200,000 Original Algorithm Check at Generation Total States Considered

92. ### Do Things Faster: Precompute stopping cells States / second 0

675 1350 2025 2700 Original Algorithm Pre-compute Stops
93. ### Do Less Things / Do Things Faster: Treat non-active robots

as equivalent
94. ### Do Less Things / Do Things Faster: Treat non-active robots

as equivalent 0 1,000,000 2,000,000 3,000,000 4,000,000 Original Algorithm Check at Generation Robot Equivalence Total States Considered
95. ### Do Less Things / Do Things Faster: Treat non-active robots

as equivalent States / second 0 750 1500 2250 3000 Original Algorithm Pre-compute Stops Robot Equiv.
96. ### Do Things Faster: Sorted Array vs Set States / second

0 800 1600 2400 3200 Original Algorithm Pre-compute Stops Robot Equiv. Arrays not Sets
97. ### Do Things Faster: Less Object Creation States / second 0

1250 2500 3750 5000 Original Algorithm Pre-compute Stops Robot Equiv. Arrays not Sets Less Objects
98. ### Do Things Faster: Use Object Identity Instead of Deep Equality

States / second 0 1750 3500 5250 7000 Original Algorithm Pre-compute Stops Robot Equiv. Arrays not Sets Less Objects Object Identity
99. ### Final Results Solving time (seconds) 0 750 1500 2250 3000

Original Active First Check at Gen. Pre-compute Robot Equiv. Arrays not Sets Less Objects Robot Identity

102. ### A* Algorithm Next state to expand is one with minimum

distance so far + estimated distance to goal

104. ### A* Algorithm 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 0
105. ### A* Algorithm 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0
106. ### A* Algorithm 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0
107. ### A* Algorithm 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0
108. ### A* Algorithm 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 0

MRU robots

types

118. ### Acknowledgements • Trever Yarrish of Zeal for the awesome graphics

and visualizations • The Zealots of Zeal for ideas, feedback, and pairing on the solver • Michael Fogleman for some optimization ideas • Trevor Lalish-Menagh for introducing me to the game