Skip to content

Commit 561b824

Browse files
committed
Uniform cost player
1 parent bde115d commit 561b824

File tree

9 files changed

+148
-44
lines changed

9 files changed

+148
-44
lines changed
Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,14 @@
11
package org.teachingextensions.logo;
22

3-
import java.util.*;
3+
import java.util.ArrayDeque;
44

55
/**
66
* A player who solves puzzles using breadth-first search.
77
*/
8-
public class BreadthFirstPlayer {
9-
private final Puzzle puzzle;
10-
private final Set<PuzzleState> visited = new HashSet<>();
11-
private final Queue<PuzzleState> frontier = new ArrayDeque<>();
8+
public class BreadthFirstPlayer extends PuzzlePlayer {
129

1310
public BreadthFirstPlayer(Puzzle puzzle) {
14-
15-
this.puzzle = puzzle;
11+
super(puzzle, new ArrayDeque<PuzzleState>());
1612
}
1713

18-
public PuzzleState solve() {
19-
PuzzleState state = new PuzzleState(this.puzzle);
20-
do {
21-
visited.add(state);
22-
if (!state.isSolution()){
23-
this.search(state);
24-
}
25-
state = frontier.remove();
26-
} while (!state.isSolution());
27-
28-
return state;
29-
}
30-
31-
private void search(PuzzleState state) {
32-
List<PuzzleState> branches = state.getBranches();
33-
for(PuzzleState b : branches){
34-
if (!visited.contains(b)){
35-
frontier.add(b);
36-
}
37-
}
38-
}
3914
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.teachingextensions.logo;
2+
3+
import org.teachingextensions.approvals.lite.Approvals;
4+
5+
/**
6+
* Test a puzzle player
7+
*/
8+
public abstract class PuzzlePlayerTest {
9+
10+
11+
protected void verifySolution() {
12+
int[] cells = {0, 1, 2, 3, 4, 5, 6, 8, 7};
13+
Puzzle p = new Puzzle(cells);
14+
PuzzlePlayer b = getPlayer(p);
15+
PuzzleState s = b.solve();
16+
Approvals.verifyAll("Solve " + p, s.getHistory());
17+
}
18+
19+
protected abstract PuzzlePlayer getPlayer(Puzzle puzzle);
20+
21+
22+
protected void verifyLongSolution() {
23+
int[] cells = {0, 1, 2, 3, 4, 8, 5, 6, 7};
24+
Puzzle p = new Puzzle(cells);
25+
PuzzlePlayer b = getPlayer(p);
26+
27+
PuzzleState s = b.solve();
28+
Approvals.verifyAll("From " + p + " to " + s.getPuzzle(), s.getHistory());
29+
}
30+
}

src/main/java/org/teachingextensions/logo/PuzzleState.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package org.teachingextensions.logo;
22

33
import java.util.ArrayList;
4+
import java.util.Comparator;
45
import java.util.List;
56
import java.util.Stack;
67

78
/**
89
* Represents a node in the puzzle-solving graph. Keeps track of the current puzzle arrangement and the actions
910
* required to arrive at the current arrangement from the starting arrangement.
1011
*/
11-
public class PuzzleState {
12+
public class PuzzleState implements Comparator<PuzzleState> , Comparable<PuzzleState>{
1213
private final Puzzle puzzle;
1314
private final Stack<Direction> history;
1415

@@ -77,6 +78,20 @@ public Puzzle getPuzzle() {
7778
return this.puzzle;
7879
}
7980

81+
public int getActualCost() {
82+
return this.history.size();
83+
}
84+
85+
@Override
86+
public int compare(PuzzleState o1, PuzzleState o2) {
87+
return o1.getActualCost() - o2.getActualCost();
88+
}
89+
90+
@Override
91+
public int compareTo(PuzzleState o) {
92+
return compare(this, o);
93+
}
94+
8095
public enum Direction {
8196
Left(-1), Right(1), Up(-3), Down(3);
8297

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.teachingextensions.logo;
2+
3+
import java.util.PriorityQueue;
4+
5+
/**
6+
* Uniform cost player tries to pick the solution with the least number of steps. The player treats every step as
7+
* if to costs the same as any other step.
8+
*/
9+
public class UniformCostPlayer extends PuzzlePlayer {
10+
public UniformCostPlayer(Puzzle puzzle) {
11+
super(puzzle, new PriorityQueue<PuzzleState>());
12+
}
13+
14+
15+
}
Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
11
package org.teachingextensions.logo;
22

33
import org.junit.Test;
4-
import org.teachingextensions.approvals.lite.Approvals;
54
import org.teachingextensions.approvals.lite.reporters.UseReporter;
65
import org.teachingextensions.approvals.lite.reporters.macosx.BeyondCompareReporter;
76

87
@UseReporter(BeyondCompareReporter.class)
9-
public class BreadthFirstPlayerTest {
8+
public class BreadthFirstPlayerTest extends PuzzlePlayerTest {
9+
10+
@Override
11+
protected PuzzlePlayer getPlayer(Puzzle puzzle) {
12+
return new BreadthFirstPlayer(puzzle);
13+
}
14+
1015
/**
1116
* Produces a puzzle solution
1217
*/
1318
@Test
1419
public void solve_puzzle() throws Exception {
15-
int[] cells = {0, 1, 2, 3, 4, 5, 6, 8, 7};
16-
Puzzle p = new Puzzle(cells);
17-
BreadthFirstPlayer b = new BreadthFirstPlayer(p);
18-
PuzzleState s = b.solve();
19-
Approvals.verifyAll("Solve " + p, s.getHistory());
20+
verifySolution();
2021
}
2122

2223
/**
2324
* Solve longer puzzle
2425
*/
2526
@Test
2627
public void solve_longer_puzzle() throws Exception {
27-
int[] cells = {0, 1, 2, 3, 4, 8, 5, 6, 7};
28-
Puzzle p = new Puzzle(cells);
29-
BreadthFirstPlayer b = new BreadthFirstPlayer(p);
30-
31-
PuzzleState s = b.solve();
32-
Approvals.verifyAll("From " + p + " to " + s.getPuzzle(), s.getHistory());
28+
verifyLongSolution();
3329
}
3430
}

src/test/java/org/teachingextensions/logo/PuzzleStateTest.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import org.teachingextensions.approvals.lite.reporters.UseReporter;
66
import org.teachingextensions.approvals.lite.reporters.macosx.BeyondCompareReporter;
77

8+
import java.util.Stack;
9+
10+
import static org.junit.Assert.assertEquals;
811
import static org.junit.Assert.assertTrue;
912

1013
@UseReporter(BeyondCompareReporter.class)
@@ -60,7 +63,7 @@ public void moves_from_top_right() {
6063
* Or we can see the next moves from the center
6164
*/
6265
@Test
63-
public void moves_from_center(){
66+
public void moves_from_center() {
6467
Puzzle p = getPuzzle(4);
6568
PuzzleState s = new PuzzleState(p);
6669
Approvals.verifyAll("Branches for " + s, s.getBranches());
@@ -70,8 +73,29 @@ public void moves_from_center(){
7073
* Finally, lets see what moves we can do from top center.
7174
*/
7275
@Test
73-
public void moves_from_top_center(){
76+
public void moves_from_top_center() {
7477
PuzzleState s = new PuzzleState(getPuzzle(1));
7578
Approvals.verifyAll("Branches for " + s, s.getBranches());
7679
}
80+
81+
/**
82+
* The actual cost is zero when there is no history
83+
*/
84+
@Test
85+
public void actual_cost() {
86+
PuzzleState s = new PuzzleState(getSolvedPuzzle());
87+
assertEquals(0, s.getActualCost());
88+
}
89+
90+
/**
91+
* The actual cost is the number of steps in the the history
92+
*/
93+
@Test
94+
public void actual_cost_is_actual_steps() {
95+
Stack<PuzzleState.Direction> history = new Stack<>();
96+
history.add(PuzzleState.Direction.Right);
97+
history.add(PuzzleState.Direction.Right);
98+
PuzzleState s = new PuzzleState(getSolvedPuzzle(), history);
99+
assertEquals(2, s.getActualCost());
100+
}
77101
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.teachingextensions.logo;
2+
3+
import org.junit.Test;
4+
import org.teachingextensions.approvals.lite.reporters.UseReporter;
5+
import org.teachingextensions.approvals.lite.reporters.macosx.BeyondCompareReporter;
6+
7+
@UseReporter(BeyondCompareReporter.class)
8+
public class UniformCostPlayerTest extends PuzzlePlayerTest {
9+
@Override
10+
protected PuzzlePlayer getPlayer(Puzzle puzzle) {
11+
return new UniformCostPlayer(puzzle);
12+
}
13+
14+
/**
15+
* Produces a puzzle solution
16+
*/
17+
@Test
18+
public void solve_puzzle() throws Exception {
19+
verifySolution();
20+
}
21+
22+
/**
23+
* Solve longer puzzle
24+
*/
25+
@Test
26+
public void solve_longer_puzzle() throws Exception {
27+
verifyLongSolution();
28+
}
29+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
From [0, 1, 2, 3, 4, 8, 5, 6, 7] to [0, 1, 2, 3, 4, 5, 6, 7, 8]
2+
3+
4+
{Down = 3}
5+
{Left = -1}
6+
{Left = -1}
7+
{Up = -3}
8+
{Right = 1}
9+
{Down = 3}
10+
{Right = 1}
11+
{Up = -3}
12+
{Left = -1}
13+
{Left = -1}
14+
{Down = 3}
15+
{Right = 1}
16+
{Right = 1}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Solve [0, 1, 2, 3, 4, 5, 6, 8, 7]
2+
3+
4+
{Right = 1}

0 commit comments

Comments
 (0)