diff --git a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java index df720b3..8e2ab5d 100644 --- a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java +++ b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Axel.java @@ -1,29 +1,211 @@ package de.hs_mannheim.informatik.spreadsheet; import java.io.FileNotFoundException; +import java.util.Scanner; /** * Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim. * - * @author Oliver Hummel + * @author Oliver Hummel & Victor Waitz */ public class Axel { + static Scanner keyboard = new Scanner(System.in); + static Spreadsheet spr = new Spreadsheet(6,8); public static void main(String[] args) throws FileNotFoundException { - Spreadsheet spr = new Spreadsheet(10,10); - + // Spreadsheet spr = new Spreadsheet(6,9); + + spr.put("A3", "123"); spr.put("A2", "1"); - spr.put("B9", "=41+A2"); - spr.put("J5", "=7*6"); - spr.put("J6", "=3/2"); + spr.put("B4", "=41+A2"); + spr.put("C5", "=7*6"); + spr.put("D1", "=3/2"); System.out.println(spr); - spr.saveCsv("/tmp/test.csv"); + // spr.saveCsv("/tmp/test.csv"); - // TODO: You might want to put "UI loop" for entering value and formulas here resp. in some UI methods. + // 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(); + if (userCommandPositionInput.charAt(0) == '*'){ + executeCommand(userCommandPositionInput); + continue; + } + String userPositionInput = userCommandPositionInput; + + String userValueFormulaInput = userValueFormulaInput(); + + spr.put(userPositionInput, userValueFormulaInput); + + System.out.println(spr); + } + } + + //? User input for a program command or a position + public static String userCommandPositionInput(){ + System.out.println(); + System.out.println("Input a command for the program or a position"); + System.out.printf("List of program commands: *exit, *save, *load or *help %nFormat for position: A1 or B14%n"); + System.out.print("Input: "); + String userCommandPositionInput = keyboard.nextLine(); + + return userCommandPositionComputation(userCommandPositionInput); + } + + public static String userCommandPositionComputation(String userCommandPositionInput){ + + if (userCommandPositionInput.isEmpty()){ + System.out.println("Input is empty!"); + return userCommandPositionInput(); + } + + //? Program command + if (userCommandPositionInput.charAt(0) == '*'){ + if (!(userCommandErrorCheck(userCommandPositionInput))) { + System.out.println("Invalid command!"); + return userCommandPositionInput(); + } + return userCommandPositionInput; + } + + //? Position + if (!(userPositionErrorCheck(userCommandPositionInput))){ + System.out.println("Invalid position!"); + return userCommandPositionInput(); + } + + if (!(userPositionBoundsErrorCheck(userCommandPositionInput, spr))){ + System.out.println("Position out of bounds!"); + return userCommandPositionInput(); + } + + return userCommandPositionInput; + } + + public static boolean userCommandErrorCheck(String CommandToCheck){ + //? true if valid + //? valid inputs are: *exit, *save, *load, *help (and all upper case variants) + + CommandToCheck = CommandToCheck.toLowerCase(); + if (CommandToCheck.equals("*exit") || CommandToCheck.equals("*save") || CommandToCheck.equals("*load") || CommandToCheck.equals("*help")){ + return true; + } + return false; + } + + public static boolean userPositionErrorCheck(String positionToCheck){ + //? true if valid + //? valid inputs are: A1, B14, C79, E99, F1, G99, J1, M98, ... (and all lower case variants) + + positionToCheck = positionToCheck.toUpperCase(); + + //? Check if input is the right length + if (positionToCheck.length() < 2 || positionToCheck.length() > 3){ + return false; + } + + //? Check if input is in the right format + if (!(Character.isLetter(positionToCheck.charAt(0)) && Character.isDigit(positionToCheck.charAt(1)))){ + return false; + } + + if (positionToCheck.length() == 3){ + if (!(Character.isDigit(positionToCheck.charAt(2)))){ + return false; + } + } + + return true; + } + + public static boolean userPositionBoundsErrorCheck(String positionToCheck, Spreadsheet spr){ + //? true if valid + + positionToCheck = positionToCheck.toUpperCase(); + + if ((spr.getRow(positionToCheck) >= spr.getRowsLCount()) || (spr.getCol(positionToCheck) >= spr.getColsCount())) { + return false; + } + + return true; + } + + //? User input for a value or a formula + public static String userValueFormulaInput(){ + System.out.println(); + System.out.printf("Input a value of a formula for the selected position.%n"); + System.out.printf("Format for a value: 7 or 1337 %nFormat for a formula: =7*6 or =SUM(A1:A3)%n"); + System.out.print("Input: "); + String userCommandInput = keyboard.nextLine(); + + return userValueFormulaComputation(userCommandInput); + } + + public static String userValueFormulaComputation(String userValueFormulaInput){ + if (userValueFormulaInput.isEmpty()){ + System.out.println("Input is empty!"); + return userValueFormulaInput(); + } + + //? Formula + if (userValueFormulaInput.charAt(0) == '='){ + if (!(userFormulaErrorCheck(userValueFormulaInput))) { + System.out.println("Invalid formula!"); + return userValueFormulaInput(); + } + return userValueFormulaInput; + } + + //? Value + if (!(userValueErrorCheck(userValueFormulaInput))){ + System.out.println("Invalid value!"); + return userValueFormulaInput(); + } + + return userValueFormulaInput; + } + + public static boolean userFormulaErrorCheck(String formulaToCheck){ + //? true if valid + //? valid inputs are: =7*6, =SUM(A1:A3), =A1, =A1+A2, =A1-A2, ... (and all lower case variants) + + //TODO ME: Formula format check, maybe too much work + //TODO ME: Check if formula vars are in bounds + + //? remove '=' at the beginning and make everything upper case + formulaToCheck = formulaToCheck.toUpperCase().substring(1); + + if (formulaToCheck.startsWith("SUMME(") || formulaToCheck.startsWith("PRODUKT(") || formulaToCheck.startsWith("MITTELWERT(") || formulaToCheck.startsWith("STABW(") || formulaToCheck.startsWith("MIN(") || formulaToCheck.startsWith("MAX(")){ + return true; + } + + return true; + } + + public static boolean userValueErrorCheck(String valueToCheck){ + //? true if valid + //? valid inputs are: 7, 1337, 0, ... + + String digitCheckRegex = "-?\\d+(\\.\\d+)?"; + if (!(valueToCheck.matches(digitCheckRegex))){ + return false; + } + + return true; + } + + + public static void executeCommand(String command) { + System.out.printf("Executing command: %s%n", command); + //TODO ME: + } } \ No newline at end of file diff --git a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Cell.java b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Cell.java index f80e156..ecbb637 100644 --- a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Cell.java +++ b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Cell.java @@ -4,7 +4,7 @@ package de.hs_mannheim.informatik.spreadsheet; * Part of a simplified spreadsheet system for the PR1 programming lab at Hochschule Mannheim. * A cell needs to be able to hold a formula and a value * - * @author Oliver Hummel + * @author Oliver Hummel & Victor Waitz */ public class Cell { private String formula = ""; diff --git a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java index de46be0..eecdd09 100644 --- a/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java +++ b/Axel/src/de/hs_mannheim/informatik/spreadsheet/Spreadsheet.java @@ -10,7 +10,7 @@ import java.util.regex.Pattern; * A simplified spreadsheet class for the PR1 programming lab at Hochschule Mannheim. * One aspect worth mentioning is that it only supports long numbers, not doubles. * - * @author Oliver Hummel + * @author Oliver Hummel & Victor Waitz */ public class Spreadsheet { Cell[][] cells; @@ -57,18 +57,19 @@ public class Spreadsheet { put(getRow(cellName), getCol(cellName), value); } - private int getCol(String cellName) { + public int getCol(String cellName) { return cellName.charAt(0) - 'A'; } - private int getRow(String cellName) { + public int getRow(String cellName) { + //TODO ME: Implement row numbers with two digits return cellName.charAt(1) - '1'; } // ----- // business logic - /** + /* * A method for reading in data from a CSV file. * @param path The file to read. * @param separator The char used to split up the input, e.g. a comma or a semicolon. @@ -80,7 +81,7 @@ public class Spreadsheet { // TODO: implement this } - /** + /* * A method for saving data to a CSV file. * @param path The file to write. * @return Nothing. @@ -105,27 +106,34 @@ public class Spreadsheet { out.close(); } - /** + /* * This method does the actual evaluation/calcluation of a specific cell * @param cellName the name of the cell to be evaluated * @return Nothing. */ + private void evaluateCell(int row, int col) { String formula = cells[row][col].getFormula(); String result = ""; 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 + else if (formula.startsWith("PRODUKT(")) // e.g. PRODUKT(A3:B9) result = "TODO"; // TODO + else if (formula.startsWith("MITTELWERT(")) // e.g. MITTELWERT(A3:A5) result = "TODO"; // TODO + else if (formula.startsWith("STABW(")) // e.g. STABW(C6:D8) -> Standardabweichung result = "TODO"; // TODO + else if (formula.startsWith("MIN(")) // e.g. MIN(C13:H13) -> größter Wert result = "TODO"; // TODO + else if (formula.startsWith("MAX(")) // e.g. MAX(A1:A10) -> Standardabweichung result = "TODO"; // TODO + else if (!formula.isEmpty()) { try { result = "" + calculate(formula); @@ -137,7 +145,7 @@ public class Spreadsheet { cells[row][col].setValue("" + result); } - /** + /* * 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. @@ -149,7 +157,7 @@ public class Spreadsheet { return 0; } - /** + /* * This method calculates the result of a "normal" algebraic expression. It only needs to support * expressions like =B4 or =2+A3-B2, i.e. only with int numbers and other cells and with plus, * minus, times, split only. An expression always starts with either a number or a cell name. If it @@ -178,11 +186,20 @@ public class Spreadsheet { // ----- + public int getRowsLCount() { + return cells.length; + } + + public int getColsCount() { + return cells[0].length; + } + + public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" "); - for (int i = 0; i < cells.length; i++) { + for (int i = 0; i < cells[0].length; i++) { sb.append(" " + (char)('A'+ i) + " | "); } @@ -198,5 +215,4 @@ public class Spreadsheet { } return sb.toString(); } - } \ No newline at end of file diff --git a/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java b/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java new file mode 100644 index 0000000..474394b --- /dev/null +++ b/Axel/tests/de/hs_mannheim/informatik/spreadsheet/AxelTest.java @@ -0,0 +1,83 @@ +package de.hs_mannheim.informatik.spreadsheet; + +import static org.junit.jupiter.api.Assertions.*; + +class AxelTest { + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("User command or position input") + void userCommandPositionComputation() { + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Command input error check") + void userCommandErrorCheck() { + String[] successTestList = {"*exit", "*save", "*load", "*help", "*eXiT", "*SAVE", "*LoAd", "*hElP"}; + String[] failureTestList = {"exit", "save", "load", "help", "eXiT", "SAVE", "LoAd", "hElP", "*exit*", "*save*", "*load*", "*help*", "*eXiT*", "*SAVE*", "*LoAd*", "*hElP*", "*test", "*TEST", "*saev", "*xeit"}; + + for (String successTest : successTestList) { + assertTrue(Axel.userCommandErrorCheck(successTest)); + } + + for (String failureTest : failureTestList) { + assertFalse(Axel.userCommandErrorCheck(failureTest)); + } + } + + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Position input error check") + void userPositionErrorCheck() { + //? Overall format test + String[] successTestList = {"A1", "B14", "C79", "E99", "F1", "G99", "J1", "M98", "N67", "o45", "p23", "q12", "r2"}; + 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)); + } + + for (String failureTest : failureTestList) { + assertFalse(Axel.userPositionErrorCheck(failureTest)); + } + + //? Out of bounds test + Spreadsheet testSpr = 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)); + } + + for (String failureTest : failureBoundsTest) { + assertFalse(Axel.userPositionBoundsErrorCheck(failureTest, testSpr)); + } + + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("User value or formula input") + void userValueFormulaComputation() { + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Value input error check") + void userValueErrorCheck() { + String[] successTestList = {"0", "1", "-1", "1234", "4324", "-465"}; + String[] failureTestList = {"a", "aa", "A!", "A1", "wef", "-a", "a-","-1a"}; + + for (String successTest : successTestList) { + assertTrue(Axel.userValueErrorCheck(successTest)); + } + + for (String failureTest : failureTestList) { + assertFalse(Axel.userValueErrorCheck(failureTest)); + } + } + + @org.junit.jupiter.api.Test + @org.junit.jupiter.api.DisplayName("Formula input error check") + void userFormulaErrorCheck() { + } +} \ No newline at end of file