I need to give the widest path from one chosen node to another in a self-generated graph. After this, I need to state the "bottleneck" or smallest weight on the computed path. As it is, I don't know where to start to find the bottleneck and I'm having trouble showing the path. Under the Graph class, in the printPath method, I am currently getting a StackOverflow Error from presumably infinite recursion, though I don't understand how its recurring infinitely in the first place. I've used some code from here: https://www.geeksforgeeks.org/printing-paths-dijkstras-shortest-path-algorithm/ with slight modification to find the largest path rather than the shortest as well renaming variables. I feel an error in said modification is most likely one source of the problem. Following is the output of my most recent test:
Enter a positive integer.
5
Node list: {1,2,3,4,5}
Edge list: {(2,3,17),(2,4,8),(3,5,3)}
Enter a source node.
1
Enter a destination node
5
Vertex: 1 --> 5
Distance: 20
Path: Exception in thread "main" java.lang.StackOverflowError
at Graph.printPath(Graph.java:104)
at Graph.printPath(Graph.java:104)
at Graph.printPath(Graph.java:104)
Here's my code so far. I've had my code in separate classes, so I apologize for any errors I may have made combining them to one file. I also apologize for the massive and messy block of code but I don't think there's anything here I can weed out before posting.
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Random;
public class Graph{
private ArrayList<Node> nodes = new ArrayList<Node>();
private ArrayList<Edge> edges = new ArrayList<Edge>();
private int[][] adjMatrix;
Graph(int numNodes, int weightBound, double probability){
ArrayList<Node> tempNodeList = new ArrayList<Node>(numNodes);
for(int i = 0; i < numNodes; i++) {
Node tempNode = new Node(i+1);
tempNodeList.add(tempNode);
}
this.nodes = tempNodeList;
Random rand = new Random();
for(int i = 0; i < numNodes; i++) {
for(int j = i+1; j < numNodes; j++) {
if(rand.nextInt((int)Math.round(1/probability)) == 0) {
Edge tempEdge = new Edge(rand.nextInt(5*numNodes-1)+1, nodes.get(i), nodes.get(j));
edges.add(tempEdge);
}
}
}
adjMatrix = new int[numNodes][numNodes];
for(int i = 0; i < edges.size(); i++) {
adjMatrix[edges.get(i).getNode(0).getID()-1][edges.get(i).getNode(1).getID()-1] = edges.get(i).getWeight();
adjMatrix[edges.get(i).getNode(1).getID()-1][edges.get(i).getNode(0).getID()-1] = edges.get(i).getWeight();
}
}
public void printGraph() {
System.out.print("Node list: {");
for(int i = 0; i < nodes.size(); i++) {
nodes.get(i).printNode();
if(i != nodes.size()-1) {
System.out.print(",");
}
}
System.out.println("}");
System.out.print("Edge list: {");
for(int i = 0; i < edges.size(); i++) {
edges.get(i).printEdge();
if(i != edges.size()-1) {
System.out.print(",");
}
}
System.out.println("}");
}
public void widestPath(int source, int dest){
int numVertices = adjMatrix[0].length;
int[] longestDists = new int[numVertices];
boolean[] inPath = new boolean[numVertices];
for(int i = 0; i < numVertices; i++) {
inPath[i] = false;
}
longestDists[source] = 0;
Node tempNode = nodes.get(source);
tempNode.setParent(-1);
nodes.set(source, tempNode);
for(int i = 1; i < numVertices; i++) {
int furthestNode = -1;
int longestDist = Integer.MIN_VALUE;
for(int index = 0; index < numVertices; index++) {
if(!inPath[index] && longestDists[index] > longestDist) {
furthestNode = index;
longestDist = longestDists[index];
}
}
inPath[furthestNode] = true;
for(int index = 0; index < numVertices; index++) {
int edgeWeight = adjMatrix[furthestNode][index];
if(edgeWeight > 0 && ((longestDist + edgeWeight) > (longestDists[index]))){
tempNode = nodes.get(index);
tempNode.setParent(furthestNode);
nodes.set(index, tempNode);
longestDists[index] = longestDist + edgeWeight;
}
}
}
printResult(source, longestDists, dest);
}
public void printResult(int source, int[] dists, int dest) {
System.out.println("Vertex: " + (source+1) + " --> " + (dest+1));
System.out.println("Distance: " + dists[dest]);
System.out.print("Path: ");
printPath(dest);
}
public void printPath(int dest) {
if(nodes.get(dest).getParent() == -1) {
return;
}
printPath(nodes.get(dest).getParent()); // StackOverflow here
System.out.print((dest+1) + " ");
}
}
public class Node {
private int ID;
private int distance = Integer.MIN_VALUE;
private int parent;
Node(int id){
this.ID = id;
}
public int getID() {
return this.ID;
}
public void printNode() {
System.out.print(this.ID);
}
public void setDist(int dist) {
this.distance = dist;
}
public int getDist() {
return this.distance;
}
public void setParent(int p) {
this.parent = p;
}
public int getParent() {
return this.parent;
}
}
public class Edge {
private int weight;
private ArrayList<Node> vertices = new ArrayList<Node>(2);
Edge(int weight){
this.weight = weight;
}
Edge(int weight, Node n1, Node n2){
this.weight = weight;
this.vertices.add(n1);
this.vertices.add(n2);
}
public int getWeight() {
return weight;
}
public void setNodes(Node n1, Node n2) {
this.vertices.set(0, n1);
this.vertices.set(1, n2);
}
public ArrayList<Node> getNodes(){
return vertices;
}
public void printEdge() {
System.out.print("(" + vertices.get(0).getID() + "," + vertices.get(1).getID() + "," + this.weight + ")");
}
public int otherNodeIndex(int ID) {
if(vertices.get(0).getID() == ID) {
return 1;
}else if(vertices.get(1).getID() == ID) {
return 0;
} else {
return -1;
}
}
public Node getNode(int index) {
return vertices.get(index);
}
}
public class Driver {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int input = -1;
while(input <= 0) {
System.out.println("Enter a positive integer.");
input = sc.nextInt();
}
double probability = 0.25;
Graph gr = new Graph(input, input*5, probability);
gr.printGraph();
int source = -1;
int dest = -1;
while(source < 0 || source > input) {
System.out.println("Enter a source node.");
source = sc.nextInt()-1;
}
while(dest < 0 || dest > input) {
System.out.println("Enter a destination node");
dest = sc.nextInt()-1;
}
gr.widestPath(source, dest);
}
}
Im running my code, and after it says the first print statement it pauses. It pauses at a point where it calls a function "insert" and simply doesnt respond anything. it prints "adding dog, cat, & horse" but then just stops, doesnt do anything after that.
main function
package assignment2;
public class Main {
public static void main(String[] args) {
OrderedStringList myList = new OrderedStringList(5);
System.out.println("adding dog, cat, & horse");
myList.Insert("dog");
myList.Insert("cat");
myList.Insert("horse");
myList.Display();
System.out.println("Value pig find = "+ myList.Find("pig"));
System.out.println("Value horse find = "+ myList.Find("horse"));
System.out.println("Adding mouse & rat");
myList.Insert("mouse");
myList.Insert("rat");
myList.Display();
System.out.println("myList size: "+ myList.Size());
if (!myList.Insert("chinchilla"))
System.out.println("Could not add chinchilla, full");
System.out.println("Removing dog, adding chinchilla.");
myList.Delete("dog");
myList.Insert("chinchilla");
myList.Display();
}
}
here is my code of functions
package assignment2;
public class OrderedStringList {
int length;
int numUsed;
String[] storage;
boolean ordered;
public OrderedStringList(int size){
length = size;
storage = new String[length];
numUsed = 0;
}
public boolean Insert(String value){
boolean result = false;
int index = 0;
if (numUsed < length) {
while (index < numUsed) {
int compare = storage[index].compareTo(value);
if (compare < 0)
index++;
}
moveItemsDown(index);
storage[index] = value;
numUsed++;
result = true;
}
return result;
}
private void moveItemsDown(int start){
int index;
for (index = numUsed-1; index >=start; index--){
storage[index+1] = storage[index];
}
}
private void moveItemsUp(int start){
int index;
for (index = start; index < numUsed-1; index++){
storage[index] = storage[index+1];
}
}
public boolean Find(String value){
return (FindIndex(value) >= 0);
}
private int FindIndex(String value) {
int result = -1;
int index = 0;
boolean found = false;
while ((index < numUsed) && (!found)) {
found = (value.equals(storage[index]));
if (!found)
index++;
}
if (found)
result = index;
return result;
}
public boolean Delete(String value){
boolean result = false;
int location;
location = FindIndex(value);
if (location >= 0) {
moveItemsUp(location);
numUsed--;
result = true;
}
return result;
}
public void Display() {
int index;
System.out.println("list Contents: ");
for (index = 0; index < numUsed; index++) {
System.out.println(index+" "+storage[index]);
}
System.out.println("-------------");
System.out.println();
}
public void DisplayNoLF() {
int index;
System.out.println("list Contents: ");
for (index = 0; index < numUsed; index++) {
System.out.print(storage[index]+" ");
}
System.out.println("-------------");
System.out.println();
}
public int Size(){
return numUsed;
}
}
You're getting caught in an infinite loop in the while statement of your Insert function. Consider this piece of code:
while (index < numUsed) {
int compare = storage[index].compareTo(value);
if (compare < 0)
index++;
}
What happens if compare >= 0 for index = 0? Index doesn't increment upwards, then the while loop is called again on index = 0, ad infinitum. You need to increment index outside of the if statement and put a different condition in your if statement.
while (index < numUsed && storage[index].compareTo(value) < 0) {
index++;
}
solved my problem by doing this. i simply removed the for loop and added an extra requirement on the while loop.
I am trying to recursively populate a tree, but my code is only only fill out one depth length, and then quiting. i.e. each node only has one child. Is there something am failing to take in to consideration?
public static void populate(Node n, int depth, String player){
System.out.println("Depth: " + depth);
if(player.equalsIgnoreCase("X"))
player = "O";
else
player = "X";
int j = 0;
System.out.println("empty spots: " + ((Board)n.getData()).noOfEmpty());
for(int i=0; i<((Board)n.getData()).noOfEmpty(); i++){
if(((Board)n.getData()).getSquare(j).equalsIgnoreCase("X")
|| ((Board)n.getData()).getSquare(j).equalsIgnoreCase("O"))
j++;
else{
Board tmp = new Board(((Board)n.getData()), j, player);
Node newNode = new Node(tmp);
tree.insert(n, newNode);
populate(newNode, depth-1, player);
}
}
}
P.S. and i check the noOfEmpty() return value, which should determine the number of children a node should have.
edit:#eznme the complete code as requested:
public class MinMax {
protected static Tree tree;
public static void createTree(Board b){
tree = new Tree();
tree.setRoot(new Node(b));
populate(tree.getRoot(), 5, "X");
//System.out.println("printing tree");
//tree.print(1);
}
public static void populate(Node n, int depth, String player){
System.out.println("Depth: " + depth);
if(player.equalsIgnoreCase("X"))
player = "O";
else
player = "X";
int j = 0;
System.out.println("empty spots: " + ((Board)n.getData()).noOfEmpty());
for(int i=0; i<((Board)n.getData()).noOfEmpty(); i++){
if(((Board)n.getData()).getSquare(j).equalsIgnoreCase("X")
|| ((Board)n.getData()).getSquare(j).equalsIgnoreCase("O"))
j++;
else{
Board tmp = new Board(((Board)n.getData()), j, player);
Node newNode = new Node(tmp);
tree.insert(n, newNode);
populate(newNode, depth-1, player);
}
}
}
}
import java.util.ArrayList;
/**
*
* #author Greg
*/
public class Node {
protected Object data;
protected int score; //fields to be used by the MaxMin class
protected ArrayList<Node> children;
//constructors
public Node(){
children = new ArrayList(0);
data = null;
}
public Node(Object obj){
children = new ArrayList(0);
data = obj;
}
public void setChild(Node n){
//EFFECT: set the ith child to node t
children.add(n);
}
public void setChildren(Node[] t){
//EFFECT: copy the array t, into the array children, effectively
// setting all the chidern of this node simultaneouly
int l = children.size();
for(int i=0; i<t.length; i++){
children.add(l, t[i]);
}
}
public void setData(Object obj){
//EFFECT: set the date of this node to obj, and also set the number of
// children this node has
data = obj;
}
public Node getChild(int i){
//EFFECT: returns the child at index i
return children.get(i);
}
public int noOfChildren(){
//EFFECT: return the length of this node
return children.size();
}
public Object getData(){
//EFFECT: returns the data of this node
return data;
}
#Override
public String toString(){
//EFFECT: returns the string form of this node
return "" + data.toString() + "\nwith " + noOfChildren()+ "\n";
}
public boolean isLeaf(){
if(children.size()==0)
return true;
return false;
}
public void setScore(int scr){
score = scr;
}
public int getScore(){
return score;
}
}
public class Tree {
private Node root;
public Tree(){
setRoot(null);
}
public Tree(Node n){
setRoot(n);
}
public Tree(Object obj){
setRoot(new Node(obj));
}
protected Node getRoot(){
return root;
}
protected void setRoot(Node n){
root = n;
}
public boolean isEmpty(){
return getRoot() == null;
}
public Object getData(){
if(!isEmpty())
return getRoot().getData();
return null;
}
public Object getChild(int i){
return root.getChild(i);
}
public void setData(Object obj){
if(!isEmpty())
getRoot().setData(obj);
}
public void insert(Node p,Node c){
if(p != null)
p.setChild(c);
}
public void print(int mode){
if(mode == 1) pretrav();
else if(mode == 2) postrav();
else
System.out.println("yeah... mode 1 or 2...nothing else, try agn");
}
public void pretrav(){
pretrav(getRoot());
}
protected void pretrav(Node t){
if(t == null)
return;
System.out.println(t.getData()+" \n");
for(int i=0; i<t.noOfChildren(); i++)
pretrav(t.getChild(i));
}
public void postrav(){
postrav(getRoot());
}
protected void postrav(Node t){
if(t == null)
return;
System.out.print(t.getData()+" ");
for(int i=0; i<t.noOfChildren(); i++)
pretrav(t.getChild(i));
System.out.print(t.getData()+" ");
}
}
public class Board {
boolean isFull = false; // a check to see if the board is full
String[] grid = new String[9]; //an array represting the 9 square on a board
int hV;
String MIN, MAX;
public Board(){
for(int i=0; i<grid.length;i++)
grid[i] = Integer.toString(i);
hV = heuristicValue(this);
}
public Board(Board b, int x, String player){
this.grid = b.getBoard();
if(!(grid[x].equalsIgnoreCase("X")|| grid[x].equalsIgnoreCase("X")))
grid[x] = player;
}
public boolean setSquare(String player, int position){
/*
EFFECT:set a square on the board to either a X or a O, debending on the player
PRECON: square (x,y) is empty
POATCON: square (x,y) has player 'symbol'
*/
boolean isValidPlay = false;
try{
//as a sanity
Integer.parseInt(grid[position]);
grid[position] = player;
isValidPlay = true;
}catch(NumberFormatException e){
System.out.println("positon " + position + "is already occupied");
}
return isValidPlay;
}
public boolean endGame(){
/*
* EFFECT: check to see if the game have been won or drawn
*/
if(ticTacToe(0,1,2)){
//System.out.println("Player " + grid[0] + " wins");
return true;
}
else if(ticTacToe(3,4,5)){
//System.out.println("Player " + grid[3] + " wins");
return true;
}
else if(ticTacToe(6,7,8)){
//System.out.println("Player " + grid[6] + " wins");
return true;
}
else if(ticTacToe(0,4,8)){
//System.out.println("Player " + grid[0]+ " wins");
return true;
}
else if(ticTacToe(0,3,6)){
//System.out.println("Player " + grid[0]+ " wins");
return true;
}
else if(ticTacToe(1,4,7)){
//System.out.println("Player " + grid[1] + " wins");
return true;
}
else if(ticTacToe(2,5,8)){
//System.out.println("Player " + grid[2] + " wins");
return true;
}else if(ticTacToe(2,4,6)){
//System.out.println("Player " + grid[2] + " wins");
return true;
}
else
return isDrawn();
}
public boolean ticTacToe(int x, int y, int z){
/*
* check is x, y and z has the same value
*/
try{
Integer.parseInt(grid[x]);
return false;
}catch(NumberFormatException e){
if( grid[x].equals(grid[y])
&& grid[x].equals(grid[z]))
return true;
else
return false;
}
}
public String getSquare(int i){
return grid[i];
}
#Override
public String toString(){
String msg = "";
for(int i=0; i<grid.length; i++){
msg = msg + grid[i] + " ";
if(i==2 || i==5)
msg = msg+ "\n";
}
return msg;
}
public boolean isDrawn(){
/*
* check to see if there are any 'free' spaces on the board, if there are any
* return false, else return true
*/
for(int i=0; i<grid.length; i++){
try{
Integer.parseInt(grid[i]);
return false;
}catch(NumberFormatException e){
}
}
System.out.println("Game drawn");
return true;
}
public String[] getBoard(){
return grid;
}
public int noOfEmpty(){
//EFFECT: returns the number of empty squares
int count = 0;
for(int i=0; i<grid.length; i++)
if (!(grid[i].equalsIgnoreCase("X") || grid[i].equalsIgnoreCase("O")))
count++;
return count;
}
public int heuristicValue(Board b){
String MAX = "X", MIN = "O";
/*
* calculate a value that will be used as a heuristic function
* the function works for ever X in a row WITHOUT O: 1 point,
* for two X in a row WITHOUT a O: 5 points
* and 3 X in a row: 100 points
*/
//System.out.println("Computing heuristic");
//System.out.println("Computing horizontals");
int hCount = 0;
//sum up the horizontals
for(int i=0; i<9; i=i+3){
int tmpMAX = playerCount(b, MAX,i,i+1,i+2);
int tmpMIN = playerCount(b, MIN,i,i+1,i+2);
//System.out.println(tmpMAX);
//System.out.println(tmpMIN);
if(tmpMIN > 0){
//System.out.println("Min was zero");
}
else if(tmpMAX==1){
//System.out.println("has one");
hCount = hCount + 1;
}
else if(tmpMAX==2){
//System.out.println("was tw0");
hCount = hCount + 5;
}
else if(tmpMAX==3){
//System.out.println("full 100");
hCount = hCount + 100;
}
}
//System.out.println("Computing verticals");
//sum up the verticals
for(int i=0; i<3; i++){
int tmpMAX = playerCount(b, MAX,i,i+3,i+6);
int tmpMIN = playerCount(b, MIN,i,i+3,i+6);
if(tmpMIN > 0){}
else if(tmpMAX==1){
hCount = hCount +1;
}
else if(tmpMAX==2){
hCount = hCount + 5;
}
else if(tmpMAX==3){
hCount = hCount + 100;
}
}
//System.out.println("Computing diagonals");
//sum up diagonals
if(playerCount(b, MIN,0,4,8)==0){
if(playerCount(b, MAX,0,4,8)==1){
hCount = hCount + 1;
}
if(playerCount(b, MAX,0,4,8)==2)
hCount = hCount + 5;
if(playerCount(b, MAX,0,4,8)==3)
hCount = hCount + 100;
}
if(playerCount(b, MIN,2,4,6)==0){
if(playerCount(b, MAX,2,4,6)==1){
hCount = hCount + 1;
}
if(playerCount(b, MAX,2,4,6)==2)
hCount = hCount + 5;
if(playerCount(b, MAX,2,4,6)==3)
hCount = hCount + 100;
}
//System.out.println("Computing completed");
int hV = hCount;
return hV;
}
int playerCount(Board b, String player, int x, int y, int z){
int count = 0;
if(b.getSquare(x).equals(player))
count = count + 1;
if(b.getSquare(y).equals(player))
count = count + 1;
if(b.getSquare(z).equals(player))
count = count + 1;
//System.out.println("playerCount; " + count);
return count;
}
}
import java.io.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new
InputStreamReader(System.in));
Board thisGame = new Board();
System.out.println("Start \n" + thisGame.toString());
MinMax.createTree(thisGame);
System.exit(0);
}
}
In order to recursively build a n-ary tree, I would do this:
public static void populate(Node n, int height){
if(height = 0){
n = new Node();
}else{
n = new Node();
for(int i = 0; i < n.nbChilds(); i++){
populate(n.getChildAt(i), height - 1);
}
}
}
I hope it helps.
Order of nodes creation with this algo (on a binary tree):
1
2 9
3 6 10 13
4 5 7 8 11 12 14 15
So here is what I would do in your case (minimax tic-tac-toe):
Terminology:
Height of a node: Distance from this node to it's further leaf.
Depth of a node: Distance from the root of the tree, to this node.
You have to keep trying all cases until: the board is full OR one player won. So, your tree's height is numberOfCells + 1.
If we simplify the problem and don't worry about symmetric duplicates:
Each node will have numberOfcells - nodeDepth childs.
public static void main(String[] args){
Tree t = new Tree();
int nbCells = 9;
t.setRoot(buildTree(new Board(nbCells), 0, -1));
}
public static Node buildTree(Board b, int player, int positionToPlay){
if(player != 0){
b.setCellAt(positionToPlay, player);
}
Node n = new Node(b, b.nbEmptyCells());
int j = 0;
for(int i = 0; i < b.nbCells(); i++){
if(b.getCellAt(i) == 0)
n.setChildAt(j++, buildTree(new Board(b), changePlayer(player), i));
}
return n;
}
public static int changePlayer(int p){
switch(p){
case 0:
return 1;
case 1:
return 2;
case 2:
return 1;
default:
return 0;
}
}
Node class:
public class Node {
private Board board;
private Node[] childs;
public Node(Board b, int nbChilds){
this.board = new Board(b);
this.childs = new Node[nbChilds];
}
public Node getChildAt(int i){
return childs[i];
}
public int nbChilds(){
return childs.length;
}
public void setChildAt(int i, Node n){
this.childs[i] = n;
}
public Board getBoard(){
return this.board;
}
I think you got a wrong approach.
First of all, you're doing a loop and recursion, besides using a depth variable that has no meaning since you never check it's value either to end the recursion, or to know something about what you want to do.
The use a a dynamic function within the loop itself is not quite good, since the iteration should be well defined from the beginning of the loop.
i is just useless in your context.
So if I understand your code, a problematic case would be a case where there is 3 empty squares and 4 non empty squares since you would iterate i from 0 to 3 and do nothing but incrementing j from 0 to 3 then exit because i would have reach 3.
Of course I may be mistaken on some points because I don't know what tree is, from where did it come from? is it related to n? What is a board.
I hope my contribution can help you and I encourage you to post more details to clarify the holes and enable me to help you a bit more.