diff --git a/spring24/week7/Challenge.java b/spring24/week7/Challenge.java new file mode 100644 index 0000000..1b9fcc4 --- /dev/null +++ b/spring24/week7/Challenge.java @@ -0,0 +1,391 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.List; + +public class Challenge { + + /** + * Read and store the contents of a file into a String or other type for further processing. + * + * @param f + * @return + */ + public String readFile(File f) { + if(f == null) return null; // Catch if the File does not exist. + StringBuilder sb = new StringBuilder(); + + try (Scanner s = new Scanner(f)){ + while(s.hasNextLine()) + sb.append(s.nextLine() + "\n"); + + return sb.toString(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + return ""; + } + + /** + * Challenge 1: + * Modify the split() method to account for multi-line input Strings. + * + * Given an input String, store each token in an ArrayList. + * + * A token is a single word, symbol, or character, surrounded on both sides by a space. + * + * @param s + * @return + */ + public ArrayList[] split(String s) { + ArrayList list = new ArrayList(); + String[] tokens = s.split(" "); + + for(int i = 0; i < tokens.length; i++) + list.add(tokens[i]); + + return null; // TODO: Return an ArrayList of tokens for each line in the input String. + } + + //Stack utility class to be used in challenge 2. + //This class is used to store the numbers and operations in the correct order to be evaluated. + private class Stack { + private Node head; + private Node tail; + + private int size; + + public Stack() { + head = null; + tail = null; + size = 0; + } + + public Stack(String value) { + head = new Node(value); + tail = null; + size = 1; + } + + public int size() { + return size; + } + + public void insert(String value) { + Node next = new Node(value); + if(head == null) { + head = next; + size++; + return; + } + + if(tail == null) { + tail = next; + head.next = tail; + size++; + return; + } + + tail.next = next; + tail = next; + tail.next = null; + size++; + } + + public void add(String value) { + Node next = new Node(value); + if(head == null) { + head = next; + size++; + return; + } + + if(tail == null) { + tail = next; + head.next = tail; + size++; + return; + } + + tail.next = next; + tail = next; + tail.next = null; + size++; + } + + public boolean isNotEmpty() { + return size > 0; + } + + public String pop() { + if(head == null) { + System.out.println("the stack has ran out of elements!"); + return "0"; + } + + Node next = head; + if(head.next == null) { + size --; + head = null; + tail = null; + return next.value; + } + + head = head.next; + size--; + + return next.value; + } + + public void print() { + Node current = head; + + while(current != null) { + System.out.println(current.value); + current = current.next; + } + } + + private class Node { + public String value; + public Node next; + + public Node(String value) { + this.value = value; + } + } + } + + /** + * Challenge 2: + * Modify the calculate(), evaluate(), and isOperation() methods to ensure they calculate the result using correct order of operations, + * with additional allowed operations. Additionally, modify the calculate() method to account for an input array of ArrayLists of tokens. + * + * Assume the input ArrayList of tokens are all valid integers, doubles, or operations. The output should only contain 4 decimal places, + * rounding up if the 5th place is greater than 5. + * + * The valid operations are: '+', '-', '*', '/', '%', '^', 'sin', 'cos', 'tan', 'log', 'ans', '(', and ')'. + * + * @param tokens + */ + public double[] calculate(ArrayList[] tokens) { + // TODO: Use the commented code below to calculate the result of the expressions in the input array of ArrayList of tokens. + /* + Stack numbers = new Stack(); + Stack operations = new Stack(); + double r = 0.0; + + for(int i = 0; i < tokens.size(); i++) { + String token = tokens.get(i); + + // Add the token to the number or operation stack. + if(!token.equals("(") && !token.equals(")")) { + if(isOperation(token)) operations.insert(token); + else numbers.insert(token); + + continue; + } + + // If the token is an opening parenthesis, evaluate the expression inside the matching closing parenthesis. + if(token.equals("(")) { + int deepness = 1; + int startIndex = i + 1; + + // Find the matching closing parenthesis. + for(int j = startIndex; j < tokens.size(); j++) { + if(tokens.get(j).equals("(")) deepness++; + if(tokens.get(j).equals(")")) deepness--; + + if(deepness == 0) { + // Evaluate the expression inside the parenthesis. + double result = calculate(new ArrayList(tokens.subList(startIndex, j))); + numbers.insert(Double.toString(result)); + + // Skip the rest of the parenthesis. + i = j; + break; + } + } + } + } + + // Evaluate the remaining operations and numbers. + while(numbers.isNotEmpty() && operations.isNotEmpty()) { + r = evaluate(numbers.pop(), operations.pop(), numbers.pop()); + numbers.insert(Double.toString(r)); + } + + // Return the result, rounded to 4 decimal places. + // return Math.round(r * 10000.0) / 10000.0; + */ + return null; // TODO: Return an array of the results of the expressions in the input array of ArrayList of tokens. + } + + /** + * Helper method for Challenge 2. + * + * Given a number, operation, and another number, evaluate the expression. + * + * @param a the first number. + * @param o the operation. + * @param b the second number. + * @return the result of the expression. + */ + private double evaluate(String a, String o, String b) { + double x = Double.parseDouble(a); + double y = Double.parseDouble(b); + char op = o.charAt(0); + + switch(op) { + case '+': + return x + y; + case '-': + return x - y; + case '*': + return x * y; + case '/': + return x / y; + case '%': + return x % y; + } + + return 0.0; + } + + /** + * Helper method for Challenge 2. + * + * Given a token, determine if it is an operation symbol. + * + * @param token the token to check. + * @return true if the token is an operation symbol, false otherwise. + */ + private boolean isOperation(String token) { + String[] allowedOperations = { + "+", + "-", + "*", + "/", + "%" + }; + + // Determine if the token is an operation symbol. + for(int i = 0; i < allowedOperations.length; i++) + if(token.equals(allowedOperations[i])) return true; + + return false; + } + + // Not used in the final solution, but just for your reference. + public boolean testReadFile(String s) { + return s.equals("( ( 5 + 5 ) * 5 * 3 ) / ( 5 * 3 + ( 8 * 4 ) )\n" + + "((5+5)*5*3)/(5*3+(8*4))\n" + + "sin((19*3)^4+1)\n" + + "cos((14*7)/14^2)\n" + + "tan(3^3/3*3)\n" + + "log(4739)+2\n" + + "(4.239*192.4)-15.327\n" + + "ans^2*3\n"); + } + + public boolean testChallenge1(ArrayList[] list) { + // The expected tokenized output of split() for the first ArrayList of tokens. + ArrayList expectedFirst = new ArrayList<>(); + expectedFirst.add("("); + expectedFirst.add("("); + expectedFirst.add("5"); + expectedFirst.add("+"); + expectedFirst.add("5"); + expectedFirst.add(")"); + expectedFirst.add("*"); + expectedFirst.add("5"); + expectedFirst.add("*"); + expectedFirst.add("3"); + expectedFirst.add(")"); + expectedFirst.add("/"); + expectedFirst.add("("); + expectedFirst.add("5"); + expectedFirst.add("*"); + expectedFirst.add("3"); + expectedFirst.add("+"); + expectedFirst.add("("); + expectedFirst.add("8"); + expectedFirst.add("*"); + expectedFirst.add("4"); + expectedFirst.add(")"); + expectedFirst.add(")"); + + // The expected tokenized output of split() for the last ArrayList of tokens. + ArrayList expectedLast = new ArrayList<>(); + expectedLast.add("ans"); + expectedLast.add("^"); + expectedLast.add("2"); + expectedLast.add("*"); + expectedLast.add("3"); + + if(expectedFirst.size() != list[0].size() || expectedLast.size() != list[list.length - 1].size()) { + System.out.println("Your solution for Challenge 2 does not correctly tokenize! You have too few or too many elements."); + return false; + } + + for(int i = 0; i < expectedFirst.size(); i++) + if(!(expectedFirst.get(i).equals(list[0].get(i)))) { + System.out.println("Your solution for Challenge 2 does not correctly tokenize! On the first line, expected " + expectedFirst.get(i) + " but got " + list[0].get(i) + " at index " + i + "."); + return false; + } + + for(int i = 0; i < expectedLast.size(); i++) + if(!(expectedLast.get(i).equals(list[list.length - 1].get(i)))) { + System.out.println("Your solution for Challenge 2 does not correctly tokenize! On the last line, expected " + expectedLast.get(i) + " but got " + list[list.length - 1].get(i) + " at index " + i + "."); + return false; + } + + return true; + } + + public boolean testChallenge2(double[] results) { + double[] expected = { + 3.1915, + 3.1915, + 0.9903, + 1.0, + 0.5095, + 5.6757, + 800.2566, + 1921231.878 + }; + + if(expected.length != results.length) { + System.out.println("Your solution for Challenge 2 does not correctly calculate! You have too few or too many elements."); + return false; + } + + for(int i = 0; i < expected.length; i++) + if(expected[i] != results[i]) { + System.out.println("Your solution for Challenge 2 does not correctly calculate! Expected " + expected[i] + " but got " + results[i] + " at index " + i + "."); + return false; + } + + return true; + } + + // Test driver for the three coding challenges. + public static void main(String[] args) { + Challenge c = new Challenge(); + + File f = new File("Example.txt"); + String s = c.readFile(f); + System.out.println("contents of the file: \n" + s); + + ArrayList[] list = c.split(s); + //double[] result = c.calculate(list); + + System.out.print("Challenge 1 - "); + System.out.println(c.testChallenge1(list) ? "Correct!\n" : "Incorrect.\n"); + + //System.out.print("Challenge 2 - "); + //System.out.println(c.testChallenge2(result) ? "Correct!\n" : "Incorrect.\n"); + } +} diff --git a/spring24/week7/Example.txt b/spring24/week7/Example.txt new file mode 100644 index 0000000..9af8130 --- /dev/null +++ b/spring24/week7/Example.txt @@ -0,0 +1,8 @@ +( ( 5 + 5 ) * 5 * 3 ) / ( 5 * 3 + ( 8 * 4 ) ) +((5+5)*5*3)/(5*3+(8*4)) +sin((19*3)^4+1) +cos((14*7)/14^2) +tan(3^3/3*3) +log(4739)+2 +(4.239*192.4)-15.327 +ans^2*3 diff --git a/spring24/week7/run b/spring24/week7/run new file mode 100755 index 0000000..f18d273 --- /dev/null +++ b/spring24/week7/run @@ -0,0 +1,6 @@ +#!/bin/zsh + +javac Challenge.java +java Challenge + +rm *.class