/* Java application whose purpose is to test the methods in the ** GraphOutDeg1Plus class via interaction with a user. ** If there is a single command-line argument, it is taken to be ** the name of a file in which an outdegree-1 graph is described. ** If there are multiple command-line arguments, they are taken to form ** the description of an outdegree-1 graph. In either case, that ** description is put into a form (namely, an array) that is fed to ** the constructor of GraphOutDeg1Plus. Thereafter, the user can ** enter commands that result in the observer methods of that class ** being called. ** ** Author: R. McCloskey ** Date: October 2022 */ import java.util.Scanner; import java.io.File; import java.io.FileNotFoundException; public class OutDeg1GraphTester { private static OutDeg1GraphPlus graph; private static int[] graphDescrip; public static void main(String[] args) throws FileNotFoundException { graphDescrip = graphDescription(args); graph = new OutDeg1GraphPlus(graphDescrip); test(graph); System.out.println("Goodbye."); } /* Returns an integer array that serves as a description of an outdegree-1 ** graph. If the given array (args[]) of Strings has only one element, it ** is taken to be the name of a file containing a plain text version of such ** a description. If the given array has multiple elements, the concatenation ** of those elements (with spaces added in between) are taken to be a such a ** description. The expected format for a plain text description of an ** outdegree-1 graph is exemplified by the following, which describes a ** graph of six nodes (as indicated by the first numeral) in which the ** single outgoing edge from nodes 0, 1, ..., 5 go to nodes 2, 0, 4, 2, 5, ** and 1, respectively. ** +--------------+ ** |6 2 0 4 2 5 1 | ** +--------------+ */ private static int[] graphDescription(String[] args) throws FileNotFoundException { Scanner input = null; // Attach 'input' to the intended input source. if (args.length == 1) { try { input = new Scanner(new File(args[0])); } catch (FileNotFoundException e) { println("No file named " + args[0] + " was found"); println("Program aborting..."); System.exit(0); } } else { input = new Scanner(concatenate(args)); } // Translate the sequence of tokens into an integer array and return it. int numNodes = input.nextInt(); int[] arcs = new int[numNodes]; for (int i=0; i != numNodes; i++) { arcs[i] = input.nextInt(); } return arcs; } /* Returns the string resulting from concatenating the elements of the ** given array, with a space inserted between consecutive elements. */ private static String concatenate(String[] ary) { StringBuilder s = new StringBuilder(); for (int i=0; i != ary.length; i++) { s.append(ary[i] + ' '); } return s.toString(); } private static void printHelp() { println("Available commands:"); println("-------------------"); println(" Q (Quit)"); println(" H (Help)"); println(" G (display Graph)"); println(" R (Reset: start over again with same graph)"); println(" C v (does node #v lie on a Cycle?)"); println(" D v (what is the Distance from node #v to a cycle)"); println(" S v w (are nodes #v and #w in the Same component?)"); println(" N (what is the Number of components in the graph?)"); // println(" W (how much Work has been done (since last reset)?)"); } private static void test(OutDeg1GraphPlus g) { printHelp(); printGraph(); Scanner keyboard = new Scanner(System.in); boolean keepGoing = true; while (keepGoing) { try { System.out.print("\n> "); String commandLine = keyboard.nextLine(); if (commandLine.length() != 0) { keepGoing = performCommand(commandLine); } } catch (Exception e) { e.printStackTrace(System.out); } } } /* Performs the given command and returns true unless that was the ** Quit command (in which false is returned). */ private static boolean performCommand(String commandLine) { boolean result = true; Scanner commandScanner = new Scanner(commandLine); char command = commandScanner.next().toUpperCase().charAt(0); if (command == 'Q') { result = false; } else if (command == 'H') { printHelp(); } else if (command == 'G') { printGraph(); } else if (command == 'R') { resetGraph(); } else if (command == 'C') { int u = readNodeNum(commandScanner); graph.resetWorkMeasure(); reportOnCycle(u); reportWork(); } else if (command == 'D') { int u = readNodeNum(commandScanner); graph.resetWorkMeasure(); reportDistToCycle(u); reportWork(); } else if (command == 'S') { int v = readNodeNum(commandScanner); int w = readNodeNum(commandScanner); graph.resetWorkMeasure(); reportInSameComponent(v,w); reportWork(); } else if (command == 'N') { graph.resetWorkMeasure(); reportNumComponents(); reportWork(); } else if (command == 'W') { reportWork(); } else { println("Unrecognized command..."); } return result; } /* Reads an integer from the given Scanner; if it is not a legal ** node identifier (in range [0..graph.numNodes()), zero is returned. */ private static int readNodeNum(Scanner scanner) { int nodeNum = 0; if (scanner.hasNextInt()) { nodeNum = scanner.nextInt(); if (nodeNum < 0 || nodeNum >= graph.numNodes()) { System.out.printf("%d is not a valid node ID; replacing with zero\n", nodeNum); nodeNum = 0; } } else { String str = scanner.next(); System.out.printf("\"%s\" is not a valid node ID; replacing by zero\n", str); } return nodeNum; } private static void printGraph() { println("Graph:"); println(graph.toString()); } /* Resets the graph, so that any information gathered during earlier ** calls to its observer methods is lost. */ private static void resetGraph() { graph = new OutDeg1GraphPlus(graphDescrip); } private static void reportOnCycle(int u) { boolean onCycle = graph.onCycle(u); println("Node " + u + (onCycle ? " LIES" : " DOES NOT LIE") + " on a cycle."); } private static void reportDistToCycle(int u) { int dist = graph.distanceToCycle(u); println("Distance from node " + u + " to a cycle is " + dist); } private static void reportInSameComponent(int v, int w) { boolean inSameComp = graph.inSameComponent(v,w); println("Nodes " + v + " and " + w + " do " + (inSameComp ? "" : " NOT ") + "lie in the same component."); } private static void reportNumComponents() { int numComp = graph.numComponents(); System.out.printf("The graph has %d components.\n", numComp); } private static void reportWork() { int work = graph.workMeasure(); println("Measure of work performed: " + work); } /* Surrogate for System.out.println(). */ private static void println(String s) { System.out.println(s); } }