-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTreeTester.java
257 lines (231 loc) · 9.47 KB
/
TreeTester.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import java.io.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* Framework to test the Binary Space Partitioning implementations.
* <p>
* There should be no need to change this for task A.
* If you need to make changes for task B, please make a copy,
* then modify the copy for task B.
*
* @author Jeffrey Chan, 2016.
* @author Yongli Ren, 2019.
*/
public class TreeTester {
private static final String SEQUENTIAL_TREE = "seqtree";
private static final String LINKED_TREE = "linktree";
private static final String SAMPLE = "sample";
/**
* Print help/usage message.
*/
private static void usage() {
String progName = TreeTester.class.getSimpleName();
System.err.println(progName + ": <implementation> [-f <filename to load tree>] [filename to print results]");
System.err.printf("<implementation> = <%s | %s | %s>%n", SEQUENTIAL_TREE, LINKED_TREE, SAMPLE);
System.err.println("If the optional output filename is specified, then non-interactive mode will be used and respective output is written to that file. Otherwise interactive mode is assumed and output is written to System.out.");
System.exit(1);
} // end of usage
/**
* Checks the number of specified tokens
*
* @param tokens the given tokens
* @param expectedNum the expected length of the given tokens
*/
private static void verifyTokens(String[] tokens, int expectedNum) {
if (tokens.length != expectedNum) {
throw new IllegalArgumentException("incorrect number of tokens.");
}
}
/**
* Process the operation commands coming from inReader,
* and updates the tree according to the operations.
*
* @param inReader Input reader where the operation commands are coming from.
* @param tree The tree which the operations are executed on.
* @param writer Where to output the results.
* @throws IOException If there is an exception to do with I/O.
*/
public static void processOperations(
BufferedReader inReader,
BSPTree<String> tree,
PrintWriter writer
) throws IOException {
String line;
int lineNum = 1;
boolean bQuit = false;
// continue reading in commands until we either receive the quit signal
// or there are no more input commands
while (!bQuit && (line = inReader.readLine()) != null) {
String[] tokens = line.split(" ");
// check if there is at least an operation command
if (tokens.length < 1) {
System.err.println(lineNum + ": not enough tokens.");
lineNum++;
continue;
}
String command = tokens[0];
try {
// determine which operation to execute
switch (command.toUpperCase()) {
// set root node
case "RN":
verifyTokens(tokens, 2);
tree.setRootNode(tokens[1]);
break;
// split node
case "SP":
verifyTokens(tokens, 4);
tree.splitNode(tokens[1], tokens[2], tokens[3]);
break;
// find node
case "FN":
verifyTokens(tokens, 2);
writer.println(tree.findNode(tokens[1]));
break;
// find parent node
case "FP":
verifyTokens(tokens, 2);
writer.println(tree.findParent(tokens[1]));
break;
// find children nodes
case "FC":
verifyTokens(tokens, 2);
writer.println(tree.findChildren(tokens[1]));
break;
// print all the nodes in the "preorder" traversal
case "TP":
tree.printInPreorder(writer);
break;
// print all the nodes in the "inorder" traversal
case "TI":
tree.printInInorder(writer);
break;
// print all the nodes in the "postorder" traversal
case "TS":
tree.printInPostorder(writer);
break;
// quit
case "Q":
bQuit = true;
break;
default:
System.err.println(lineNum + ": Unknown command.");
} // end of switch()
} catch (IllegalArgumentException e) {
System.err.println(lineNum + ": " + e.getMessage());
}
lineNum++;
}
} // end of processOperations()
/**
* Creates new {@link PrintWriter}.
*
* @param filename the output filename
* @return new {@link PrintWriter}
* @throws IOException If there is an exception to do with I/O.
*/
private static PrintWriter createWriter(String filename) throws IOException {
OutputStream out = (filename == null || filename.trim().isEmpty())
? System.out
: new FileOutputStream(filename);
return new PrintWriter(out, true);
}
/**
* Main method. Determines which implementation to test and processes command line arguments.
*/
public static void main(String[] args) {
// parse command line options
String fileOpt = "f";
OptionParser parser = new OptionParser(fileOpt + ":");
OptionSet options = parser.parse(args);
String inputFilename = null;
// -f <inputFilename> specifies the file that contains nodes information to construct the initial tree with.
if (options.has(fileOpt)) {
if (options.hasArgument(fileOpt)) {
inputFilename = (String) options.valueOf(fileOpt);
} else {
System.err.printf("Missing filename argument for -%s option.\n", fileOpt);
usage();
}
}
// non option arguments
List<String> remainArgs = options.nonOptionArguments()
.stream().map(o -> (String) o)
.collect(Collectors.toList());
// check number of non-option command line arguments
int maxArgs = 2, minArgs = 1;
if (remainArgs.size() > maxArgs || remainArgs.size() < minArgs) {
System.err.println("Incorrect number of arguments.");
usage();
}
// parse non-option arguments
String implementationType = remainArgs.get(0);
String outFilename = null;
// output files
if (remainArgs.size() == maxArgs) {
outFilename = remainArgs.get(1);
System.out.println("Non-interactive mode.");
} else {
System.out.println("Interactive mode.");
}
// determine which implementation to test
BSPTree<String> tree;
switch (implementationType) {
case SEQUENTIAL_TREE:
tree = new SequentialRepresentation<>();
break;
case LINKED_TREE:
tree = new LinkedRepresentation<>();
break;
case SAMPLE:
tree = new SampleImplementation<>();
break;
default:
System.err.println("Unknown implementation type.");
usage();
return;
}
// if file specified, then load file
if (inputFilename != null) {
try (BufferedReader reader = new BufferedReader(new FileReader(inputFilename))) {
String line;
String delimiter = "[ \t,]+";
String[] tokens;
String srcLabel, leftChild, rightChild;
boolean hasRoot = false;
while ((line = reader.readLine()) != null) {
tokens = line.split(delimiter);
if (!hasRoot) {
verifyTokens(tokens, 1);
tree.setRootNode(tokens[0]);
hasRoot = true;
continue;
}
verifyTokens(tokens, 3);
srcLabel = tokens[0];
leftChild = tokens[1];
rightChild = tokens[2];
tree.splitNode(srcLabel, leftChild, rightChild);
}
} catch (FileNotFoundException ex) {
System.err.println("File " + args[2] + " not found.");
} catch (IOException ex) {
System.err.println("Cannot open file " + args[2]);
} catch (Exception ex) {
System.err.println(ex.getMessage());
}
}
// construct in and output streams/writers/readers, then process each operation.
try (BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in))) {
// output to writer
PrintWriter writer = createWriter(outFilename);
// process the operations
processOperations(inReader, tree, writer);
writer.close();
} catch (IOException e) {
System.err.println(e.getMessage());
}
} // end of main()
} // end of class TreeTester