From 33ed4534f00f4e90ff167571ee413116406a8b2f Mon Sep 17 00:00:00 2001 From: 3013050 <3013050@stud.hs-mannheim.de> Date: Fri, 29 Dec 2023 20:28:36 +0100 Subject: [PATCH] Function Calc Added calculations for every function calculation + tests & small input error improvements, added size limit for spreadsheet, smnall changes to input text --- .../informatik/spreadsheet/Axel.java | 62 ++++-- .../informatik/spreadsheet/Spreadsheet.java | 177 ++++++++++++++++-- .../informatik/spreadsheet/AxelTest.java | 98 +++++++++- 3 files changed, 293 insertions(+), 44 deletions(-) diff --git a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java index c54d863..8246190 100644 --- a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java +++ b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java @@ -16,9 +16,9 @@ public class Axel { static Spreadsheet spr = new Spreadsheet(11,11); public static void main(String[] args) throws FileNotFoundException { - // Spreadsheet spr = new Spreadsheet(6,9); - - + System.out.println("Welcome to Axel (Totally not Excel)"); + System.out.println(); + /* spr.put("A1", "1"); spr.put("A2", "1"); spr.put("A3", "123"); @@ -29,15 +29,16 @@ public class Axel { spr.put("B4", "=41+A2"); spr.put("C5", "=7*6"); spr.put("D1", "=3/2"); - + */ + + progLoad(); System.out.println(spr); // spr.saveCsv("/tmp/test.csv"); // DONE: You might want to put "UI loop" for entering value and formulas here resp. in some UI methods. // TODO ME: Implement program commands - System.out.println("Welcome to Axel (Totally not Excel)"); - System.out.println(); + while(true) { String userCommandPositionInput = userCommandPositionInput(); @@ -48,7 +49,7 @@ public class Axel { } String userPositionInput = userCommandPositionInput; - String userValueFormulaInput = userValueFormulaInput(); + String userValueFormulaInput = userValueFormulaInput(userPositionInput); spr.put(userPositionInput, userValueFormulaInput); @@ -86,7 +87,7 @@ public class Axel { } //? Position - if (!(userPositionErrorCheck(userCommandPositionInput))){ + if (!(userPositionErrorCheck(userCommandPositionInput, spr))){ System.out.println("Invalid position!"); return userCommandPositionInput(); } @@ -110,7 +111,7 @@ public class Axel { return false; } - public static boolean userPositionErrorCheck(String positionToCheck){ + public static boolean userPositionErrorCheck(String positionToCheck, Spreadsheet spr){ //? true if valid //? valid inputs are: A1, B14, C79, E99, F1, G99, J1, M98, ... (and all lower case variants) @@ -149,27 +150,27 @@ public class Axel { //? User input for a value or a formula - public static String userValueFormulaInput(){ + public static String userValueFormulaInput(String currentPos){ System.out.println(); - System.out.printf("Input a value of a formula for the selected position.%n"); + System.out.printf("Input a value of a formula for the selected position: %s.%n", currentPos); System.out.printf("Format for a value: 7 or 1337 %nFormat for a formula: =7*6 or =SUMME(A1:A3)%n"); System.out.print("Input: "); String userCommandInput = keyboard.nextLine(); - return userValueFormulaComputation(userCommandInput); + return userValueFormulaComputation(userCommandInput, currentPos); } - public static String userValueFormulaComputation(String userValueFormulaInput){ + public static String userValueFormulaComputation(String userValueFormulaInput, String currentPos){ if (userValueFormulaInput.isEmpty()){ System.out.println("Input is empty!"); - return userValueFormulaInput(); + return userValueFormulaInput(currentPos); } //? Formula if (userValueFormulaInput.charAt(0) == '='){ if (!(userFormulaErrorCheck(userValueFormulaInput))) { System.out.println("Invalid formula!"); - return userValueFormulaInput(); + return userValueFormulaInput(currentPos); } return userValueFormulaInput; } @@ -177,7 +178,7 @@ public class Axel { //? Value if (!(userValueErrorCheck(userValueFormulaInput))){ System.out.println("Invalid value!"); - return userValueFormulaInput(); + return userValueFormulaInput(currentPos); } return userValueFormulaInput; @@ -202,19 +203,41 @@ public class Axel { public static boolean userFormulaFunctionErrorCheck(String functionToCheck){ String[] functionCorners = spr.isolateFunctionCorners(functionToCheck); - String[] functionBlock= spr.wholeFunctionBlock(functionToCheck); if (functionCorners.length != 2){ return false; } for (String functionCorner: functionCorners){ - System.out.printf("Corner: %s - Cell test: %s %n", functionCorner, spr.isValueCellName(functionCorner)); if (!(spr.isValueCellName(functionCorner).equals("cellName"))){ return false; } if (!userPositionBoundsErrorCheck(functionCorner, spr)){ + System.out.print("Out of bounds - "); + return false; + } + } + if (functionToCheck.startsWith("MITTELWERT(") || functionToCheck.startsWith("STABW(")) { + String[] functionBlock= spr.wholeFunctionBlock(functionToCheck); + boolean allEmpty = true; + + for (String cell : functionBlock) { + if (!cell.isEmpty()){ + allEmpty = false; + } + } + if (allEmpty){ + System.out.print("Division by zero - "); + return false; + } + } + if (functionToCheck.startsWith("STABW(")) { + String[] functionBlock= spr.wholeFunctionBlock(functionToCheck); + String[] notEmptyValues = spr.extractNotEmptyCells(functionBlock); + + if (notEmptyValues.length < 2){ + System.out.print("Division by zero - "); return false; } } @@ -273,6 +296,9 @@ public class Axel { spr.put("K11", "100"); spr.put("J4", "4"); spr.put("I10", "69"); + spr.put("F5", "3"); + spr.put("G4", "2"); + spr.put("G5", "3"); } } \ No newline at end of file diff --git a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java index ed73771..dfaebca 100644 --- a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java +++ b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java @@ -1,5 +1,6 @@ package de.hs_mannheim.informatik.spreadsheet; +import javax.naming.ldap.spi.LdapDnsProviderResult; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; @@ -25,6 +26,15 @@ public class Spreadsheet { // TODO limit the maximum size on 99 (1..99) rows and 26 (A..Z) columns + if (rows > 99){ + System.out.printf("Row size %d is bigger then 99, value will be set to 99! %n", rows); + rows = 99; + } + if (cols > 26){ + System.out.printf("Col size %d is bigger then 26, value will be set to 26! %n", cols); + cols = 26; + } + cells = new Cell[rows][cols]; for (int r = 0; r < rows; r++) @@ -101,7 +111,7 @@ public class Spreadsheet { else out.print(cell.getValue()); - if (cell != row[cells.length-1]) + if (cell != row[cells[0].length-1]) out.print(","); } out.println(); @@ -120,24 +130,24 @@ public class Spreadsheet { private void evaluateCell(int row, int col) { String formula = cells[row][col].getFormula(); String result = ""; - isolateFunctionCorners(formula); + if (formula.startsWith("SUMME(")) // e.g. SUMME(A3:A8) - result = "" + sum(formula.substring(6, 8), formula.substring(9, 11)); // TODO adapt to cells with two digits + result = "" + sum(formula); else if (formula.startsWith("PRODUKT(")) // e.g. PRODUKT(A3:B9) - result = "TODO"; // TODO + result = "" + prod(formula); else if (formula.startsWith("MITTELWERT(")) // e.g. MITTELWERT(A3:A5) - result = "TODO"; // TODO + result = "" + avrg(formula); else if (formula.startsWith("STABW(")) // e.g. STABW(C6:D8) -> Standardabweichung - result = "TODO"; // TODO + result = "" + stdDevp(formula); else if (formula.startsWith("MIN(")) // e.g. MIN(C13:H13) -> größter Wert - result = "TODO"; // TODO + result = "" + min(formula); else if (formula.startsWith("MAX(")) // e.g. MAX(A1:A10) -> Standardabweichung - result = "TODO"; // TODO + result = "" + max(formula); else if (!formula.isEmpty()) { try { @@ -146,7 +156,6 @@ public class Spreadsheet { result = "exc."; } } - cells[row][col].setValue("" + result); } @@ -183,19 +192,157 @@ public class Spreadsheet { block.add(String.format("%c%d", charCol, rowInt)); } } + return block.toArray(new String[0]); } - /** + /* * Method for calculating the sum of a rectangular block of cells, such as from A1 to B3. * @param startCellName The name of the cell in the upper left corner of the rectangle. * @param endCellName The name of the cell in the lower right corner of the rectangle. * @return The sum calculated. */ - private long sum(String startCellName, String endCellName) { - // TODO implement + public long sum(String formula) { + String[] block = wholeFunctionBlock(formula); + long res = 0; - return 0; + for (String cellName : block){ + String cellValue = get(cellName); + long value = cellValue.isEmpty() ? 0 : Long.parseLong(cellValue); + res += value; + } + + return res; + } + + public long prod(String formula){ + String[] block = wholeFunctionBlock(formula); + + long res = 1; + boolean allEmpty = true; + + for (String cellName : block){ + String cellValue = get(cellName); + if (!cellValue.isEmpty()){ + allEmpty = false; + } + long value = cellValue.isEmpty() ? 1 : Long.parseLong(cellValue); + res *= value; + } + + if (allEmpty){ + res = 0; + } + return res; + } + + public long avrg(String formula){ + String[] block = wholeFunctionBlock(formula); + + boolean allEmpty = true; + long res = 0; + int counter = 0; + + for (String cellName : block){ + String cellValue = get(cellName); + if (cellValue.isEmpty()){ + continue; + } + allEmpty = false; + + res += Long.parseLong(cellValue); + counter++; + } + if (allEmpty){ + System.out.println("Division by zero! Value set to 0"); + return 0; + } + + res = res/counter; + return res; + } + + public long stdDevp(String formula){ + String[] block = wholeFunctionBlock(formula); + + String[] notEmptyValues = extractNotEmptyCells(block); + + if(notEmptyValues.length < 2){ + System.out.println("Division by zero! Value set to 0"); + return 0; + } + + long meanValue = avrg(formula); + long squaredDiffsSum = 0; + + for (String value : notEmptyValues){ + long difference = Long.parseLong(value) - meanValue; + squaredDiffsSum += (long) Math.pow(difference, 2); + } + + long variance = squaredDiffsSum / (notEmptyValues.length - 1); + return (long) Math.sqrt(variance); + } + + public long min(String formula){ + String[] block = wholeFunctionBlock(formula); + + String firstElement = ""; + long currentSmallest = 0; + for (int i = 0; i < block.length; i++) { + String cellValue = get(block[i]); + if (cellValue.isEmpty()) { + continue; + } + if (firstElement.isEmpty()){ + firstElement = get(block[i]); + currentSmallest = Long.parseLong(firstElement); + } + + long value = Long.parseLong(cellValue); + if (value < currentSmallest){ + currentSmallest = value; + } + } + return currentSmallest; + } + + public long max(String formula){ + String[] block = wholeFunctionBlock(formula); + + String firstElement = ""; + long currentBiggest = 0; + for (int i = 0; i < block.length; i++) { + String cellValue = get(block[i]); + if (cellValue.isEmpty()) { + continue; + } + + if (firstElement.isEmpty()){ + firstElement = get(block[i]); + currentBiggest = Long.parseLong(firstElement); + } + + long value = Long.parseLong(cellValue); + if (value > currentBiggest){ + currentBiggest = value; + } + } + return currentBiggest; + } + + public String[] extractNotEmptyCells(String[] block){ + ArrayList notEmptyValues = new ArrayList(); + + for (String cell : block) { + String cellValue = get(cell); + + if (!cellValue.isEmpty()){ + notEmptyValues.add(cellValue); + } + } + + return notEmptyValues.toArray(new String[0]); } /** @@ -209,7 +356,6 @@ public class Spreadsheet { */ public long calculate(String formula) throws ArithmeticException { long res = 0; - // TODO implement ArrayList formulaElements = extractExpressionElements(formula); @@ -274,9 +420,6 @@ public class Spreadsheet { return res; } - private void emptyCellZero(){ - - } public String isValueCellName(String sToCheck){ //? 7 -> "value", A1 -> "cellName", 7A -> "invalid" diff --git a/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java b/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java index 48ccaba..22ef32b 100644 --- a/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java +++ b/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java @@ -34,25 +34,24 @@ class AxelTest { String[] failureTestList = {"A100", "Z101", "AA1", "AB2", "ZZ1", "A1A", "FHT", "AAA", "G3U", "ZZZ", "2A", "47H", "AAAA", "test", "TEST", "save", "*save", "*exit"}; for (String successTest : successTestList) { - assertTrue(Axel.userPositionErrorCheck(successTest)); + assertTrue(Axel.userPositionErrorCheck(successTest, testspr)); } for (String failureTest : failureTestList) { - assertFalse(Axel.userPositionErrorCheck(failureTest)); + assertFalse(Axel.userPositionErrorCheck(failureTest, testspr)); } //? Out of bounds test - Spreadsheet testSpr = new Spreadsheet(6,8); - + Spreadsheet smallTestSpr = new Spreadsheet(6,8); String[] successBoundsTest = {"A1", "a1", "b3", "c5", "A3", "H6", "h6"}; String[] failureBoundsTest = {"i2", "J6", "B7", "K9", "Z99"}; for (String successTest : successBoundsTest) { - assertTrue(Axel.userPositionBoundsErrorCheck(successTest, testSpr)); + assertTrue(Axel.userPositionBoundsErrorCheck(successTest, smallTestSpr)); } for (String failureTest : failureBoundsTest) { - assertFalse(Axel.userPositionBoundsErrorCheck(failureTest, testSpr)); + assertFalse(Axel.userPositionBoundsErrorCheck(failureTest, smallTestSpr)); } } @@ -84,8 +83,7 @@ class AxelTest { @org.junit.jupiter.api.Test @org.junit.jupiter.api.DisplayName("Normal calculation") void calculate() { - - putTestSpr(testspr); + putTestSpr(); String[] successTestList = {"=2*3", "=2+3", "=5-2", "=6/2", "7/2", "101/2", "=5+6-10*2", "=4-3+50-1/2", "=A1", "=K11", "=A1+A2+A3+A4", "=K11/2/5*2-15", "=a1+A2*a4-6+E7", "=a2-A1+J4-3"}; long[] successTestResult = {6, 5, 3, 3, 3, 50, 2, 25, 1, 100, 10, 5, 6, 2}; @@ -104,6 +102,7 @@ class AxelTest { assertNotEquals(failureTestResult[i], testspr.calculate(failureTestList[i])); } } + @org.junit.jupiter.api.Test @org.junit.jupiter.api.DisplayName("Is CellName") void isValueCellName(){ @@ -145,8 +144,86 @@ class AxelTest { } } + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Sum") + void sum(){ + putTestSpr(); + String[] successTestList = {"SUMME(A1:B2)", "summe(B1:e1)", "Summe(B4:I10)", "SUMME(K1:K11)", "SUMME(F1:H1)", "SUMME(F4:G5)", "SUMME(A3:a3)"}; + long[] successResultList = {14, 5, 85, 300, 0, 8, 3}; - private void putTestSpr(Spreadsheet testspr){ + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.sum(testElement)); + } + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Product") + void prod(){ + putTestSpr(); + String[] successTestList = {"PRODUKT(A1:B2)", "PRODUKT(A2:B3)", "PRODUKT(B1:C4)", "Produkt(F1:H1)", "produkt(f4:g5)", "PRODUKT(A3:a3)"}; + long[] successResultList = {60, 252, 1680, 0, 18, 3}; + + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.prod(testElement)); + } + + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Average") + void avrg(){ + putTestSpr(); + String[] successTestList = {"MITTELWERT(A1:B4)", "MITTELWERT(A3:B4)", "MITTELWERT(A1:A4)", "mittelwert(K1:K11)","Mittelwert(F1:H1)" ,"MITTELWERT(f4:g5)", "MITTELWERT(A3:a3)"}; + long[] successResultList = {4, 5, 2, 150, 0, 2, 3}; + + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.avrg(testElement)); + } + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Standard deviation") + void stdDevp(){ + putTestSpr(); + String[] successTestList = {"STABW(A1:B4)", "STABW(A2:B3)", "STABW(A1:A4)", "STABW(K1:K11)", "stabw(f1:H1)", "Stabw(f4:g5)", "STAbW(a3:a3)"}; + long[] successResultList = {2, 2, 1, 70, 0, 1, 0}; + + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.stdDevp(testElement)); + } + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Min value") + void min(){ + putTestSpr(); + String[] successTestList = {"MIN(A1:B4)", "MIN(A2:B3)", "MIN(A1:A4)", "MIN(K1:K11)", "min(f1:H1)", "Min(f4:g5)", "min(a3:a3)"}; + long[] successResultList = {1, 2, 1, 100, 0, 2, 3}; + + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.min(testElement)); + } + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Max value") + void max(){ + putTestSpr(); + String[] successTestList = {"MAX(A1:B4)", "MAX(A2:B3)", "MAX(A1:A4)", "MAX(K1:K11)", "max(f1:H1)", "Max(f4:g5)", "max(a3:a3)"}; + long[] successResultList = {8, 7, 4, 200, 0, 3, 3}; + + for (int i = 0; i < successTestList.length; i++) { + String testElement = successTestList[i].toUpperCase(); + assertEquals(successResultList[i], testspr.max(testElement)); + } + } + + private void putTestSpr(){ testspr.put("A1", "1"); testspr.put("A2", "2"); testspr.put("A3", "3"); @@ -159,5 +236,8 @@ class AxelTest { testspr.put("K11", "100"); testspr.put("J4", "4"); testspr.put("I10", "69"); + testspr.put("F5", "3"); + testspr.put("G4", "2"); + testspr.put("G5", "3"); } } \ No newline at end of file