Skip to content

Commit 541d403

Browse files
using a stack :)
1 parent 6a737e5 commit 541d403

File tree

9 files changed

+137
-142
lines changed

9 files changed

+137
-142
lines changed

gradle/wrapper/gradle-wrapper.jar

-628 Bytes
Binary file not shown.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Mon Nov 14 19:33:06 CET 2016
1+
#Wed Nov 30 22:32:28 CET 2016
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip

gradlew

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,9 @@ function splitJvmOpts() {
161161
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162162
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163163

164+
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
165+
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
166+
cd "$(dirname "$0")"
167+
fi
168+
164169
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

gradlew.bat

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ goto fail
4949
@rem Get command-line arguments, handling Windows variants
5050

5151
if not "%OS%" == "Windows_NT" goto win9xME_args
52-
if "%@eval[2+2]" == "4" goto 4NT_args
5352

5453
:win9xME_args
5554
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
6059
if "x%~1" == "x" goto execute
6160

6261
set CMD_LINE_ARGS=%*
63-
goto execute
64-
65-
:4NT_args
66-
@rem Get arguments from the 4NT Shell from JP Software
67-
set CMD_LINE_ARGS=%$
6862

6963
:execute
7064
@rem Setup the command line
Lines changed: 44 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,79 @@
11
package ch.sebastianhaeni.pancake;
22

3-
import java.util.Arrays;
4-
import java.util.List;
5-
63
import ch.sebastianhaeni.pancake.dto.Node;
7-
import ch.sebastianhaeni.pancake.dto.SearchResult;
4+
5+
import java.util.Arrays;
6+
import java.util.Stack;
87

98
public class RecursiveSolver {
109

10+
private static Stack<Node> stack = new Stack<>();
11+
private static int candidateBound = Integer.MAX_VALUE;
12+
1113
private RecursiveSolver() {
1214
}
1315

1416
public static void main(String[] args) {
1517

16-
// Node root = new Node(new int[]{46, 53, 18, 4, 56, 11, 57, 59, 55, 25, 6, 34, 41, 13, 39, 52, 7, 33, 43, 21, 32, 51, 5, 1, 58, 49, 54, 9, 24, 17, 19, 27, 50, 42, 22, 30, 20, 3, 14, 28, 40, 10, 12, 29, 37, 8, 36, 2, 26, 38, 16, 60, 15, 48, 35, 45, 31, 44, 23, 47});
18+
Node root = new Node(new int[]{46, 53, 18, 4, 56, 11, 57, 59, 55, 25, 6, 34, 41, 13, 39, 52, 7, 33, 43, 21, 32, 51, 5, 1, 58, 49, 54, 9, 24, 17, 19, 27, 50, 42, 22, 30, 20, 3, 14, 28, 40, 10, 12, 29, 37, 8, 36, 2, 26, 38, 16, 60, 15, 48, 35, 45, 31, 44, 23, 47});
1719
// Node root = new Node(new int[]{2, 6, 10, 5, 1, 3, 8, 4, 7, 9});
1820
// Node root = new Node(new int[]{3, 1, 2});
1921
// Node root = new Node(new int[]{11, 7, 15, 6, 17, 3, 19, 16, 4, 10, 8, 12, 20, 14, 2, 5, 1, 9, 13, 18});
2022
// Node root = new Node(new int[]{5, 2, 7, 10, 13, 16, 14, 6, 8, 18, 15, 11, 1, 12, 3, 4, 9, 17});
21-
Node root = new Node(new int[] { 4, 25, 15, 7, 28, 17, 6, 5, 23, 29, 19, 27, 13, 21, 9, 1, 26, 22, 11, 18, 16, 12, 10, 30, 2, 3, 8, 14, 24, 20 });
23+
// Node root = new Node(new int[] { 4, 25, 15, 7, 28, 17, 6, 5, 23, 29, 19, 27, 13, 21, 9, 1, 26, 22, 11, 18, 16, 12, 10, 30, 2, 3, 8, 14, 24, 20 });
24+
// Node root = new Node(new int[]{2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11});
2225

2326
System.out.format("Solving a pancake pile of height %d.\n", root.getState().length);
2427

2528
long start = System.currentTimeMillis();
26-
Node solution = solve(root);
29+
solve(root);
2730
long end = System.currentTimeMillis();
2831

29-
System.out.format("%dms passed\n", (end - start));
32+
showSolution(start, end);
33+
}
3034

31-
if (solution == null) {
32-
System.out.println("No solution found");
33-
return;
34-
}
35-
System.out.format("Found solution after %d flips.\n", solution.getDepth());
35+
private static void showSolution(long start, long end) {
36+
System.out.format("%dms passed\n", (end - start));
37+
System.out.format("Found solution after %d flips.\n", stack.size());
3638

3739
StringBuilder sb = new StringBuilder();
38-
Node current = solution;
39-
while (current.getParent() != null) {
40-
sb.insert(0, Arrays.toString(current.getParent().getState()) + '\n');
41-
current = current.getParent();
40+
41+
while (!stack.isEmpty()) {
42+
sb.insert(0, Arrays.toString(stack.pop().getState()) + '\n');
4243
}
4344

4445
System.out.println(sb.toString());
4546
}
4647

47-
private static Node solve(Node root) {
48-
if (root.isSolution()) {
49-
return root;
50-
}
51-
52-
Node solutionNode = null;
53-
int bound = root.getOptimisticDistanceToSolution();
54-
int maxBound = bound * 10;
55-
56-
while (solutionNode == null) {
57-
System.out.println("Searching with bound " + bound);
58-
SearchResult result = search(root, bound);
59-
60-
if (result.getSolutionNode() != null) {
61-
solutionNode = result.getSolutionNode();
62-
}
63-
64-
if (result.getBound() >= maxBound) {
65-
return null;
48+
private static void solve(Node root) {
49+
root = root.augment();
50+
stack.push(root);
51+
stack.peek().calcDistance();
52+
stack.peek().nextNodes();
53+
int bound = root.getDistance();
54+
55+
int stateBound;
56+
57+
while (stack.peek().getDistance() != 0) {
58+
if (stack.peek().getDistance() + stack.peek().getDepth() > bound) {
59+
stateBound = stack.peek().getDepth() + stack.peek().getDistance();
60+
candidateBound = stateBound < candidateBound ? stateBound : candidateBound;
61+
stack.pop();
62+
} else if (stack.peek().getChildren().empty()) {
63+
if (stack.peek().getDepth() == 0) {
64+
bound = candidateBound;
65+
System.out.println("Searching with bound " + candidateBound);
66+
candidateBound = Integer.MAX_VALUE;
67+
stack.peek().nextNodes();
68+
} else {
69+
stack.pop();
70+
}
71+
} else {
72+
stack.push(stack.peek().getChildren().pop());
73+
stack.peek().nextNodes();
6674
}
67-
68-
bound = result.getBound();
6975
}
70-
71-
return solutionNode;
7276
}
7377

74-
private static SearchResult search(Node node, int bound) {
75-
int newBound = node.getDepth() + node.getOptimisticDistanceToSolution();
76-
77-
if (newBound > bound) {
78-
return new SearchResult(newBound);
79-
}
80-
81-
if (node.isSolution()) {
82-
return new SearchResult(node);
83-
}
84-
85-
int min = Integer.MAX_VALUE;
86-
List<Node> successors = node.nextNodes();
87-
88-
for (Node successor : successors) {
89-
SearchResult result = search(successor, bound);
90-
91-
if (result.getSolutionNode() != null) {
92-
return result;
93-
}
94-
95-
if (result.getBound() < min) {
96-
min = result.getBound();
97-
}
98-
}
99-
100-
return new SearchResult(min);
101-
}
10278

10379
}
Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package ch.sebastianhaeni.pancake.dto;
22

33
import java.io.Serializable;
4-
import java.util.AbstractList;
5-
import java.util.ArrayList;
6-
import java.util.List;
4+
import java.util.Stack;
75

86
/**
97
* A node in a search tree.
@@ -25,80 +23,90 @@ public class Node implements Serializable {
2523
* The parent node. This is only used to figure out the solution path after the solution has been found.
2624
*/
2725
private final Node parent;
26+
27+
/**
28+
* Position this node's parent was flipped at.
29+
*/
2830
private final int flipPosition;
2931

32+
private Stack<Node> children = new Stack<>();
33+
34+
/**
35+
* Pancake pile size.
36+
*/
37+
private final int size;
38+
private int distance;
39+
3040
public Node(int[] state) {
31-
this(state, 0, null, -1);
41+
this(state, 0, null, -1, 0);
3242
}
3343

34-
private Node(int[] state, int depth, Node parent, int flipPosition) {
44+
private Node(int[] state, int depth, Node parent, int flipPosition,int distance) {
3545
this.state = state;
3646
this.depth = depth;
3747
this.parent = parent;
3848
this.flipPosition = flipPosition;
49+
this.size = state.length;
50+
this.distance=distance;
3951
}
4052

41-
public int getOptimisticDistanceToSolution() {
42-
int distance = 0;
43-
int current = 1;
53+
public void calcDistance() {
54+
distance = 0;
4455

45-
for (int i = 1; i < state.length; i++) {
46-
int pancake = state[i];
47-
if (Math.abs(pancake - current) != 1) {
56+
for (int i = 0; i < size - 1; i++) {
57+
if (Math.abs(state[i] - state[i + 1]) > 1) {
4858
distance++;
4959
}
50-
current = pancake;
5160
}
52-
53-
// 1.07 from https://en.wikipedia.org/wiki/Pancake_sorting
54-
return (int) (distance * 1.07);
5561
}
5662

5763
public boolean isSolution() {
58-
int current = 1;
59-
60-
for (int i = 1; i < state.length; i++) {
61-
int pancake = state[i];
62-
if (pancake - current != 1) {
64+
for (int i = 0; i < size - 1; i++) {
65+
if (state[i] != state[i + 1] - 1) {
6366
return false;
6467
}
65-
current = pancake;
6668
}
6769

6870
return true;
6971
}
7072

71-
public List<Node> nextNodes() {
72-
AbstractList<Node> list = new ArrayList<>();
73-
74-
for (int i = 1; i < state.length; i++) {
75-
int flipPosition = i + 1;
76-
if (flipPosition != this.flipPosition) {
77-
Node flip = flip(flipPosition);
78-
list.add(flip);
73+
public void nextNodes() {
74+
for (int i = 2; i < size; i++) {
75+
if (Math.abs(state[i - 1] - state[i]) > 1) {
76+
if (Math.abs(state[i] - state[0]) > 1) {
77+
children.push(flip(i, distance));
78+
} else {
79+
children.push(flip(i, distance - 1));
80+
}
7981
}
8082
}
81-
82-
return list;
8383
}
8484

8585
/**
8686
* Flips the prefix at the defined flip position.
8787
*
8888
* @param flipPosition the position where the state shall be reversed
89+
* @param distance predetermined optimistic distance
8990
* @return prefix reversed state
9091
*/
91-
Node flip(int flipPosition) {
92+
Node flip(int flipPosition, int distance) {
9293

93-
int[] flipped = new int[state.length];
94+
int[] flipped = new int[size];
9495

9596
for (int i = 0; i < flipPosition; i++) {
9697
flipped[i] = state[flipPosition - i - 1];
9798
}
9899

99-
System.arraycopy(state, flipPosition, flipped, flipPosition, state.length - flipPosition);
100+
System.arraycopy(state, flipPosition, flipped, flipPosition, size - flipPosition);
101+
102+
return new Node(flipped, getDepth() + 1, this, flipPosition, distance);
103+
}
100104

101-
return new Node(flipped, getDepth() + 1, this, flipPosition);
105+
public Node augment() {
106+
int[] augmentedState = new int[size + 1];
107+
System.arraycopy(state, 0, augmentedState, 0, size);
108+
augmentedState[size] = size + 1;
109+
return new Node(augmentedState);
102110
}
103111

104112
public int getDepth() {
@@ -116,4 +124,12 @@ public Node getParent() {
116124
public int getFlipPosition() {
117125
return flipPosition;
118126
}
127+
128+
public int getDistance() {
129+
return distance;
130+
}
131+
132+
public Stack<Node> getChildren() {
133+
return children;
134+
}
119135
}

src/main/java/ch/sebastianhaeni/pancake/processor/Controller.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private Node solve(Node root) throws InterruptedException {
138138
}
139139

140140
Node solutionNode = null;
141-
int bound = root.getOptimisticDistanceToSolution();
141+
int bound = root.getDistance();
142142
int maxBound = bound * 2;
143143

144144
while (solutionNode == null) {
@@ -165,7 +165,7 @@ private Node solve(Node root) throws InterruptedException {
165165
}
166166

167167
private SearchResult search(Node node, int bound) throws InterruptedException {
168-
int newBound = node.getDepth() + node.getOptimisticDistanceToSolution();
168+
int newBound = node.getDepth() + node.getDistance();
169169

170170
if (newBound > bound) {
171171
return new SearchResult(newBound);
@@ -175,11 +175,11 @@ private SearchResult search(Node node, int bound) throws InterruptedException {
175175
return new SearchResult(node);
176176
}
177177

178-
List<Node> successors = node.nextNodes();
179-
180-
outstandingWork.addAll(successors.stream()
181-
.map(successor -> new WorkPacket(successor, bound))
182-
.collect(Collectors.toList()));
178+
// List<Node> successors = node.nextNodes();
179+
//
180+
// outstandingWork.addAll(successors.stream()
181+
// .map(successor -> new WorkPacket(successor, bound))
182+
// .collect(Collectors.toList()));
183183

184184
if (!distributor.isStarted()) {
185185
distributor.start();

src/main/java/ch/sebastianhaeni/pancake/processor/Worker.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ch.sebastianhaeni.pancake.processor;
22

33
import java.text.DecimalFormat;
4+
import java.util.ArrayList;
45
import java.util.List;
56

67
import org.apache.logging.log4j.LogManager;
@@ -91,7 +92,7 @@ private void listenToSplitCommand() {
9192

9293
private SearchResult compute(Node node, int bound) {
9394
computeCount++;
94-
int newBound = node.getDepth() + node.getOptimisticDistanceToSolution();
95+
int newBound = node.getDepth() + node.getDistance();
9596

9697
if (newBound > bound) {
9798
return new SearchResult(newBound);
@@ -101,7 +102,8 @@ private SearchResult compute(Node node, int bound) {
101102
return new SearchResult(node);
102103
}
103104

104-
List<Node> successors = node.nextNodes();
105+
// List<Node> successors = node.nextNodes();
106+
List<Node> successors = new ArrayList<>();
105107

106108
if (splitCommand != null && splitCommand.Test() != null) {
107109
listenToSplitCommand();

0 commit comments

Comments
 (0)