I have tweaked and tested and tweaked. As far as I can see this gives the correct result every time for everything I could think of to test. Yet for some reason it doesn't validate. Does anybody know what else I can do? This is no longer a programming problem imo but a validator problem. Every testcase has at least 1 recursion call, every test case gives the correct number of actions and the correct output. What more do they want?
package com.codegym.task.task34.task3404;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
/*
Recursion for mathematical expressions
*/
public class Solution {
public static void main(String[] args) {
Solution solution = new Solution();
solution.recurse("sin(2*(-5+1.5*4)+28)", 0); // Expected output: 0.5 6
solution.recurse("tan(2025 ^ 0.5)", 0); // Expected output: 1 2
solution.recurse("1+2.41+1", 0); // Expected 4.41 1
solution.recurse("2^2", 0); // Expected 4 1
}
public void recurse(final String expression, int countOperation) {
// Implement
int count = countOperation;
if (count == 0) {
count = getOperationsCount(expression);
}
String next = "";
//System.out.println(count);
boolean work = false;
if (expression.contains("+") ||
expression.contains("-") ||
expression.contains("^") ||
expression.contains("*") ||
expression.contains("/") ||
expression.contains("sin") ||
expression.contains("cos") ||
expression.contains("tan")){
work = true;
}
if (!work){
print(expression, count);
return;
}
if (expression.contains("(")) { // checks for substrings
String sub = expression.substring(expression.lastIndexOf('(') + 1, expression.indexOf(')'));
//System.out.println(sub);
Object x = calculate(sub);
StringBuilder builder = new StringBuilder(expression.substring(0, expression.lastIndexOf('(')));
builder.append(x);
builder.append(expression.substring(expression.indexOf(')') + 1));
// System.out.println(builder.toString() + " builder to string");
next = builder.toString();
} else { // Got to do the sin/cos/tan manually
if (expression.startsWith("sin") || expression.startsWith("tan") || expression.startsWith("cos")) {
double x = 0;
double calculateWithMe = Math.toRadians(Double.parseDouble(expression.substring(3)));
if (expression.startsWith("sin")) {
x = Math.sin(calculateWithMe);
}
if (expression.startsWith("tan")) {
x = Math.tan(calculateWithMe);
}
if (expression.startsWith("cos")) {
x = Math.cos(calculateWithMe);
}
double answer = Math.round(x * 100) / 100.0;
print(String.valueOf(answer), count);
return;
}
else {
String sub = "";
String sub2 = "";
String part1 = "";
String part2 = "";
int last1 = 0;
int last2 = 0;
String token = null;
StringBuilder buildMe = new StringBuilder();
if (expression.contains("^")){
part1 = expression.substring(0, expression.indexOf("^"));
part2 = expression.substring(expression.indexOf("^")+1);
last1 = getLastIndex(part1);
last2 = getLastIndex(part2);
token = "^";
if (last1 >0) {
sub = part1.substring(last1);
}else {
sub = part1;
}
if(last2 > 0) {
sub2 = part2.substring(0, last2);
}else {
sub2 = part2;
}
}else if(expression.contains("*")){
part1 = expression.substring(0, expression.indexOf("*"));
part2 = expression.substring(expression.indexOf("*")+1);
last1 = getLastIndex(part1);
last2 = getLastIndex(part2);
token = "*";
if (last1 >0) {
sub = part1.substring(last1);
}else {
sub = part1;
}
if(last2 > 0) {
sub2 = part2.substring(0, last2);
}else {
sub2 = part2;
}
}else if(expression.contains("/")){
part1 = expression.substring(0, expression.indexOf("/"));
part2 = expression.substring(expression.indexOf("/")+1);
last1 = getLastIndex(part1);
last2 = getLastIndex(part2);
token = "/";
if (last1 >0) {
sub = part1.substring(last1);
}else {
sub = part1;
}
if(last2 > 0) {
sub2 = part2.substring(0, last2);
}else {
sub2 = part2;
}
}else if(expression.contains("+")){
part1 = expression.substring(0, expression.indexOf("+"));
part2 = expression.substring(expression.indexOf("+")+1);
last1 = getLastIndex(part1);
last2 = getLastIndex(part2);
token = "+";
if (last1 >0) {
sub = part1.substring(last1);
}else {
sub = part1;
}
if(last2 > 0) {
sub2 = part2.substring(0, last2);
}else {
sub2 = part2;
}
/*System.out.println(sub + " = sub");
System.out.println(sub2 + " = sub2");
System.out.println(expression + " = original");
System.out.println(buildMe.toString() + " = new");*/
}else if(expression.contains("-")){
part1 = expression.substring(0, expression.indexOf("-"));
part2 = expression.substring(expression.indexOf("-")+1);
last1 = getLastIndex(part1);
last2 = getLastIndex(part2);
token = "-";
if (last1 >0) {
sub = part1.substring(last1);
}else {
sub = part1;
}
if(last2 > 0) {
sub2 = part2.substring(0, last2);
}else {
sub2 = part2;
}
}
//build the new string here
if (last1 > 0 && last2 > 0) {
buildMe.append(part1.substring(0, last1));
}
buildMe.append("(").append(sub).append(token).append(sub2).append(")");
if (last2 > 0){
buildMe.append(part2.substring(last2));
}
next = buildMe.toString();
}
}
recurse(next, count);
}
private int getLastIndex(String substring){
int lastIndex = 0;
for (char x : substring.toCharArray()){
if (x == '+' || x == '-' || x == '*' || x == '/' || x == '^'){
int temp = substring.lastIndexOf(x);
if (temp > lastIndex){
lastIndex = temp;
}
}
}
return lastIndex;
}
private void print(String answer, int count){
NumberFormat numberFormat = new DecimalFormat("#.##");
Double result = Double.parseDouble(answer);
System.out.println(String.format("%s %d", numberFormat.format(result), count));
return;
}
private Object calculate(String sum) { //does the actual calculations
Object x = 0.0;
if (sum.contains("^")){
double a = Double.parseDouble(sum.substring(0, sum.indexOf("^")).trim());
double b = Double.parseDouble(sum.substring(sum.indexOf("^")+1).trim());
x = Math.pow(a, b);
}
else {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
try {
x = engine.eval(sum);
} catch (ScriptException e) {
e.printStackTrace();
}
}
// System.out.println(x);
return x;
}
private int getOperationsCount(String expression) { // counts the amount of operations in total
String[] operations = new String[] {"sin", "cos", "tan", "\\^", "\\+", "\\-", "\\*", "\\/"};
int operationsCount = 0;
for (String operation : operations) {
operationsCount += expression.split(operation).length - 1;
}
return operationsCount;
}
public Solution() {
// Don't delete
}
}