Puzzle8 fix
- fixed bug causing the solve function to use all the memory and then crash - added new test cases - removed unused counter in AStar
This commit is contained in:
@@ -22,9 +22,6 @@ public class AStar<State, Action> {
|
|||||||
private BiFunction<State, State, Integer> heuristic;
|
private BiFunction<State, State, Integer> heuristic;
|
||||||
private TriFunction<State, State, Action, Integer> cost;
|
private TriFunction<State, State, Action, Integer> cost;
|
||||||
|
|
||||||
private int lastStateVisitedCount = 0;
|
|
||||||
private int lastStateTotalCount = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crea una istanza dell'algoritmo A* con una funzione di azioni possibili da compiere dato uno stato
|
* Crea una istanza dell'algoritmo A* con una funzione di azioni possibili da compiere dato uno stato
|
||||||
* e una funzione di transizione che dato uno stato permette di raggiungerne un'altro tramite un'azione.
|
* e una funzione di transizione che dato uno stato permette di raggiungerne un'altro tramite un'azione.
|
||||||
@@ -95,16 +92,11 @@ public class AStar<State, Action> {
|
|||||||
Objects.requireNonNull(initial);
|
Objects.requireNonNull(initial);
|
||||||
Objects.requireNonNull(goal);
|
Objects.requireNonNull(goal);
|
||||||
|
|
||||||
this.lastStateVisitedCount = 0;
|
|
||||||
this.lastStateTotalCount = 1;
|
|
||||||
|
|
||||||
NodeState found = null;
|
NodeState found = null;
|
||||||
var list = new PriorityQueue<NodeState>();
|
var list = new PriorityQueue<NodeState>();
|
||||||
list.add(new NodeState(null, initial, null, 0, 0));
|
list.add(new NodeState(null, initial, null, 0, 0));
|
||||||
|
|
||||||
while(list.size() > 0) {
|
while(list.size() > 0) {
|
||||||
this.lastStateVisitedCount += 1;
|
|
||||||
|
|
||||||
var current = list.poll();
|
var current = list.poll();
|
||||||
if(current.state.equals(goal)) {
|
if(current.state.equals(goal)) {
|
||||||
found = current;
|
found = current;
|
||||||
@@ -112,8 +104,6 @@ public class AStar<State, Action> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(var action : this.actions.apply(current.state)) try {
|
for(var action : this.actions.apply(current.state)) try {
|
||||||
|
|
||||||
this.lastStateTotalCount += 1;
|
|
||||||
var next = this.transition.apply(current.state, action);
|
var next = this.transition.apply(current.state, action);
|
||||||
var cost = this.cost.apply(current.state, next, action);
|
var cost = this.cost.apply(current.state, next, action);
|
||||||
var dist = this.heuristic.apply(next, goal);
|
var dist = this.heuristic.apply(next, goal);
|
||||||
@@ -137,16 +127,6 @@ public class AStar<State, Action> {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int lastStateVisitedCount() {
|
|
||||||
return this.lastStateVisitedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int lastStateTotalCount() {
|
|
||||||
return this.lastStateTotalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classe privata per mantenere i dati all'interno della PriorityQueue.
|
* Classe privata per mantenere i dati all'interno della PriorityQueue.
|
||||||
* Non è stata messa statica dato che ho bisogno dello stato e dell'azione.
|
* Non è stata messa statica dato che ho bisogno dello stato e dell'azione.
|
||||||
@@ -168,7 +148,7 @@ public class AStar<State, Action> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(NodeState other) {
|
public int compareTo(NodeState other) {
|
||||||
return this.total - other.total;
|
return Integer.compare(this.total, other.total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ public class Puzzle8 implements Iterable<Integer> {
|
|||||||
|
|
||||||
for(var i = 0; i < n; i++) index[p1.puzzle[i]] = i;
|
for(var i = 0; i < n; i++) index[p1.puzzle[i]] = i;
|
||||||
for(var i = 0; i < n; i++) {
|
for(var i = 0; i < n; i++) {
|
||||||
var curr = p2.puzzle[i];
|
if(i == p2.blank) continue;
|
||||||
if(curr == 0) continue;
|
|
||||||
|
|
||||||
|
var curr = p2.puzzle[i];
|
||||||
var i2 = index[curr];
|
var i2 = index[curr];
|
||||||
sum += Math.abs((i / LENGTH) - (i2 / LENGTH)) + Math.abs((i % LENGTH) - (i2 % LENGTH));
|
sum += Math.abs((i / LENGTH) - (i2 / LENGTH)) + Math.abs((i % LENGTH) - (i2 % LENGTH));
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,28 @@ public class Puzzle8 implements Iterable<Integer> {
|
|||||||
*/
|
*/
|
||||||
public int get(int x, int y) {
|
public int get(int x, int y) {
|
||||||
if(x >= LENGTH) throw new IndexOutOfBoundsException();
|
if(x >= LENGTH) throw new IndexOutOfBoundsException();
|
||||||
return puzzle[y * LENGTH + x];
|
return get(y * LENGTH + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permette di ricevere in input il valore della coordinata passata in input.
|
||||||
|
* Il valore in input ha formato flat2D, ovvero è un numero che rappresenta una coordinata 2D in uno spazio finito.
|
||||||
|
* La formula generale per calcolare il numero è la seguente: x + (MAX_X + 1) * y.
|
||||||
|
* Quindi nel nostro caso si può calcolare la formula con: x + Puzzle8.LENGTH * y.
|
||||||
|
* NOTA: non usare questo metodo se non si ha capito che cosa significhi. Piuttosto utilizzare {@link #get(int, int)}
|
||||||
|
* @param flat2D la rappresentazione monodimensionale della coordinata 2D
|
||||||
|
* @return il valore in quel punto del puzzle.
|
||||||
|
*/
|
||||||
|
public int get(int flat2D) {
|
||||||
|
return puzzle[flat2D];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permette di avere la posizione della tessera vuota in formato flat2D utilizzabile nel metodo {@link #get(int)}
|
||||||
|
* @return la posizione dello 0 o tessera vuota
|
||||||
|
*/
|
||||||
|
public int getBlankPosition() {
|
||||||
|
return this.blank;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,13 +222,14 @@ public class Puzzle8 implements Iterable<Integer> {
|
|||||||
var rand = new Random();
|
var rand = new Random();
|
||||||
for(var i = this.puzzle.length - 1; i > 0; i--) {
|
for(var i = this.puzzle.length - 1; i > 0; i--) {
|
||||||
var j = rand.nextInt(i + 1);
|
var j = rand.nextInt(i + 1);
|
||||||
|
|
||||||
var temp = this.puzzle[i];
|
var temp = this.puzzle[i];
|
||||||
this.puzzle[i] = this.puzzle[j];
|
this.puzzle[i] = this.puzzle[j];
|
||||||
this.puzzle[j] = temp;
|
this.puzzle[j] = temp;
|
||||||
|
|
||||||
if(this.puzzle[i] == 0) this.blank = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(var i = 0; i < this.puzzle.length; i++)
|
||||||
|
if(this.puzzle[i] == 0)
|
||||||
|
this.blank = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class TestPuzzle {
|
|||||||
var puzzle = new Puzzle8(goalArray);
|
var puzzle = new Puzzle8(goalArray);
|
||||||
|
|
||||||
for(var i = 0; i < goalArray.length; i++)
|
for(var i = 0; i < goalArray.length; i++)
|
||||||
assertEquals(goalArray[i], puzzle.get(i%3, i/3), "Error in initialization");
|
assertEquals(goalArray[i], puzzle.get(i), "Error in initialization");
|
||||||
|
|
||||||
var puzzle2 = new Puzzle8(goalArray);
|
var puzzle2 = new Puzzle8(goalArray);
|
||||||
assertEquals(puzzle, puzzle2, "Error in equality");
|
assertEquals(puzzle, puzzle2, "Error in equality");
|
||||||
@@ -71,8 +71,7 @@ public class TestPuzzle {
|
|||||||
var puzzle = new Puzzle8(goalArray);
|
var puzzle = new Puzzle8(goalArray);
|
||||||
var moves = new Puzzle8.Move[] {RIGHT, DOWN, LEFT, UP, DOWN, RIGHT, UP, LEFT};
|
var moves = new Puzzle8.Move[] {RIGHT, DOWN, LEFT, UP, DOWN, RIGHT, UP, LEFT};
|
||||||
|
|
||||||
for(var move : moves)
|
for(var move : moves) puzzle = new Puzzle8(puzzle, move);
|
||||||
puzzle = new Puzzle8(puzzle, move);
|
|
||||||
assertEquals(new Puzzle8(goalArray), puzzle, "After useless moves the puzzle must be the same as before!");
|
assertEquals(new Puzzle8(goalArray), puzzle, "After useless moves the puzzle must be the same as before!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,4 +157,21 @@ public class TestPuzzle {
|
|||||||
for(var move : actions) puzzle.move(move);
|
for(var move : actions) puzzle.move(move);
|
||||||
assertEquals(puzzle, goal);
|
assertEquals(puzzle, goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShuffleBlankPosition() {
|
||||||
|
var puzzle = new Puzzle8(Puzzle8.DEFAULT_GOAL);
|
||||||
|
var tot = Puzzle8.LENGTH * Puzzle8.LENGTH;
|
||||||
|
|
||||||
|
for(var i = 0; i < 1000; i++) {
|
||||||
|
puzzle.shuffle();
|
||||||
|
|
||||||
|
var blank = 10;
|
||||||
|
for(var j = 0; j < tot; j++)
|
||||||
|
if(puzzle.get(j) == 0)
|
||||||
|
blank = j;
|
||||||
|
|
||||||
|
assertEquals(blank, puzzle.getBlankPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user