package org.drooms.impl.logic;
import edu.uci.ics.jung.graph.Graph;
import org.assertj.core.api.Assertions;
import org.drooms.api.Edge;
import org.drooms.api.Node;
import org.drooms.api.Playground;
import org.drooms.impl.DefaultGame;
import org.junit.Test;
import java.util.*;
public class PathTrackerTest {
private static final Playground PLAYGROUND = new DefaultGame().buildPlayground("test", PathTrackerTest.class
.getResourceAsStream("testing.playground"));
private static final Graph<Node, Edge> GRAPH = PathTrackerTest.PLAYGROUND.getGraph();
@Test
public void testPathToItself() {
final Node start = PLAYGROUND.getNodeAt(10, 10);
Assertions.assertThat(PathTracker.getPath(GRAPH, start, Collections.singleton(start))).isEmpty();
}
@Test
public void testPathToNext() {
final Node start = PLAYGROUND.getNodeAt(10, 10);
final Node end = PLAYGROUND.getNodeAt(10, start.getY() + 1);
final List<Edge> path = PathTracker.getPath(GRAPH, start, Collections.singleton(end));
Assertions.assertThat(path).hasSize(1);
final Edge edge = path.get(0);
Assertions.assertThat(edge.getFirstNode()).isEqualToComparingFieldByField(start);
Assertions.assertThat(edge.getSecondNode()).isEqualToComparingFieldByField(end);
}
@Test
public void testPathToNextWithGarbage() {
final Node start = PLAYGROUND.getNodeAt(10, 10);
final Node end = PLAYGROUND.getNodeAt(10, start.getY() + 1);
// start and null in the set will be ignored as garbage
final List<Edge> path = PathTracker.getPath(GRAPH, start, PathTrackerTest.toSet(start, end, null));
Assertions.assertThat(path).hasSize(1);
final Edge edge = path.get(0);
Assertions.assertThat(edge.getFirstNode()).isEqualToComparingFieldByField(start);
Assertions.assertThat(edge.getSecondNode()).isEqualToComparingFieldByField(end);
}
private static int getManhattanDistance(final Node start, final Node end) {
return Math.abs(end.getX() - start.getX()) + Math.abs(end.getY() - start.getY());
}
private static Set<Node> toSet(final Node... nodes) {
return new LinkedHashSet<>(Arrays.asList(nodes));
}
@Test
public void testShortestPath() {
final Node start = PLAYGROUND.getNodeAt(10, 10);
final Node end = PLAYGROUND.getNodeAt(15, 15);
// the length of shortest path between two objects in a 2D grid is their Manhattan distance
final int manhattanDistance = PathTrackerTest.getManhattanDistance(start, end);
final List<Edge> path = PathTracker.getPath(GRAPH, start, Collections.singleton(end));
Assertions.assertThat(path).hasSize(manhattanDistance);
}
private void testShortestPathThroughNode(final boolean endFirst) {
// pass through a corner node
final Node start = PLAYGROUND.getNodeAt(3, 0);
final Node middle = PLAYGROUND.getNodeAt(0, 0);
final Node end = PLAYGROUND.getNodeAt(0, 3);
// the length of shortest path between two objects in a 2D grid is their Manhattan distance
final int manhattanDistance = PathTrackerTest.getManhattanDistance(start, end);
final List<Edge> path = PathTracker.getPath(GRAPH, start, endFirst ? PathTrackerTest.toSet(end, middle) :
PathTrackerTest.toSet(middle, end));
Assertions.assertThat(path).hasSize(manhattanDistance);
// make sure that in the path there is the middle node
final Collection<Edge> edges = GRAPH.getIncidentEdges(middle);
Assertions.assertThat(edges).hasSize(2); // otherwise the following assertion makes no sense
Assertions.assertThat(path).containsAll(edges);
}
@Test
public void testShortestPathThroughNodeMiddleFirst() {
this.testShortestPathThroughNode(false);
}
@Test
public void testShortestPathThroughNodeEndFirst() {
this.testShortestPathThroughNode(true);
}
private void testWrongNode(final boolean unreachableFirst, final boolean doesNodeExist) {
final Node start = PLAYGROUND.getNodeAt(3, 0);
final Node end = PLAYGROUND.getNodeAt(0, 3);
// first node is surrounded by walls, the other is a wall itself and therefore not present in the graph
final Node unreachable = doesNodeExist ? PLAYGROUND.getNodeAt(68, 12) : PLAYGROUND.getNodeAt(10, 15);
final List<Edge> path = PathTracker.getPath(GRAPH, start, unreachableFirst ? PathTrackerTest.toSet(unreachable,
end) : PathTrackerTest.toSet(end, unreachable));
Assertions.assertThat(path).isEmpty();
}
@Test
public void testUnreachableNodeFirst() {
this.testWrongNode(true, true);
}
@Test
public void testUnreachableNodeLast() {
this.testWrongNode(false, true);
}
@Test
public void testNonexistentNodeFirst() {
this.testWrongNode(true, false);
}
@Test
public void testNonexistentNodeLast() {
this.testWrongNode(false, false);
}
@Test
public void testShortestPathThroughTwoNodes() {
final int DISTANCE = 3;
// pass through a corner node
final Node start = PLAYGROUND.getNodeAt(DISTANCE, 0);
final Node middle1 = PLAYGROUND.getNodeAt(0, 0);
final Node middle2 = PLAYGROUND.getNodeAt(DISTANCE, DISTANCE);
final Node end = PLAYGROUND.getNodeAt(0, DISTANCE);
// minimal possible path length
final List<Edge> path = PathTracker.getPath(GRAPH, start, PathTrackerTest.toSet(middle1, end, middle2));
Assertions.assertThat(path).hasSize(DISTANCE + DISTANCE + DISTANCE);
// make sure that all nodes are in path
Set<Node> nodesToFind = PathTrackerTest.toSet(start, middle1, middle2, end);
path.forEach(edge -> nodesToFind.removeAll(GRAPH.getIncidentVertices(edge)));
Assertions.assertThat(nodesToFind).isEmpty();
}
}