1

I am presenting my source code for this issue because it has become frustrating to me that i can not do a simple system out print within the TrainsTest class. as you can see i am having the issue with printing the vaule out in TrainsTest class for the following methods;

public void testDistanceBetween_ABC public void testDistanceBetween_AD public void testDistanceBetween_ADC public void testDistanceBetween_AEBCD public void testDistanceBetween_AED public void numRoutesWithin_CC30 public void testEquals

any help will be appreciated! Thank you!

Below is my node class


package com.utsavized.trains;

public class Node {
public String name;
public boolean visited;

public Node(String name) {
    this.name = name;
    this.visited = false;
}

@Override
public boolean equals(Object b) {
    if (b == null || b.getClass() != getClass()) {
        return false;
    }
    Node bx = (Node)b;
    return this.name.equals(bx.name);
}

@Override
public int hashCode() {
    if(this.name == null) return 0;
    return this.name.hashCode();
}
}

Below is my Edge class


public class Edge {

public Node origin;

public Node destination;

public int weight;

public Edge next;

public Edge(Node origin, Node destination, int weight) {
    this.origin         = origin;
    this.destination    = destination;
    this.weight         = weight;
    this.next       = null;
}

public Edge next(Edge edge) {
    this.next = edge;
    return this;
}
}

Below is my Routes class


import java.util.ArrayList;
import java.util.Hashtable;

public class Routes {
public Hashtable<Node, Edge> routeTable;

public Routes() {
    this.routeTable = new Hashtable<Node, Edge>();
}


public int distanceBetween(ArrayList<Node> cities) throws Exception {
    /*There is no distance between
     * no cities or 1 city*/
    if(cities.size() < 2)
        return 0;
    int distance, depth, i;
    distance = depth = i = 0;

    /* For each city in the list,
     * we check if entry exists in our
     * hash table.
     */
    while(i < cities.size() - 1) {
        if(this.routeTable.containsKey(cities.get(i))) {
            Edge route = this.routeTable.get(cities.get(i));
            /*If key exists, we check if route from key to next
             * city exists. We add the distance, and maintain a
             * depth count
             */
            while(route != null) {
                if(route.destination.equals(cities.get(i + 1))) {
                    distance += route.weight;
                    depth++;
                    break;
                }
                route = route.next;
            }
        }
        else
            throw new Exception("NO SUCH ROUTE");
        i++;
    }
    /*If edge depth is not equal to vertex - 1,
     * then it is safe to assume that one ore more
     * routes do not exist
     */
    if(depth != cities.size() - 1)
        throw new Exception("NO SUCH ROUTE");

    return distance;
}

/*
 * Number of stops;
 * Wrapper for recursive function
 */
public int numStops(Node start, Node end, int maxStops) throws Exception{
    //Wrapper to maintain depth of traversal
    return findRoutes(start, end, 0, maxStops);
}

/*
 * Finds number of stops from start to end,
 * with a maximum of maxStops and the depth
 * limit.
 */
private int findRoutes(Node start, Node end, int depth, int maxStops) throws Exception{
    int routes = 0;
    //Check if start and end nodes exists in route table
    if(this.routeTable.containsKey(start) && this.routeTable.containsKey(end)) {
        /*
         * If start node exists then traverse all possible
         * routes and for each, check if it is destination
         * If destination, and number of stops within 
         * allowed limits, count it as possible route.
         */
        depth++;
        if(depth > maxStops)        //Check if depth level is within        limits
            return 0;
        start.visited = true;       //Mark start node as visited
        Edge edge = this.routeTable.get(start);
        while(edge != null) {
            /* If destination matches, we increment route
             * count, then continue to next node at same depth
             */
            if(edge.destination.equals(end)) {
                routes++;
                edge = edge.next;
                continue;
            }
            /* If destination does not match, and
             * destination node has not yet been visited,
             * we recursively traverse destination node
             */
            else if(!edge.destination.visited) {
                routes += findRoutes(edge.destination, end, depth,                                                        maxStops);
                depth--;
            }
            edge = edge.next;
        }
    }
    else
        throw new Exception("NO SUCH ROUTE");

    /*
     * Before exiting this recursive stack level,
     * we mark the start node as visited.
     */
    start.visited = false;
    return routes;
}

/*
 * Shortest route;
 * Wrapper for recursive function
 */
public int shortestRoute(Node start, Node end) throws Exception {
    //Wrapper to maintain weight
    return findShortestRoute(start, end, 0, 0);

}

/*
 * Finds the shortest route between two nodes
 */
private int findShortestRoute(Node start, Node end, int weight, int shortestRoute) throws Exception{
    //Check if start and end nodes exists in route table
    if(this.routeTable.containsKey(start) && this.routeTable.containsKey(end)) {
        /*
         * If start node exists then traverse all possible
         * routes and for each, check if it is destination
         */
        start.visited = true;       //Mark start node as visited
        Edge edge = this.routeTable.get(start);
        while(edge != null) {
            //If node not already visited, or is the destination, increment weight
            if(edge.destination == end || !edge.destination.visited)
                weight += edge.weight;

            /* If destination matches, we compare
             * weight of this route to shortest route
             * so far, and make appropriate switch
             */
            if(edge.destination.equals(end)) {
                if(shortestRoute == 0 || weight < shortestRoute)
                    shortestRoute = weight;
                start.visited = false;
                return shortestRoute;           //Unvisit node and return shortest route
            }
            /* If destination does not match, and
             * destination node has not yet been visited,
             * we recursively traverse destination node
             */
            else if(!edge.destination.visited) {
                shortestRoute = findShortestRoute(edge.destination, end, weight, shortestRoute);
                //Decrement weight as we backtrack
                weight -= edge.weight;
            }
            edge = edge.next;
        }
    }
    else
        throw new Exception("NO SUCH ROUTE");

    /*
     * Before exiting this recursive stack level,
     * we mark the start node as visited.
     */
    start.visited = false;
    return shortestRoute;

}

/*
 * Shortest route;
 * Wrapper for recursive function
 */
public int numRoutesWithin(Node start, Node end, int maxDistance) throws Exception {
    //Wrapper to maintain weight
    return findnumRoutesWithin(start, end, 0, maxDistance);
}

/*
 * Finds the shortest route between two nodes
 */
private int findnumRoutesWithin(Node start, Node end, int weight, int maxDistance) throws Exception{
    int routes = 0;
    //Check if start and end nodes exists in route table
    if(this.routeTable.containsKey(start) && this.routeTable.containsKey(end)) {
        /*
         * If start node exists then traverse all possible
         * routes and for each, check if it is destination
         */
        Edge edge = this.routeTable.get(start);
        while(edge != null) {
            weight += edge.weight; 
            /* If distance is under max, keep traversing
             * even if match is found until distance is > max
             */
            if(weight <= maxDistance) {
                if(edge.destination.equals(end)) {
                    routes++;
                    routes += findnumRoutesWithin(edge.destination, end, weight, maxDistance);
                    edge = edge.next;
                    continue;
                }
                else {
                    routes += findnumRoutesWithin(edge.destination, end, weight, maxDistance);
                    weight -= edge.weight;  //Decrement weight as we backtrack
                }
            }
            else 
                weight -= edge.weight;

            edge = edge.next;
        }
    }
    else
        throw new Exception("NO SUCH ROUTE");

    return routes;

}   

}

Below is my TrainsTest class


    package com.utsavized.trains;



    import static org.junit.Assert.*;

    import java.util.ArrayList;
    import java.util.stream.Collectors;

    import org.junit.BeforeClass;
    import org.junit.Test;

    public class TrainsTest {
static Routes graph;
static Node a, b, c, d, e;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
    graph = new Routes(); //Build graph

    a = new Node("A");
    b = new Node("B");
    c = new Node("C");
    d = new Node("D");
    e = new Node("E");

    /*Input given in programming challenge
    Graph: AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7*/
    graph.routeTable.put(a, new Edge(a, b, 5).next(new Edge(a, d, 5).next(new Edge(a, e, 7))));
    graph.routeTable.put(b, new Edge(b, c, 4));
    graph.routeTable.put(c, new Edge(c, d, 8).next(new Edge(c, e, 2)));
    graph.routeTable.put(d, new Edge(d, c, 8).next(new Edge(d, e, 6)));
    graph.routeTable.put(e, new Edge(e, b, 3));
}

@Test
public void testDistanceBetween_ABC() throws Exception {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(b);
    route.add(c);
    //System.out.println(a);
    assertEquals(9, graph.distanceBetween(route));      

}

@Test
public void testDistanceBetween_AD() throws Exception {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(d);
    assertEquals(5, graph.distanceBetween(route));
}

@Test
public void testDistanceBetween_ADC() throws Exception  {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(d);
    route.add(c);
    assertEquals(13, graph.distanceBetween(route));
}

@Test
public void testDistanceBetween_AEBCD() throws Exception  {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(e);
    route.add(b);
    route.add(c);
    route.add(d);
    assertEquals(22, graph.distanceBetween(route));
}

@Test(expected=Exception.class)
public void testDistanceBetween_AED() throws Exception  {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(e);
    route.add(d);
    assertEquals(-1, graph.distanceBetween(route));
}

@Test
public void testNumStops_CC3() throws Exception {
    int numStops = graph.numStops(c, c, 3);
    assertEquals(2, numStops);
}

@Test
public void testNumStops_AC4() throws Exception {
    int numStops = graph.numStops(a, c, 4);
    assertEquals(4, numStops);
}

@Test
public void testShortestRoute_AC() throws Exception {
    int shortestRoute = graph.shortestRoute(a, c);
    assertEquals(9, shortestRoute);
    System.out.println(shortestRoute);  
}

@Test
public void testShortestRoute_BB() throws Exception {
    int shortestRoute = graph.shortestRoute(b, b);
    assertEquals(9, shortestRoute);
}

@Test
public void numRoutesWithin_CC30() throws Exception {
    int numRoutesWithin = graph.numRoutesWithin(c, c, 30);
    assertEquals(7, numRoutesWithin);
}

@Test
public void testEquals() {
    Node a1 = new Node("A");
    Node a2 = new Node("A");
    Node b = new Node("B");

    assertEquals(true, a1.equals(a2));
    assertEquals(false, a1.equals(b));
    assertEquals(true, (new Node("Test").equals(new Node("Test"))));
}

}

Hi I am trying to print the value for a, b and c. As you can see I am using System out println on route but it is not outputting nothing. Is there a way to output the outcome without too much modification towards the method?

public void testDistanceBetween_ADC() throws Exception  {
    ArrayList<Node> route = new ArrayList<Node>(); 
    route.add(a);
    route.add(d);
    route.add(c);
    assertEquals(13, graph.distanceBetween(route));
    System.out.println(route);
}

I am not sure if I should be outputting the variable 'route' or if I need to add another small method withing this. Any help will be appreciated I know it is a simple thing I am trying to do but for some reason it is not working for me.

many thanks!!

  • does the test run successfully? In case it fails it'll end on the assertEqual method skipping the System.out.println ... just to be sure – Gerald Mücke May 11 '16 at 15:27
  • the test runs successfully but outputs: com.utsavized.trains.Node@41 is there a way to output this method? – user3306763 May 11 '16 at 15:36

2 Answers2

0

In Edit to my original answer, it seems that there is an error in your inner while-loop of your distanceBetween-method.

In case of a route containing the nodes A, B, C, it will compute Node A, get the Edge to Node B and then in the inner loop it will sum up the weight of the edge. After that, you call break. This will break both while-loops

If you really want to break the loops, you should take a look how to label loops in java: Labeled Loops

I do not prefer to work with labeled-loops because it sometimes gets a bit messy. In your case, just use:

if(route.destination.equals(cities.get(i + 1))) {
                distance += route.weight;
                depth++;
} else {
            route = route.next;
}

//do further (error) handling

At the moment, it is not clear what you want to do with the depth-variable. In your implementation, it will always throw an Exception because you break your loops after finding the first route, then sum up depth and then you check if depth has a specific size. So at routes greater than 2 nodes this exception will always fly.

For a minimal example, it may be useful to work only with the distance:

       //...
        Edge route = this.routeTable.get(cities.get(i));
        int newDistance = distance;
        /*If key exists, we check if route from key to next
         * city exists. We add the distance, and maintain a
         * depth count
         */
        while(route != null) {
            if(route.destination.equals(cities.get(i + 1))) {
                newDistance += route.weight;
               // depth++;
            } else {
                route = route.next;
            }
        }

        if(newDistance == distance) {
             //the distance didnt change - it seems there was no route found, throw Exception or expand the graph or whatever
        } else {
             distance = newDistance; //now you have the distance for the next loop-run
        }
Community
  • 1
  • 1
Supahupe
  • 515
  • 2
  • 11
  • could you give an example on how it would look like with using the above example? – user3306763 May 11 '16 at 15:13
  • i tried it and still did not work, it started to frustrate me. i know i am missing something tiny. it always the case! – user3306763 May 11 '16 at 15:37
  • Please show your Node-class and also the graph-class and what you did in your toString()-method – Supahupe May 11 '16 at 15:39
  • package com.utsavized.trains; public class Node { public String name = null; public boolean visited; int id = 0; public Node(String name, int id) { this.name = name; this.visited = false;} public boolean equals(Object b) { if (b == null || b.getClass() != getClass()) { return false;} Node bx = (Node)b; return this.name.equals(bx.name);} public int hashCode() { if(this.name == null) return 0; return this.name.hashCode();} public String toString() { return "Node: [name:"+this.name+",id:"+this.id+"]"; }} – user3306763 May 11 '16 at 15:46
  • Is this the whole class? Because I cant find any attributes with seem to make sense for calculating a distance between the nodes. Did you wrote the Graph and its nodes on your own or is it an external library or something like that as Gerald Mücke asked? – Supahupe May 11 '16 at 15:49
  • i am unable to add the whole class the comment section will not allow me – user3306763 May 11 '16 at 15:56
  • could we chat via email for us to resolve this issue that i am facing please? – user3306763 May 11 '16 at 16:09
  • Hi Stupahupe, Hope you are well? i took your advice and amended my original post. i present the full source code. I'd appreciate it if you could take a look and see why i can not system out ptrinln in my trainstest class. sorry for being such a pain. – user3306763 May 12 '16 at 09:07
  • Hi, IMHO there may be an implementation error in your distanceBetween-Method. Your while loop goes over cities and takes and edge connected to the node. Then you check if your edge is connected to the next node of your root. If its true, you sum up deepth and after that, you break. I think you just want to break the inner while-loop because at the first hit of for example ABC, it will end already at B. I will refine my oringinal answer – Supahupe May 12 '16 at 10:35
  • Thank you for looking into this, i looked at your edited solution however it throwing me more errors, is there a way to keep what i have and just print out the value within the trainstest class? – user3306763 May 12 '16 at 11:28
  • the reason why i am asking is because if you look at the method public void testShortestRoute_AC() in TrainsTest, i am using system.out.println(a) and this is working for me and outputting the answer. just wondering if this can be done on the other methods. – user3306763 May 12 '16 at 11:29
  • Sure you can output it this way. Just implement the toString-method to Node and then you can call System.out.println(a.toString()) (where a is an instance of Node) – Supahupe May 12 '16 at 11:31
  • When copying your code if(route.destination.equals(cities.get(i + 1))) { distance += route.weight; depth++; } else { route = route.next; } in my distanceBetween method it is giving me errors on the word 'route' the error message is '- route cannot be resolved to a variable' – user3306763 May 12 '16 at 13:03
0

You have 3 options

Implement toString()

In case the Node class is part of your sources, just add toString method

public String toString(){
    return name;
}

Override Node

In case Node class is part of an external library but not final, you could override the node and implement toString() use the overriden class instead as supahupe suggested.

Use Stream & map for display

In case you can't override node as Supahupe suggested, you could use the publicly accessible name field and map that to a new list of Strings and print this out

System.out.println(route.stream().map(n -> n.name).collect(Collectors.toList()));

Alternatively you could create a decorator class for your node for the sole purpose of printing it out nicely, aproach would be the same as for stream

...stream().map(n -> new NodeDecorator(n))...
Gerald Mücke
  • 10,724
  • 2
  • 50
  • 67