package pathgame.algorithm; import pathgame.gameplay.Player; import pathgame.logging.Logger; import pathgame.tilemap.TileMap; import java.util.ArrayList; import java.util.Collections; public class TravellingSalesAlg { public static int calcSalesPathLen(TileMap map, Player player) { DijkstraMagic dijkstra = new DijkstraMagic(map, player); ArrayList> salesPitch = dijkstra.getSalesPitch(); //make minimum spanning tree ArrayList MSTree = makeMSTree(salesPitch); //find pairs-shortest path for verteces with odd degree and add those edges to MSTree ArrayList oddDegEdges = makeOddDegEdges(MSTree, salesPitch); MSTree.addAll(oddDegEdges); //finde euler tour ArrayList eulerTour = getEulerTour(MSTree); //cut short cutShort(eulerTour); Logger.onAlgoDone(salesPitch, eulerTour); //calculate the total weight of the tour using the edge table (salesPitch) int tourWeight = calcTourWeight(eulerTour, salesPitch); System.out.println("min cost: " + tourWeight); return tourWeight; //brute force //return bruteForce(salesPitch); } private static int calcTourWeight(ArrayList tour, ArrayList> salesPitch) { int totalWeight = 0; for(int i = 0; i < tour.size()-1; i++) { int startNode, endNode; if(tour.get(i) < tour.get(i+1)) { startNode = tour.get(i); endNode = tour.get(i+1) - startNode - 1; } else { startNode = tour.get(i+1); endNode = tour.get(i) - startNode - 1; } totalWeight += salesPitch.get(startNode).get(endNode).getTotalCost(); } return totalWeight; } private static void cutShort(ArrayList eulerTour) { int counter = 2; while(counter < eulerTour.size()-1) { int current = eulerTour.get(counter); boolean found = false; for(int i = 0; i < counter; i++) { if(eulerTour.get(i) == current) { found = true; break; } } if(found) { eulerTour.remove(counter); } else { counter++; } } } private static ArrayList getEulerTour(ArrayList graph) { ArrayList tour = new ArrayList<>(); while (graph.size() > 0) { if(tour.size() == 0) { tour = getSubtour(graph, graph.get(0).getSrc()); } else { int start = -1; for(int e = 0; e < graph.size(); e++) { TreeEdge edge = graph.get(e); for(int tp = 0; tp < tour.size(); tp++) { if(edge.getSrc() == tour.get(tp)) { start = edge.getSrc(); break; } else if(edge.getDest() == tour.get(tp)) { start = edge.getDest(); break; } } if(start!= -1) { break; } } ArrayList subTour = getSubtour(graph, start); mergeTours(tour, subTour); } } return tour; } private static ArrayList getSubtour(ArrayList graph, int start) { ArrayList tour = new ArrayList<>(); tour.add(start); int pos = nextTourEdgePos(graph, start); int next = graph.get(pos).getOtherVertex(start); graph.remove(pos); tour.add(next); while (next != start) { pos = nextTourEdgePos(graph, next); next = graph.get(pos).getOtherVertex(next); graph.remove(pos); tour.add(next); } return tour; } private static int nextTourEdgePos(ArrayList graph, int vertex) { for(int i = 0; i < graph.size(); i++) { if(graph.get(i).getSrc() == vertex || graph.get(i).getDest() == vertex) { return i; } } return -1; } private static void mergeTours(ArrayList tour, ArrayList subTour) { int mergeTo = subTour.get(0); int mergePos = -1; for(int i = 0; i < tour.size(); i++) { if (tour.get(i) == mergeTo) { mergePos = i; } } for(int i = subTour.size()-1; i > 0; i--) { tour.add(mergePos+1, subTour.get(i)); } } private static ArrayList makeOddDegEdges(ArrayList msTree, ArrayList> salesPitch) { int numOfEdges[] = new int[salesPitch.size()]; for (int i = 0; i < msTree.size(); i++) { numOfEdges[msTree.get(i).getSrc()]++; numOfEdges[msTree.get(i).getDest()]++; } OddDegreeList oddDegs = new OddDegreeList(); for (int i = 0; i < numOfEdges.length; i++) { //System.out.println(numOfEdges[i]); if (numOfEdges[i] % 2 == 1) { oddDegs.add(i); } } Permutation permut = new Permutation(oddDegs.size(), 2); calcPairShortest(oddDegs, salesPitch, permut, 0, 0); permut.makePermutMinimal(); //System.out.println(permut.tempCounter1); //System.out.println(permut.tempCounter2); //System.out.println("min cost: " + permut.getMinCost()); //permut.printPermut(); ArrayList oddEdges = new ArrayList<>(); oddDegs.resetUsed(); for(int i = 0; i < permut.size(); i++) { int offSet = permut.getValAtPos(i); addOddEdge(oddEdges, oddDegs, salesPitch, offSet); } addOddEdge(oddEdges, oddDegs, salesPitch, 0); return oddEdges; } private static void addOddEdge(ArrayList oddEdges, OddDegreeList oddDegs, ArrayList> salesPitch, int offSet) { int orig = oddDegs.getUnused(0); oddDegs.makeOffsetUsed(0); int dest = oddDegs.getUnused(offSet); oddDegs.makeOffsetUsed(offSet); oddEdges.add(new TreeEdge(orig, dest, salesPitch.get(orig).get(dest - orig - 1).getTotalCost())); } private static void calcPairShortest(OddDegreeList oddDegs, ArrayList> salesPitch, Permutation permut, int permutPos, int costSoFar) { while(true) { int offSet; if(permutPos == permut.size()) { offSet = 0; } else { offSet = permut.getValAtPos(permutPos); } int orig = oddDegs.getUnused(0); int dest = oddDegs.getUnused(1 + offSet); int edgeWeight = salesPitch.get(orig).get(dest - orig - 1).getTotalCost(); int newCost = costSoFar + edgeWeight; //permut.tempCounter1++; /*System.out.println(); System.out.println("permut pos: " + permutPos); System.out.println(orig + " : " + dest); System.out.println("newCost: " + newCost); permut.printPermut();*/ if(newCost < permut.getMinCost()) { if(permutPos == permut.size()) { permut.setMinCost(newCost); /*System.out.println(); System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); System.out.println("New Min: " + newCost); System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");*/ } else { int used1 = oddDegs.makeOffsetUsed(0); int used2 = oddDegs.makeOffsetUsed(offSet); calcPairShortest(oddDegs, salesPitch, permut, permutPos+1, costSoFar+edgeWeight); oddDegs.makeUnused(used1); oddDegs.makeUnused(used2); } } if(permutPos == permut.size()) { //permut.tempCounter2++; break; } if(permut.isPosAtMax(permutPos)) { break; } permut.increaseAtPos(permutPos); } } public static ArrayList makeMSTree(ArrayList> salesPitch) { ArrayList allEdges = new ArrayList<>(); ArrayList msTree = new ArrayList<>(); int vertNum = salesPitch.size(); for (int orig = 0; orig < salesPitch.size(); orig++) { for (int dest = 0; dest < salesPitch.get(orig).size(); dest++) { allEdges.add(new TreeEdge(orig, dest + 1 + orig, salesPitch.get(orig).get(dest).getTotalCost())); //System.out.println(edge.getSrc() + " " + edge.getDest() + " " + edge.getWeight()); //System.out.println(salesPitch.get(orig).get(dest).getTotalCost()); } } //System.out.println(vertNum); Collections.sort(allEdges); while (msTree.size() < vertNum - 1) { if (notCycle(msTree, allEdges.get(0))) { msTree.add(allEdges.get(0)); //System.out.println(allEdges.get(0).getSrc() + " " + allEdges.get(0).getDest() + " " + allEdges.get(0).getWeight()); } allEdges.remove(0); } return msTree; } private static void qEdges(ArrayList tree, ArrayList edgeQ, int vertex) { for(int i = 0; i < tree.size(); i++) { TreeEdge edge = tree.get(i); if(edge.getSrc() == vertex || edge.getDest() == vertex) { if(!edge.isChecked()) { edgeQ.add(edge); //System.out.println("src: " + edge.getSrc() + "; dest: " + edge.getDest()); edge.setChecked(true); } } } } private static boolean notCycle(ArrayList tree, TreeEdge additon) { ArrayList edgeQ = new ArrayList<>(); int dest = additon.getDest(); resetEdges(tree); qEdges(tree, edgeQ, additon.getSrc()); while(edgeQ.size() > 0) { TreeEdge edge = edgeQ.get(0); edgeQ.remove(0); if(edge.getSrc() == dest || edge.getDest() == dest) { return false; } else { qEdges(tree, edgeQ, edge.getSrc()); qEdges(tree, edgeQ, edge.getDest()); } } return true; } private static void resetEdges(ArrayList tree) { for(int i = 0; i < tree.size(); i++) { tree.get(i).setChecked(false); } } /*private static int bruteForce(ArrayList> salesPitch) { Permutation permutation = new Permutation(salesPitch.size(), 1); OddDegreeList nodeList = new OddDegreeList(); for(int i = 0; i < salesPitch.size()+1; i++) { nodeList.add(i); } while(!permutation.isOverFlowing()) { int newSum = bruteSumPermut(permutation, salesPitch, nodeList); if(newSum < permutation.getMinCost()) { permutation.setMinCost(newSum); } /*permutation.printPermut(); System.out.println(newSum); System.out.println();*/ /*permutation.increaseLowest(); } permutation.makePermutMinimal(); permutation.printPermut(); System.out.println("min cost: " + permutation.getMinCost()); return 0; } private static int bruteSumPermut(Permutation permutation, ArrayList> salesPitch, OddDegreeList nodeList) { int sum = 0; nodeList.resetUsed(); int first = -1; int last = -1; for(int i = 0; i < permutation.size(); i++) { int pos = nodeList.getUnused(permutation.getValAtPos(i)); //System.out.println("pos: " + pos); if(first == -1) { first = pos; } else { //System.out.println(last + " - " + pos); sum += bruteWeight(last, pos, salesPitch); //System.out.println(sum); } last = pos; nodeList.makePosUsed(pos); } //System.out.println(last + " - " + nodeList.getUnused(0)); int pos = nodeList.getUnused(0); sum += bruteWeight(last, pos, salesPitch); //System.out.println(pos + " - " + first); sum += bruteWeight(pos, first, salesPitch); return sum; } private static int bruteWeight(int first, int sec, ArrayList> salesPitch) { if(first < sec) { return salesPitch.get(first).get(sec-first-1).getTotalCost(); } else { return salesPitch.get(sec).get(first-sec-1).getTotalCost(); } }*/ }