Skip to content

Commit 664d1d5

Browse files
committed
Initial Commit
0 parents commit 664d1d5

File tree

6 files changed

+475
-0
lines changed

6 files changed

+475
-0
lines changed

.classpath

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" path="src"/>
4+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
5+
<classpathentry kind="output" path="bin"/>
6+
</classpath>

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin
2+
*.class

.project

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>Truth Table Generator</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.jdt.core.javabuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.jdt.core.javanature</nature>
16+
</natures>
17+
</projectDescription>
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
package discreteMath;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Queue;
6+
7+
public class ExpressionTree
8+
{
9+
public Node root;
10+
public List<Node> leafs;
11+
12+
private List<Character> evaluationResults;// The results of the last call to evaluate() on root.
13+
private List<String> evaluationOrder;// The order that the nodes were evaluated.
14+
15+
/**
16+
* Builds a binary expression tree representing the expression to be evaluated.
17+
* @param initialExpression The expression to build the tree from.
18+
*/
19+
public ExpressionTree(String initialExpression)
20+
{
21+
leafs = new ArrayList<Node>();
22+
evaluationOrder = new ArrayList<String>();
23+
root = new Node(initialExpression);
24+
}
25+
26+
/**
27+
* A node on the binary expression tree.
28+
*/
29+
class Node
30+
{
31+
char operand;
32+
Node left;
33+
Node right;
34+
35+
/**
36+
* Creates a node on the binary expression tree, from the input expression.
37+
* If the input expression is not in base form,
38+
* it recursively creates child nodes for the left and right branches.
39+
*
40+
* Also keeps track of the order that nodes are created in, since this is useful information
41+
* if using this tree to generate a truth table.
42+
*/
43+
Node(String expression)
44+
{
45+
String leftExpression;
46+
String rightExpression;
47+
String[] elements;
48+
49+
// Divide the original expression into individual elements
50+
elements = parseExpression(expression);
51+
// Retrieve the individual parsed elements as the elements of an array (e.g. left, middle, right)
52+
leftExpression = elements[0];
53+
this.operand = elements[1].charAt(0);
54+
rightExpression = elements[2];
55+
// If not the base case, recurse again for left and right branches
56+
if (leftExpression != null)
57+
{
58+
this.left = new Node(leftExpression);
59+
}
60+
if (rightExpression != null)
61+
{
62+
this.right = new Node(rightExpression);
63+
}
64+
// Determine if this Node is terminal or has branches
65+
if (leftExpression == null && rightExpression == null)
66+
{
67+
// Keep track of the leafs so that class users can modify the leaf nodes or set their values.
68+
leafs.add(this);
69+
}
70+
evaluationOrder.add(this.toString());
71+
}
72+
73+
public String toString()
74+
{
75+
String result = "";
76+
result += (left == null) ? ("") : ("(" + left.toString() + ")");
77+
result += operand;
78+
result += (right == null) ? ("") : ("(" + right.toString() + ")");
79+
return result;
80+
}
81+
82+
void setOperand(char newOperand)
83+
{
84+
this.operand = newOperand;
85+
}
86+
}
87+
88+
/**
89+
* Returns an expression parsed into three parts:
90+
* The left branch, the operand, and the right branch, respectively,
91+
* in the form of a 3 element array of Strings.
92+
*
93+
* @param expression The expression to parse.
94+
* @return A 3 element array of Strings with the parsed elements.
95+
*/
96+
private String[] parseExpression(String expression)
97+
{
98+
String[] result = new String[3];
99+
String alphabet = "abcdefghijklmnopqrstuvwxyz";
100+
101+
// Begin by checking the case of an isolated variable.
102+
if (alphabet.contains(String.valueOf(expression.charAt(0))))
103+
{
104+
if (expression.length() == 1)
105+
{
106+
result[0] = null;
107+
result[1] = expression;
108+
result[2] = null;
109+
return result;
110+
}
111+
else
112+
{
113+
// I should really throw an exception here, but this is just a toy program.
114+
System.err.println("Syntax Error!" + "\n" + "Exiting Program.");
115+
System.exit(-1);
116+
}
117+
}
118+
if (expression.startsWith("("))
119+
{
120+
// Determine if the expression has unneeded parentheses...
121+
int count = 1; // The number of unmatched open parentheses.
122+
int position;
123+
for (position = 1; position < expression.length(); position++)
124+
{
125+
if (expression.charAt(position) == '(')
126+
{
127+
count++;
128+
}
129+
else if (expression.charAt(position) == ')')
130+
{
131+
count--;
132+
}
133+
// If we reach the end of the original open parentheses
134+
if (count == 0)
135+
{
136+
// check if there is another set after...
137+
if (expression.substring(position+1).contains("("))
138+
{
139+
result[0] = expression.substring(0, position + 1);
140+
result[1] = String.valueOf(expression.charAt(position+1));
141+
result[2] = expression.substring(position+2);
142+
return result;
143+
}
144+
else
145+
{
146+
// Remove the unneeded parentheses and recurse...
147+
expression = expression.substring(1, expression.length() - 1);
148+
return parseExpression(expression);
149+
}
150+
}
151+
}
152+
}
153+
else if(expression.startsWith("!"))
154+
{
155+
// If in the form of !var
156+
if(alphabet.contains(String.valueOf(expression.charAt(1))))
157+
{
158+
result[0] = null;
159+
result[1] = "!";
160+
result[2] = expression.substring(1);
161+
return result;
162+
}
163+
// If in the form of !(Expression)
164+
else if((expression.charAt(1) == '(') && (expression.charAt(expression.length() - 1) == ')'))
165+
{
166+
result[0] = null;
167+
result[1] = "!";
168+
result[2] = expression.substring(1);
169+
}
170+
else
171+
{
172+
// I should really throw an exception here, but this is just a toy program.
173+
System.err.println("Syntax Error!" + "\n" + "Exiting Program.");
174+
System.exit(-1);
175+
}
176+
}
177+
return result;
178+
}
179+
180+
/**
181+
* Returns the boolean result of the expression starting from the passed node.
182+
*
183+
* Typical use would to pass the root node of the tree in the first call; the method will then
184+
* recursively iterate through the tree until reaching the base case, and then return it's results up
185+
* the tree, evaluating as it goes.
186+
*
187+
* This method also stores it's results in evaluationResults, because we need to know the results
188+
* of each sub-expression within the tree if we want to build a truth table.
189+
*/
190+
public boolean evaluate(Node node)
191+
{
192+
// Reset the evaluation results list every time root is passed.
193+
if (node == this.root)
194+
{
195+
evaluationResults = new ArrayList<Character>();
196+
}
197+
// First, check if we already know the answer...
198+
if (node.operand == 'T')
199+
{
200+
evaluationResults.add(Boolean.toString(true).toUpperCase().toCharArray()[0]);
201+
return true;
202+
}
203+
else if (node.operand == 'F')
204+
{
205+
evaluationResults.add(Boolean.toString(false).toUpperCase().toCharArray()[0]);
206+
return false;
207+
}
208+
// Otherwise, continue recursion.
209+
boolean result;
210+
switch (node.operand)
211+
{
212+
// Note that we have to AVOID short-circuit evaluation here by using | and & instead of || and &&
213+
case '&': // AND
214+
result = (evaluate(node.left) & evaluate(node.right));
215+
break;
216+
case '|': // OR
217+
result = (evaluate(node.left)) | (evaluate(node.right));
218+
break;
219+
case '!': // NOT
220+
result = !(evaluate(node.right));
221+
break;
222+
default:
223+
// Should never reach here.
224+
result = false; // Default value
225+
break;
226+
}
227+
evaluationResults.add(Boolean.toString(result).toUpperCase().toCharArray()[0]);
228+
return result;
229+
}
230+
231+
/**
232+
* When passed a Queue of Operands, this iterates throught the list of leaf-level nodes in the tree
233+
* and sets the values of their operands from the ones in the queue.
234+
*/
235+
public void setLeafOperands(Queue<Character> operands)
236+
{
237+
if (operands.size() == leafs.size())
238+
{
239+
for (Node leaf : leafs)
240+
{
241+
leaf.setOperand(operands.poll());
242+
}
243+
}
244+
else
245+
{
246+
// I should really throw an exception here, but this is just a toy program.
247+
System.err.println("Internal error!" + "\n" + "Exiting Program.");
248+
System.exit(-1);
249+
}
250+
}
251+
252+
public List<Character> getLastEvaluationResults()
253+
{
254+
return evaluationResults;
255+
}
256+
257+
258+
public List<String> getEvaluationOrder()
259+
{
260+
return evaluationOrder;
261+
}
262+
}

src/discreteMath/TruthTable.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package discreteMath;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* An object representing a truth table. Consists of a list of strings containing the column headers,
8+
* and a list of TruthTableRow objects, representing the rows of the table.
9+
*/
10+
public class TruthTable
11+
{
12+
private List<TruthTableRow> rows;
13+
private List<String> header;
14+
15+
/**
16+
* Standard constructor that just instantiates the fields of the class.
17+
*/
18+
public TruthTable()
19+
{
20+
this.rows = new ArrayList<TruthTableRow>();
21+
this.header = new ArrayList<String>();
22+
}
23+
24+
/**
25+
* An inner class of TruthTable representing a row within the table. Consists of a list of truth values
26+
* 'T' and 'F'.
27+
*/
28+
class TruthTableRow
29+
{
30+
List<Character> results = new ArrayList<Character>();
31+
32+
/**
33+
* Creates an instance of TruthTableRow. Must be provided as a parameter a list of Character objects
34+
* representing the truth vales of the row, in the order they are to put inserted into the table in.
35+
*
36+
* Once the row is created, it adds itself to a collection of rows in the outer class.
37+
*/
38+
TruthTableRow(List<Character> results)
39+
{
40+
this.results = results;
41+
rows.add(this);
42+
}
43+
44+
}
45+
46+
/**
47+
* Returns a string representing the table, in a format that can be printed to the console.
48+
*
49+
* Throws an error if the header strings are not initialized.
50+
*/
51+
public String toString()
52+
{
53+
if (header == null)
54+
{
55+
return "Error in TruthTable.toString()! Header is null!";
56+
}
57+
String result = "";
58+
for (String str : header)
59+
{
60+
result += str + " ";
61+
}
62+
result = result.substring(0, result.length() - 2);
63+
result += '\n';
64+
// For each row in the truth table...
65+
for (int row = 0; row < rows.size(); row++)
66+
{
67+
result += '\n';
68+
// For each element in the row...
69+
for (int value = 0; value < rows.get(row).results.size(); value++)
70+
{
71+
String spaces = "";
72+
while (spaces.length() < header.get(value).length())
73+
{
74+
spaces += " ";
75+
}
76+
result += rows.get(row).results.get(value) + spaces;
77+
}
78+
}
79+
return result;
80+
}
81+
82+
/**
83+
* Needed to initialize the header strings, since they are not known when the class is instatiated.
84+
* MUST be called before attempting to call toString() and print the table to the console.
85+
* @param header
86+
*/
87+
public void setHeader(List<String> header)
88+
{
89+
this.header = header;
90+
}
91+
}

0 commit comments

Comments
 (0)