From 55ba2dfd3ec7f71ed0f785ef60a2375cf097a027 Mon Sep 17 00:00:00 2001 From: "Mr. J" <45538844+Ultraviolet-Ninja@users.noreply.github.com> Date: Sun, 2 Jan 2022 19:39:06 -0600 Subject: [PATCH] Dev (#40) * Started on CheapCheckout * Created CheapCheckoutTest * Worked on Caesar and created CaesarTest * Finished CaesarTest * Down to Java 16 * Wrote instructions for starting the program --- .github/workflows/codeql-analysis.yml | 68 ----- Progress.md | 12 +- README.md | 11 +- build.gradle | 10 +- src/main/java/bomb/ManualController.java | 247 +++++++++--------- src/main/java/bomb/Widget.java | 132 +++++----- .../java/bomb/components/hex/HexTile.java | 3 +- .../microcontroller/EightPinController.java | 3 +- .../microcontroller/SixPinController.java | 3 +- .../microcontroller/TenPinController.java | 3 +- .../bomb/modules/ab/alphabet/Alphabet.java | 3 +- .../java/bomb/modules/ab/battleship/Ship.java | 11 +- .../java/bomb/modules/ab/bitwise/Bitwise.java | 3 +- .../modules/ab/boolean_venn/BooleanVenn.java | 3 +- .../java/bomb/modules/c/caesar/Caesar.java | 53 ++-- .../c/cheap_checkout/CheapCheckout.java | 165 ++++++++++++ .../c/cheap_checkout/CheckoutItem.java | 94 +++++++ .../c/cheap_checkout/CheckoutItems.java | 31 --- src/main/java/bomb/modules/c/chess/Chess.java | 3 +- .../bomb/modules/c/chords/ChordQualities.java | 3 +- .../c/colored_switches/ColoredSwitches.java | 4 +- .../java/bomb/modules/dh/emoji/Emoji.java | 16 +- .../java/bomb/modules/dh/emoji/EmojiMath.java | 13 +- .../bomb/modules/dh/fast_math/FastMath.java | 5 +- .../dh/hexamaze_redesign/Hexamaze.java | 3 +- .../hexalgorithm/maze_finding/MazeSearch.java | 3 +- .../hexalgorithm/pathfinding/ExitChecker.java | 4 +- .../hexalgorithm/pathfinding/MazeRunner.java | 3 +- .../hexalgorithm/storage/HexagonalPlane.java | 4 +- .../bomb/modules/il/ice_cream/IceCream.java | 4 +- .../java/bomb/modules/il/laundry/Laundry.java | 3 +- .../m/microcontroller/MicroController.java | 3 +- .../m/morsematics/MorsematicsController.java | 10 + .../java/bomb/modules/m/murder/Murder.java | 5 +- .../bomb/modules/np/number_pad/NumberPad.java | 4 +- .../bomb/modules/r/round_keypads/Keypad.java | 2 + .../modules/r/round_keypads/RoundKeypads.java | 5 +- .../round_keypads/RoundKeypadsController.java | 3 +- .../bomb/modules/s/shape_shift/ShapeEnd.java | 4 +- .../modules/s/shape_shift/ShapeShift.java | 11 +- .../s/shape_shift/ShapeShiftController.java | 6 +- .../modules/s/simon/screams/SimonScreams.java | 10 +- .../bomb/modules/s/simon/screams/Star.java | 12 +- .../modules/s/simon/states/SimonStates.java | 6 +- .../bomb/modules/s/square/SquareButton.java | 9 +- .../s/square/SquareButtonController.java | 10 + .../java/bomb/modules/t/bulb/TheBulb.java | 5 +- .../java/bomb/modules/t/two_bit/TwoBit.java | 12 +- .../modules/wz/word_search/WordFinder.java | 10 +- .../data/structures/queue/BufferedQueue.java | 6 +- .../tools/data/structures/ring/ArrayRing.java | 6 +- .../bomb/tools/data/structures/trie/Trie.java | 12 +- src/main/java/bomb/tools/filter/Regex.java | 42 +-- .../java/bomb/tools/filter/RegexFilter.java | 4 +- .../java/bomb/tools/number/MathUtils.java | 32 +++ .../factory/MorseCodeGraphFactory.java | 2 - .../pattern/factory/TextFormatterFactory.java | 8 + .../tools/pattern/observer/ObserverHub.java | 15 +- .../tools/pattern/observer/ResetObserver.java | 5 +- .../java/bomb/tools/string/StringFormat.java | 19 +- .../bomb/modules/c/caesar/CaesarTest.java | 69 +++++ .../c/cheap_checkout/CheapCheckoutTest.java | 91 +++++++ .../c/cheap_checkout/CheckoutItemTest.java | 49 ++++ .../modules/dh/fast_math/FastMathTest.java | 2 +- .../s/simon/screams/SimonScreamsTest.java | 8 - .../modules/s/square/SquareButtonTest.java | 3 +- .../wz/word_search/WordFinderTest.java | 12 - src/test/resources/suites/suiteOne.xml | 3 + 68 files changed, 963 insertions(+), 475 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 src/main/java/bomb/modules/c/cheap_checkout/CheckoutItem.java delete mode 100644 src/main/java/bomb/modules/c/cheap_checkout/CheckoutItems.java create mode 100644 src/main/java/bomb/modules/m/morsematics/MorsematicsController.java create mode 100644 src/main/java/bomb/modules/s/square/SquareButtonController.java create mode 100644 src/test/java/bomb/modules/c/caesar/CaesarTest.java create mode 100644 src/test/java/bomb/modules/c/cheap_checkout/CheapCheckoutTest.java create mode 100644 src/test/java/bomb/modules/c/cheap_checkout/CheckoutItemTest.java diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index e88c72b0..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,68 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '16 7 * * 3' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'java' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/Progress.md b/Progress.md index e5dc85fb..7e5cfb6f 100644 --- a/Progress.md +++ b/Progress.md @@ -22,10 +22,12 @@ - The Bulb - TwoBit -20/100 + Colored Switches +21/100 ### Incomplete Modules -- Battleship +- Battleship +- Caesar Cipher +- Cheap Checkout - Ice Cream - Morsematics - Murder @@ -35,7 +37,7 @@ - Square Button - Word Search -9/100 +11/100 ### Untouched Modules - 3D Maze @@ -45,8 +47,6 @@ - Binary LEDs - BitMaps - Broken Button -- Caesar Cipher -- Cheap Checkout - Color Flash - Color Math - Color Squares @@ -109,4 +109,4 @@ - Yahtzee - Zoo -72/100 +68/100 diff --git a/README.md b/README.md index e4d77deb..fb2d933b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![CircleCI](https://circleci.com/gh/Ultraviolet-Ninja/GradleCenturion/tree/main.svg?style=shield)](https://circleci.com/gh/Ultraviolet-Ninja/GradleCenturion/tree/main) [![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/Ultraviolet-Ninja/GradleCenturion.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Ultraviolet-Ninja/GradleCenturion/context:java) -![Project Version](https://img.shields.io/badge/version-0.21.2-blueviolet) +![Project Version](https://img.shields.io/badge/version-0.21.3-blueviolet) ## Intro This project is designed to solve all puzzles found on the Centurion Bomb from Keep Talking and Nobody Explodes, which is a combination of many community-made puzzles and some from the base game set in different languages.
@@ -11,7 +11,7 @@ This project is designed to solve all puzzles found on the Centurion Bomb from K This is a huge project for one man to tackle, but I've [learned a lot](Learned.md) from the challenges I've faced. ## Technologies -- Java 17 +- Java 16 - Gradle 7.3.3 ### Plugins - Jacoco @@ -33,6 +33,13 @@ This is a huge project for one man to tackle, but I've [learned a lot](Learned.m ## Status - In progress See the running list of modules [here](Progress.md) +## How to run the program +*Disclaimer:* Make sure you have Java [16](https://www.oracle.com/java/technologies/javase/jdk16-archive-downloads.html) or [17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) +and the JAVA_HOME is set. +1. Grab the latest .zip/tar of the GradleCenturion-X.X.X and unzip it +2. Using the command line, navigate to the unzipped directory +3. Run the command `./gradlew run` + ## Inspiration After my first manual turning out to be successful in solving the main-game bombs, I thought "Why stop there?". I started creating this project working on the auto-solver for the vanilla game, which was, by comparison, much easier. diff --git a/build.gradle b/build.gradle index b41eeb1e..d4479921 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,13 @@ plugins { } group 'jasmine.jragon' -version '0.21.2' +version '0.21.3' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(16) + } +} application { mainClassName = project.hasProperty('testingArea') ? @@ -128,7 +134,7 @@ pitest { } javafx { - version = '17' + version = '16' modules = ['javafx.controls', 'javafx.fxml'] } diff --git a/src/main/java/bomb/ManualController.java b/src/main/java/bomb/ManualController.java index 6587b356..0f17e857 100644 --- a/src/main/java/bomb/ManualController.java +++ b/src/main/java/bomb/ManualController.java @@ -1,5 +1,7 @@ package bomb; +import bomb.modules.ab.blind_alley.BlindAlleyController; +import bomb.modules.s.souvenir.SouvenirController; import bomb.tools.filter.Regex; import bomb.tools.pattern.facade.FacadeFX; import bomb.tools.pattern.observer.BlindAlleyPaneObserver; @@ -11,7 +13,6 @@ import com.jfoenix.controls.JFXRadioButton; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; -import javafx.scene.Node; import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; import javafx.scene.control.Toggle; @@ -19,28 +20,34 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; -import org.intellij.lang.annotations.Language; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.regex.Pattern; +import java.util.stream.IntStream; -import static bomb.tools.filter.RegexFilter.ALL_CHAR_FILTER; -import static bomb.tools.filter.RegexFilter.filter; import static bomb.tools.pattern.facade.FacadeFX.GET_TOGGLE_NAME; +import static bomb.tools.pattern.factory.TextFormatterFactory.createSearchBarFormatter; import static bomb.tools.pattern.observer.ObserverHub.ObserverIndex.BLIND_ALLEY_PANE; +import static bomb.tools.pattern.observer.ObserverHub.ObserverIndex.FORGET_ME_NOT_TOGGLE; +import static bomb.tools.pattern.observer.ObserverHub.ObserverIndex.RESET; import static bomb.tools.pattern.observer.ObserverHub.ObserverIndex.SOUVENIR_PANE; +import static bomb.tools.pattern.observer.ObserverHub.ObserverIndex.SOUVENIR_TOGGLE; +import static java.util.Arrays.asList; +import static java.util.concurrent.CompletableFuture.supplyAsync; import static java.util.function.UnaryOperator.identity; +import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; @SuppressWarnings("ConstantConditions") @@ -48,7 +55,7 @@ public class ManualController { private static final String FXML_DIRECTORY = "fxml"; private Map regionMap; - private final List allRadioButtons; + private final List allRadioButtons; @FXML private GridPane base; @@ -70,149 +77,109 @@ public ManualController() { } public void initialize() throws ExecutionException, InterruptedException { - allRadioButtons.addAll(radioButtonHouse.getChildren()); - ObserverHub.addObserver(new ForgetMeNotToggleObserver(forgetMeNot)); - ObserverHub.addObserver(new SouvenirToggleObserver(souvenir)); - long start = System.nanoTime(); - regionMap = setupRegionMap().get(); - long stop = System.nanoTime(); - System.out.printf("Timer: %,d", stop - start); - } - - @FXML - public void buttonPress() { - Toggle selected = options.getSelectedToggle(); - String selectedName = GET_TOGGLE_NAME.apply(selected); - if (selectedName.equals("Blind Alley")) ObserverHub.updateAtIndex(BLIND_ALLEY_PANE); - else if (selectedName.equals("Souvenir")) ObserverHub.updateAtIndex(SOUVENIR_PANE); - paneSwitch(regionMap.get(selected)); - } - - private void paneSwitch(final Region pane) { - if (base.getChildren().size() != 1) base.getChildren().retainAll(menuVBox); - base.add(pane, 0, 0); - } - - @FXML - public void search() { - @Language("regexp") - String searchTerm = searchBar.getText(); - radioButtonHouse.getChildren().clear(); - - if (searchTerm.isEmpty()) { - radioButtonHouse.getChildren().addAll(allRadioButtons); - return; - } - - Regex searchPattern = new Regex(searchTerm, Pattern.CASE_INSENSITIVE); - - radioButtonHouse.getChildren().addAll( - allRadioButtons.stream() - .filter(radioButton -> { - String name = ((RadioButton) radioButton).getText(); - searchPattern.loadText(name); - return searchPattern.hasMatch(); - }).toList() + searchBar.setTextFormatter(createSearchBarFormatter()); + allRadioButtons.addAll( + radioButtonHouse.getChildren().stream() + .map(node -> (RadioButton) node) + .toList() ); + ObserverHub.addObserver(FORGET_ME_NOT_TOGGLE, new ForgetMeNotToggleObserver(forgetMeNot)); + ObserverHub.addObserver(SOUVENIR_TOGGLE, new SouvenirToggleObserver(souvenir)); +// long start = System.nanoTime(); + regionMap = setupRegionMap().get(); +// long stop = System.nanoTime(); +// System.out.printf("Timer: %,d%n", stop - start); } - private CompletableFuture> setupRegionMap() { - CompletableFuture> filePathFuture = createFilePathFuture(); + private CompletableFuture> setupRegionMap() throws ExecutionException, InterruptedException { CompletableFuture> radioButtonNameFuture = createRadioButtonNameFuture(options.getToggles()); - return filePathFuture.thenCombine(radioButtonNameFuture, - (filePathMap, radioButtonMap) -> createRegionMap(radioButtonMap, filePathMap)); - } - - private static CompletableFuture> createFilePathFuture() { - Regex filenamePattern = new Regex("\\w+\\."); - ResetObserver resetObserver = new ResetObserver(); - - CompletableFuture> future = CompletableFuture.supplyAsync( - () -> ManualController.class.getResource(FXML_DIRECTORY)) - .thenApply(ManualController::toURI) - .handle((path, ex) -> { - if (ex != null) { - ex.printStackTrace(); - System.exit(-1); - } - return path; - }) - .thenApply(File::new) - .thenApply(ManualController::getFilesFromDirectory) - .thenApply(list -> convertFilesToRegions(list, resetObserver, filenamePattern)); - - ObserverHub.addObserver(resetObserver); - return future; - } - - private static Map convertFilesToRegions(List fileList, ResetObserver resetObserver, - Regex filenamePattern) { - return fileList.stream() - .filter(location -> !location.contains("solutions") - && !location.contains("old") && !location.contains("new")) - .collect(toMap( - location -> filter(location, filenamePattern) - .replace(".", ""), - location -> createSingleRegion(location, resetObserver) - )); + return createFilePathFuture().thenApply(filePathFuture -> + filePathFuture.thenCombine(radioButtonNameFuture, (filePathMap, radioButtonMap) -> + createRegionMap(radioButtonMap, filePathMap))) + .get(); } private static CompletableFuture> createRadioButtonNameFuture(List radioButtonList) { - @Language("regexp") - String newRegex = ALL_CHAR_FILTER.getOriginalPattern() - .replace("]", "_]"); - Regex regex = new Regex(newRegex); - - return CompletableFuture.supplyAsync(radioButtonList::stream) - .thenApply(stream -> - stream.collect(toMap( - toggle -> formatRadioButtonName(toggle, regex), - identity() - ))); + return supplyAsync(radioButtonList::stream) + .thenApply(stream -> stream.collect(toMap( + toggle -> GET_TOGGLE_NAME.apply(toggle) + .replaceAll("[ -]", "_") + .replaceAll("[()']", "") + .toLowerCase(), + identity() + ))); } - private static String formatRadioButtonName(Toggle toggle, Regex regex) { - String buttonName = GET_TOGGLE_NAME.apply(toggle) - .replaceAll("[ -]", "_") - .toLowerCase(); - - return filter(buttonName, regex); - } + private static CompletableFuture>> createFilePathFuture() { + URI uri = toURI(ManualController.class.getResource(FXML_DIRECTORY)); + File file = new File(uri); - private static Region createSingleRegion(String fileLocation, ResetObserver resetObserver) { - URI path = Paths.get(fileLocation).toUri(); - FXMLLoader loader = new FXMLLoader(toURL(path)); - return loadToObserver(loader, resetObserver); + return supplyAsync(() -> getFilesFromDirectory(file)) + .thenApply(ManualController::convertFilesToRegions); } - private static Region loadToObserver(FXMLLoader loader, ResetObserver resetObserver) throws IllegalArgumentException { + private static CompletableFuture> convertFilesToRegions(List fileList) { + ResetObserver resetObserver = new ResetObserver(); + Regex filenamePattern = new Regex("\\w+(?=\\.fxml)"); + fileList.removeIf(location -> location.contains("old") || location.contains("new")); + + CompletableFuture> regionListFuture = supplyAsync(fileList::parallelStream) + .thenApply(stream -> stream.map(Paths::get) + .map(Path::toUri) + .map(uri -> createSingleRegion(uri, resetObserver)) + .collect(toList()) + ); + + CompletableFuture> fileToRegionMapFuture = + supplyAsync(() -> filenamePattern.filterCollection(fileList)) + .thenCombine(regionListFuture, + (fileNameList, regionList) -> IntStream.range(0, fileNameList.size()) + .boxed() + .collect(toMap(fileNameList::get, regionList::get)) + ); + + ObserverHub.addObserver(RESET, resetObserver); + return fileToRegionMapFuture; + } + + private static Region createSingleRegion(URI uri, ResetObserver resetObserver) + throws IllegalArgumentException { + FXMLLoader loader; + try { + loader = new FXMLLoader(uri.toURL()); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } Region output = FacadeFX.load(loader); - String location = loader.getLocation().toString(); + if (!location.contains("widget")) resetObserver.addController(loader); - if (location.contains("souvenir")) loadSouvenirController(loader); - else if (location.contains("blind_alley")) loadBlindAlleyController(loader); + if (location.contains("souvenir")) loadSouvenirController(loader.getController()); + else if (location.contains("blind_alley")) loadBlindAlleyController(loader.getController()); return output; } - private static void loadBlindAlleyController(FXMLLoader loader) { - ObserverHub.addObserver(new BlindAlleyPaneObserver(loader.getController())); + private static void loadBlindAlleyController(BlindAlleyController controller) { + ObserverHub.addObserver(BLIND_ALLEY_PANE, new BlindAlleyPaneObserver(controller)); } - private static void loadSouvenirController(FXMLLoader loader) { - ObserverHub.addObserver(new SouvenirPaneObserver(loader.getController())); + private static void loadSouvenirController(SouvenirController controller) { + ObserverHub.addObserver(SOUVENIR_PANE, new SouvenirPaneObserver(controller)); } - private static List getFilesFromDirectory(final File topLevelDirectory) throws NullPointerException { + private static List getFilesFromDirectory(final File topLevelDirectory) { List list = new ArrayList<>(); - for (final File fileEntry : topLevelDirectory.listFiles()) { - if (fileEntry.isDirectory()) - list.addAll(getFilesFromDirectory(fileEntry)); + ArrayDeque files = new ArrayDeque<>(asList(topLevelDirectory.listFiles())); + File temp; + + while ((temp = files.poll()) != null) { + if (!temp.isDirectory()) + list.add(temp.getPath()); else - list.add(fileEntry.getPath()); + files.addAll(asList(temp.listFiles())); } return list; } @@ -220,7 +187,6 @@ private static List getFilesFromDirectory(final File topLevelDirectory) private static Map createRegionMap(Map radioButtonMap, Map filePathMap) { Map regionMap = new IdentityHashMap<>(); - for (Map.Entry entry : radioButtonMap.entrySet()) regionMap.put( entry.getValue(), @@ -237,11 +203,36 @@ private static URI toURI(URL url) throws IllegalArgumentException { } } - private static URL toURL(URI uri) throws IllegalArgumentException { - try { - return uri.toURL(); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); + @FXML + public void buttonPress() { + Toggle selected = options.getSelectedToggle(); + String selectedName = GET_TOGGLE_NAME.apply(selected); + if (selectedName.equals("Blind Alley")) ObserverHub.updateAtIndex(BLIND_ALLEY_PANE); + else if (selectedName.equals("Souvenir")) ObserverHub.updateAtIndex(SOUVENIR_PANE); + paneSwitch(regionMap.get(selected)); + } + + private void paneSwitch(final Region pane) { + if (base.getChildren().size() != 1) base.getChildren().retainAll(menuVBox); + base.add(pane, 0, 0); + } + + @FXML + public void search() { + String searchTerm = searchBar.getText().toLowerCase(); + radioButtonHouse.getChildren().clear(); + if (searchTerm.isEmpty()) { + radioButtonHouse.getChildren().addAll(allRadioButtons); + return; } + + String pattern = "[\\w ]*" + searchTerm + "[\\w ]*"; + radioButtonHouse.getChildren().addAll( + allRadioButtons.stream() + .filter(radioButton -> GET_TOGGLE_NAME.apply(radioButton) + .toLowerCase() + .matches(pattern) + ).toList() + ); } } diff --git a/src/main/java/bomb/Widget.java b/src/main/java/bomb/Widget.java index bb30bd9f..accde266 100644 --- a/src/main/java/bomb/Widget.java +++ b/src/main/java/bomb/Widget.java @@ -5,6 +5,7 @@ import bomb.enumerations.TrinarySwitch; import bomb.modules.ab.blind_alley.BlindAlley; import bomb.modules.dh.forget_me.ForgetMeNot; +import org.jetbrains.annotations.NotNull; import java.util.EnumSet; import java.util.List; @@ -71,7 +72,7 @@ public static void setDBatteries(int dBatteries) { } } - public static void setIndicator(TrinarySwitch state, Indicator which) { + public static void setIndicator(@NotNull TrinarySwitch state, @NotNull Indicator which) { indicatorArray[which.ordinal()].setState(state); BlindAlley.alleyUpdate(); } @@ -101,12 +102,57 @@ public static void setIsForgetMeNotActive(boolean set) { updatesModules(); } - public static void setPortValue(Port which, int newValue) { + public static void setPortValue(@NotNull Port which, int newValue) { portArray[which.ordinal()] = newValue; BlindAlley.alleyUpdate(); } - public static boolean hasEvenNumberInSerialCode() { + public static int getNumHolders() { + return numHolders; + } + + public static int getNumModules() { + return numModules; + } + + public static int getPortQuantity(@NotNull Port which) { + return portArray[which.ordinal()]; + } + + public static int countPortTypes() { + return (int) stream(portArray) + .filter(port -> port > 0) + .count(); + } + + public static boolean getIsForgetMeNotActive() { + return isForgetMeNotActive; + } + + public static boolean getIsSouvenirActive() { + return isSouvenirActive; + } + + public static int getAllBatteries() { + return numDBatteries + numDoubleAs; + } + + public static int getNumPortPlates() { + return numPortPlates; + } + + public static String getTwoFactor() { + return twoFactor; + } + + public static void checkSerialCode() { + SERIAL_CODE_PATTERN.loadText(serialCode); + if (!SERIAL_CODE_PATTERN.matchesRegex()) throw new IllegalArgumentException(""" + Serial Code is required + Please check formatting on Widget page"""); + } + + protected static boolean hasEvenNumberInSerialCode() { String sample = filter(serialCode, NUMBER_PATTERN); for (char numberChar : sample.toCharArray()) { @@ -121,9 +167,8 @@ public static boolean hasEvenNumberInSerialCode() { * * @return An int of the last digit from a String */ - public static int getSerialCodeLastDigit() { - String buffer = filter(serialCode, NUMBER_PATTERN); - return Integer.parseInt(buffer.substring(buffer.length() - 1)); + protected static int getSerialCodeLastDigit() { + return Character.getNumericValue(serialCode.charAt(serialCode.length() - 1)); } /** @@ -132,7 +177,7 @@ public static int getSerialCodeLastDigit() { * @param indicators The array of possible Indicators * @return True if any Indicator is found */ - public static boolean hasFollowingIndicators(Indicator... indicators) { + protected static boolean hasFollowingIndicators(Indicator @NotNull ... indicators) { for (Indicator current : indicators) { if (hasIndicator(current)) return true; } @@ -145,7 +190,7 @@ public static boolean hasFollowingIndicators(Indicator... indicators) { * @param ind The Indicator to check * @return True if the Indicator is found */ - public static boolean hasIndicator(Indicator ind) { + protected static boolean hasIndicator(@NotNull Indicator ind) { return hasLitIndicator(ind) || hasUnlitIndicator(ind); } @@ -155,7 +200,7 @@ public static boolean hasIndicator(Indicator ind) { * @param ind The Indicator to check * @return True if the lit Indicator is found */ - public static boolean hasLitIndicator(Indicator ind) { + protected static boolean hasLitIndicator(@NotNull Indicator ind) { return indicatorArray[ind.ordinal()].getState() == ON; } @@ -165,11 +210,11 @@ public static boolean hasLitIndicator(Indicator ind) { * @param ind The Indicator to check * @return True if the unlit Indicator is found */ - public static boolean hasUnlitIndicator(Indicator ind) { + protected static boolean hasUnlitIndicator(@NotNull Indicator ind) { return indicatorArray[ind.ordinal()].getState() == OFF; } - public static boolean hasVowelInSerialCode() { + protected static boolean hasVowelInSerialCode() { return !EMPTY_FILTER_RESULTS.test(serialCode, VOWEL_FILTER); } @@ -178,7 +223,7 @@ public static boolean hasVowelInSerialCode() { * * @return The number of letters */ - public static int countLettersInSerialCode() { + protected static int countLettersInSerialCode() { return filter(serialCode, CHAR_FILTER).length(); } @@ -187,7 +232,7 @@ public static int countLettersInSerialCode() { * * @return The number of numbers */ - public static int countNumbersInSerialCode() { + protected static int countNumbersInSerialCode() { return filter(serialCode, NUMBER_PATTERN).length(); } @@ -198,41 +243,15 @@ public static int countNumbersInSerialCode() { * @param howMany The required amount * @return True if the bomb contains more the required amount */ - public static boolean hasMorePortsThanSpecified(Port port, int howMany) { + protected static boolean hasMorePortsThanSpecified(@NotNull Port port, int howMany) { return portArray[port.ordinal()] > howMany; } - public static int getNumHolders() { - return numHolders; - } - - public static int getNumModules() { - return numModules; - } - - public static int getPortQuantity(Port which) { - return portArray[which.ordinal()]; - } - - public static int calculateTotalPorts() { + protected static int calculateTotalPorts() { return stream(portArray).sum(); } - public static int countPortTypes() { - return (int) stream(portArray) - .filter(port -> port > 0) - .count(); - } - - public static boolean getIsForgetMeNotActive() { - return isForgetMeNotActive; - } - - public static boolean getIsSouvenirActive() { - return isSouvenirActive; - } - - public static EnumSet getFilteredSetOfIndicators(IndicatorFilter filter) { + protected static EnumSet getFilteredSetOfIndicators(IndicatorFilter filter) { EnumSet allIndicators = EnumSet.allOf(Indicator.class); List tempList = allIndicators.stream() @@ -244,39 +263,20 @@ public static EnumSet getFilteredSetOfIndicators(IndicatorFilter filt EnumSet.copyOf(tempList); } + protected static boolean doesPortExists(@NotNull Port port) { + return portArray[port.ordinal()] > 0; + } + /** * Counts all indicators, whether lit, unlit or all if specified * * @param filter Indicates what indicators should be counted, whether ON, OFF or both * @return The number of indicators */ - public static int countIndicators(IndicatorFilter filter) { + protected static int countIndicators(IndicatorFilter filter) { return getFilteredSetOfIndicators(filter).size(); } - public static int getAllBatteries() { - return numDBatteries + numDoubleAs; - } - - public static int getNumPortPlates() { - return numPortPlates; - } - - public static String getTwoFactor() { - return twoFactor; - } - - public static boolean doesPortExists(Port port) { - return portArray[port.ordinal()] > 0; - } - - public static void checkSerialCode() { - SERIAL_CODE_PATTERN.loadText(serialCode); - if (!SERIAL_CODE_PATTERN.matchesRegex()) throw new IllegalArgumentException(""" - Serial Code is required - Please check formatting on Widget page"""); - } - public static void resetProperties() { numDoubleAs = 0; numDBatteries = 0; diff --git a/src/main/java/bomb/components/hex/HexTile.java b/src/main/java/bomb/components/hex/HexTile.java index 626c2ff6..33b683b5 100644 --- a/src/main/java/bomb/components/hex/HexTile.java +++ b/src/main/java/bomb/components/hex/HexTile.java @@ -12,6 +12,7 @@ import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; +import org.jetbrains.annotations.NotNull; import java.util.EnumSet; @@ -98,7 +99,7 @@ public void setShape(HexShape shape) { scanShape(); } - public void setBackgroundFill(Color color) { + public void setBackgroundFill(@NotNull Color color) { double newRed = (color.getRed() + DEFAULT_BACKGROUND_COLOR.getRed()) / 2; double newGreen = (color.getGreen() + DEFAULT_BACKGROUND_COLOR.getGreen()) / 2; double newBlue = (color.getBlue() + DEFAULT_BACKGROUND_COLOR.getBlue()) / 2; diff --git a/src/main/java/bomb/components/microcontroller/EightPinController.java b/src/main/java/bomb/components/microcontroller/EightPinController.java index 1ee0592f..fefd1afe 100644 --- a/src/main/java/bomb/components/microcontroller/EightPinController.java +++ b/src/main/java/bomb/components/microcontroller/EightPinController.java @@ -5,6 +5,7 @@ import javafx.fxml.FXMLLoader; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -23,7 +24,7 @@ public EightPinController() { } @Override - public void setColors(List results) { + public void setColors(@NotNull List results) { Circle[] array = new Circle[]{pinOne, pinTwo, pinThree, pinFour, pinFive, pinSix, pinSeven, pinEight}; if (results.size() == PIN_COUNT) { for (int i = 0; i < array.length; i++) diff --git a/src/main/java/bomb/components/microcontroller/SixPinController.java b/src/main/java/bomb/components/microcontroller/SixPinController.java index f39120af..d5ffd9ff 100644 --- a/src/main/java/bomb/components/microcontroller/SixPinController.java +++ b/src/main/java/bomb/components/microcontroller/SixPinController.java @@ -5,6 +5,7 @@ import javafx.fxml.FXMLLoader; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -23,7 +24,7 @@ public SixPinController() { } @Override - public void setColors(List results) { + public void setColors(@NotNull List results) { Circle[] array = new Circle[]{pinOne, pinTwo, pinThree, pinFour, pinFive, pinSix}; if (results.size() == PIN_COUNT) { for (int i = 0; i < array.length; i++) diff --git a/src/main/java/bomb/components/microcontroller/TenPinController.java b/src/main/java/bomb/components/microcontroller/TenPinController.java index 8d41fb94..f467f217 100644 --- a/src/main/java/bomb/components/microcontroller/TenPinController.java +++ b/src/main/java/bomb/components/microcontroller/TenPinController.java @@ -5,6 +5,7 @@ import javafx.fxml.FXMLLoader; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -23,7 +24,7 @@ public TenPinController() { } @Override - public void setColors(List results) { + public void setColors(@NotNull List results) { Circle[] array = new Circle[]{pinOne, pinTwo, pinThree, pinFour, pinFive, pinSix, pinSeven, pinEight, pinNine, pinTen}; if (results.size() == PIN_COUNT) { diff --git a/src/main/java/bomb/modules/ab/alphabet/Alphabet.java b/src/main/java/bomb/modules/ab/alphabet/Alphabet.java index 29facafe..28d3c67f 100644 --- a/src/main/java/bomb/modules/ab/alphabet/Alphabet.java +++ b/src/main/java/bomb/modules/ab/alphabet/Alphabet.java @@ -2,6 +2,7 @@ import bomb.Widget; import bomb.tools.filter.Regex; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.HashSet; @@ -27,7 +28,7 @@ public class Alphabet extends Widget { * @param input The given letter order of tiles * @return The letters in the way they should be pressed */ - public static String order(String input) throws IllegalArgumentException { + public static String order(@NotNull String input) throws IllegalArgumentException { validateInput(input); input = input.toUpperCase(); StringBuilder output = new StringBuilder(); diff --git a/src/main/java/bomb/modules/ab/battleship/Ship.java b/src/main/java/bomb/modules/ab/battleship/Ship.java index 0687562e..3f1bacf7 100644 --- a/src/main/java/bomb/modules/ab/battleship/Ship.java +++ b/src/main/java/bomb/modules/ab/battleship/Ship.java @@ -7,6 +7,7 @@ public enum Ship { /** Minimum number of ships on a given board */ private static final int MINIMUM_NUMBER_OF_SHIPS = 4; + private static final Ship[] SHIPS = values(); private final byte shipSize; @@ -46,24 +47,24 @@ public String toString() { } public static int getNumberOfShipSpaces() { - return stream(values()) + return stream(SHIPS) .mapToInt(ship -> ship.shipSize * ship.currentQuantity) .sum(); } public static boolean areQuantitiesSet() { - return stream(values()) + return stream(SHIPS) .mapToInt(Ship::getCurrentQuantity) .sum() >= MINIMUM_NUMBER_OF_SHIPS; } public static void clearAllQuantities() { - for (Ship ship : values()) + for (Ship ship : SHIPS) ship.setCurrentQuantity((byte) 0); } public static Ship getCurrentLargestShip() { - for (Ship ship : values()) { + for (Ship ship : SHIPS) { if (ship.currentQuantity > ship.foundShips) return ship; } @@ -71,7 +72,7 @@ public static Ship getCurrentLargestShip() { } public static Ship matchShipToSize(int size) { - for (Ship ship : values()) { + for (Ship ship : SHIPS) { if (ship.shipSize == size) return ship; } diff --git a/src/main/java/bomb/modules/ab/bitwise/Bitwise.java b/src/main/java/bomb/modules/ab/bitwise/Bitwise.java index 0925e70b..5bf9fecc 100644 --- a/src/main/java/bomb/modules/ab/bitwise/Bitwise.java +++ b/src/main/java/bomb/modules/ab/bitwise/Bitwise.java @@ -2,6 +2,7 @@ import bomb.Widget; import bomb.tools.logic.LogicOperator; +import org.jetbrains.annotations.NotNull; import static bomb.Widget.IndicatorFilter.LIT; import static bomb.Widget.IndicatorFilter.UNLIT; @@ -25,7 +26,7 @@ public class Bitwise extends Widget { * @throws IllegalArgumentException - The serial code, number of timer minutes and modules * are needed for this module to work */ - public static String getByte(LogicOperator logicOps) throws IllegalArgumentException { + public static String getByte(@NotNull LogicOperator logicOps) throws IllegalArgumentException { StringBuilder builder = new StringBuilder(); for (int i = 0; i < 8; i++) builder.append(solve(i, logicOps)); diff --git a/src/main/java/bomb/modules/ab/boolean_venn/BooleanVenn.java b/src/main/java/bomb/modules/ab/boolean_venn/BooleanVenn.java index d50e8088..6c84b50a 100644 --- a/src/main/java/bomb/modules/ab/boolean_venn/BooleanVenn.java +++ b/src/main/java/bomb/modules/ab/boolean_venn/BooleanVenn.java @@ -3,6 +3,7 @@ import bomb.Widget; import bomb.tools.filter.Regex; import bomb.tools.logic.LogicOperator; +import org.jetbrains.annotations.NotNull; import static bomb.tools.filter.RegexFilter.LOGIC_REGEX; import static bomb.tools.filter.RegexFilter.LOGIC_SYMBOL_FILTER; @@ -46,7 +47,7 @@ public class BooleanVenn extends Widget { * The output order is not, c, b, a, bc, ac, ab, all * @throws IllegalArgumentException Format mismatch for the input equation */ - public static String resultCode(String operation) throws IllegalArgumentException { + public static String resultCode(@NotNull String operation) throws IllegalArgumentException { if (operation.isEmpty()) throw new IllegalArgumentException("Cannot have empty String"); return checkFormat(operation) ? interpretAB(operation) : diff --git a/src/main/java/bomb/modules/c/caesar/Caesar.java b/src/main/java/bomb/modules/c/caesar/Caesar.java index be3ba7da..1f2a5699 100644 --- a/src/main/java/bomb/modules/c/caesar/Caesar.java +++ b/src/main/java/bomb/modules/c/caesar/Caesar.java @@ -1,38 +1,57 @@ package bomb.modules.c.caesar; import bomb.Widget; -import bomb.enumerations.Indicator; -import bomb.enumerations.Port; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.IntStream; + +import static bomb.enumerations.Indicator.CAR; +import static bomb.enumerations.Indicator.NSA; +import static bomb.enumerations.Port.PARALLEL; public class Caesar extends Widget { + private static final int MAX_LETTER_COUNT = 26; - public static String reshuffle(String input) { - return restructure(input, offset()); + public static String reshuffle(@NotNull String input) throws IllegalArgumentException { + checkSerialCode(); + return shift(input, createOffset()); } - private static String restructure(String encoded, int numbShift) { - char extract; + private static String shift(String encoded, int offset) { encoded = encoded.toUpperCase(); StringBuilder result = new StringBuilder(); - for (char letter : encoded.toCharArray()) { - extract = (char) (letter - numbShift); - if (extract < 'A') { - extract = (char) ('[' - (numbShift - (letter - 'A'))); - } - result.append(extract); - } + IntStream.range(0, encoded.length()) + .map(encoded::charAt) + .map(letter -> letter - offset) + .map(Caesar::moduloUpperBound) + .map(Caesar::moduloLowerBound) + .forEach(result::appendCodePoint); return result.toString(); } - private static int offset() { - if (hasLitIndicator(Indicator.NSA) && getPortQuantity(Port.PARALLEL) > 0) return 0; + private static int createOffset() { + if (hasLitIndicator(NSA) && doesPortExists(PARALLEL)) + return 0; + int out = 0; out += getAllBatteries(); if (hasVowelInSerialCode()) out--; - if (hasEvenNumberInSerialCode()) out++; - if (hasIndicator(Indicator.CAR)) out++; + if (getSerialCodeLastDigit() % 2 == 0) out++; + if (hasIndicator(CAR)) out++; return out; } + + private static int moduloUpperBound(int value) { + return value <= 'Z' ? + value : + value - MAX_LETTER_COUNT; + } + + private static int moduloLowerBound(int value) { + return value - 'A' >= 0 ? + value : + value + MAX_LETTER_COUNT; + } } diff --git a/src/main/java/bomb/modules/c/cheap_checkout/CheapCheckout.java b/src/main/java/bomb/modules/c/cheap_checkout/CheapCheckout.java index 2a76d384..8b2ad234 100644 --- a/src/main/java/bomb/modules/c/cheap_checkout/CheapCheckout.java +++ b/src/main/java/bomb/modules/c/cheap_checkout/CheapCheckout.java @@ -1,6 +1,171 @@ package bomb.modules.c.cheap_checkout; import bomb.Widget; +import org.jetbrains.annotations.NotNull; + +import java.time.DayOfWeek; +import java.util.List; +import java.util.function.ToDoubleFunction; + +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.FRUIT; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.SWEET; +import static bomb.tools.number.MathUtils.digitalRoot; +import static bomb.tools.number.MathUtils.roundToNPlaces; public class CheapCheckout extends Widget { + private static final double SUNDAY_ADDITION = 2.15, THURSDAY_SALE = 0.5, + FRIDAY_MARK_UP = 1.25, SATURDAY_SALE = 0.65; + private static final int REQUIRED_ITEM_COUNT = 6, REQUIRED_WEIGHT_COUNT = 2; + private static final ToDoubleFunction> TO_SUM = items -> items.stream() + .mapToDouble(CheckoutItem::getCurrentPiece) + .sum(); + + public static String calculateTotalPrice(@NotNull List items, @NotNull DayOfWeek dayOfWeek, + double[] perPoundWeights, double givenCash) throws IllegalArgumentException { + validateInput(items, perPoundWeights); + items.get(4).applyMultiplicand(perPoundWeights[0]); + items.get(5).applyMultiplicand(perPoundWeights[1]); + + double total = calculateByDay(items, dayOfWeek); + boolean needsMoreMoney = total > givenCash; + + CheckoutItem.resetAlteredItems(items); + + return String.format("$%.2f", total) + (needsMoreMoney ? " Must get more money from customer" : ""); + } + + private static void validateInput(List items, double[] perPoundWeights) + throws IllegalArgumentException { + long distinct = items.stream().distinct().count(); + if (distinct != REQUIRED_ITEM_COUNT) + throw new IllegalArgumentException("Must have 6 distinct items"); + if (perPoundWeights.length != REQUIRED_WEIGHT_COUNT) + throw new IllegalArgumentException("Must have 2 weights for the 2 items that are \"by-the-pound\""); + if (!(items.get(4).isByThePound() && items.get(5).isByThePound())) + throw new IllegalArgumentException("The 5th and 6th items must be \"by-the-pound\""); + + for (int i = 0; i < 4; i++) { + if (items.get(i).isByThePound()) + throw new IllegalArgumentException("Items 1-4 shouldn't be weighted"); + } + } + + private static double calculateByDay(List items, DayOfWeek dayOfWeek) { + return switch (dayOfWeek) { + case SUNDAY -> calculateSpecialSunday(items); + case MONDAY -> calculateMalleableMonday(items); + case TUESDAY -> calculateTroublesomeTuesday(items); + case WEDNESDAY -> calculateWackyWednesday(items); + case THURSDAY -> calculateThrillingThursday(items); + case FRIDAY -> calculateFruityFriday(items); + default -> calculateSweetSaturday(items); + }; + } + + private static double calculateSpecialSunday(List items) { + return items.stream() + .peek(item -> { + if (!item.isByThePound() && item.name().contains("S")) + item.addToPrice(SUNDAY_ADDITION); + }) + .mapToDouble(CheckoutItem::getCurrentPiece) + .sum(); + } + + private static double calculateMalleableMonday(List items) { + //15% off + double sale = 0.85; + items.get(0).applyMultiplicand(sale); + items.get(2).applyMultiplicand(sale); + items.get(5).applyMultiplicand(sale); + + return TO_SUM.applyAsDouble(items); + } + + private static double calculateTroublesomeTuesday(List items) { + int counter = 0; + for (CheckoutItem item : items) { + int digRoot = digitalRoot(item.getCurrentPiece()); + item.addToPrice(digRoot); + if (++counter == 4) + break; + } + + return TO_SUM.applyAsDouble(items); + } + + private static double calculateWackyWednesday(List items) { + return items.stream() + .mapToDouble(CheckoutItem::getCurrentPiece) + .map(value -> roundToNPlaces(value, 2)) + .map(CheapCheckout::swapMinMaxDigits) + .sum(); + } + + private static double calculateThrillingThursday(List items) { + //Half off odd-indexed items + int size = items.size(); + for (int i = 0; i < size; i += 2) + items.get(i).applyMultiplicand(THURSDAY_SALE); + + return TO_SUM.applyAsDouble(items); + } + + private static double calculateFruityFriday(List items) { + return items.stream() + .peek(item -> { + if (item.matchesCategory(FRUIT)) + item.applyMultiplicand(FRIDAY_MARK_UP); + }) + .mapToDouble(CheckoutItem::getCurrentPiece) + .sum(); + } + + private static double calculateSweetSaturday(List items) { + return items.stream() + .peek(item -> { + if (item.matchesCategory(SWEET)) + item.applyMultiplicand(SATURDAY_SALE); + }) + .mapToDouble(CheckoutItem::getCurrentPiece) + .sum(); + } + + private static double swapMinMaxDigits(double number) { + number = roundToNPlaces(number, 2); + StringBuilder digit = new StringBuilder().append(number); + if (digit.length() == 3) + digit.append(0); + + char[] letters = digit.toString().toCharArray(); + char min = findMinDigit(letters); + char max = findMaxDigit(letters); + StringBuilder output = new StringBuilder(); + + for (char letter : letters) { + if (letter == min) letter = max; + else if (letter == max) letter = min; + output.append(letter); + } + + return Double.parseDouble(output.toString()); + } + + private static char findMinDigit(char[] letters) { + char min = '9'; + for (char letter : letters) { + if (letter < min && Character.isDigit(letter)) + min = letter; + } + return min; + } + + private static char findMaxDigit(char[] letters) { + char max = '0'; + for (char letter : letters) { + if (letter > max) + max = letter; + } + return max; + } } diff --git a/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItem.java b/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItem.java new file mode 100644 index 00000000..302953bb --- /dev/null +++ b/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItem.java @@ -0,0 +1,94 @@ +package bomb.modules.c.cheap_checkout; + +import bomb.abstractions.Resettable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; + +import java.util.List; + +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.CARE; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.DAIRY; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.FRUIT; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.GRAIN; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.OIL; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.OTHER; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.PROTEIN; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.SWEET; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.VEGETABLE; +import static bomb.modules.c.cheap_checkout.CheckoutItem.Category.WATER; + +public enum CheckoutItem implements Resettable { + BANANAS(FRUIT, 0.87), BROCCOLI(VEGETABLE, 1.39), + CANDY_CANES(SWEET, 3.51), CANOLA_OIL(OIL, 2.28), + CEREAL(GRAIN, 4.19), CHEESE(DAIRY, 4.49), + CHICKEN(PROTEIN, 1.99), CHOCOLATE_BAR(SWEET, 2.10), + CHOCOLATE_MILK(DAIRY, 5.68), COFFEE_BEANS(OTHER, 7.85), + COOKIES(SWEET, 2.00), DEODORANT(CARE, 3.97), + FRUIT_PUNCH(SWEET, 2.08), GRAPE_JELLY(SWEET, 2.98), + GRAPEFRUIT(FRUIT, 1.08), GUM(SWEET, 1.12), + HONEY(SWEET, 8.25), KETCHUP(OTHER, 3.59), + LEMONS(FRUIT, 1.74), LETTUCE(VEGETABLE, 1.10), + LOLLIPOPS(SWEET, 2.61), LOTION(CARE, 7.97), + MAYONNAISE(OIL, 3.99), MINTS(SWEET, 6.39), + MUSTARD(OTHER, 2.36), ORANGES(FRUIT, 0.80), + PAPER_TOWELS(CARE, 9.46), PASTA_SAUCE(VEGETABLE, 2.30), + PEANUT_BUTTER(PROTEIN, 5.00), PORK(PROTEIN, 4.14), + POTATO_CHIPS(OIL, 3.25), POTATOES(VEGETABLE, 0.68), + SHAMPOO(CARE, 4.98), SOCKS(OTHER, 6.97), + SODA(SWEET, 2.05), SPAGHETTI(GRAIN, 2.92), + STEAK(PROTEIN, 4.97), SUGAR(SWEET, 2.08), + TEA(WATER, 2.35), TISSUES(CARE, 3.94), + TOMATOES(FRUIT, 1.80), TOOTHPASTE(CARE, 2.50), + TURKEY(PROTEIN, 2.98), WATER_BOTTLES(WATER, 9.37), + WHITE_BREAD(GRAIN, 2.43), WHITE_MILK(DAIRY, 3.62); + + private final Category category; + private final double basePrice; + + private double currentPrice; + + CheckoutItem(Category category, double basePrice) { + this.category = category; + this.basePrice = basePrice; + currentPrice = basePrice; + } + + public boolean isByThePound() { + return this.category == FRUIT || (this.category == PROTEIN && this != PEANUT_BUTTER) + || (this.category == VEGETABLE && this != PASTA_SAUCE); + } + + @VisibleForTesting + public double getBasePrice() { + return basePrice; + } + + public double getCurrentPiece() { + return currentPrice; + } + + public boolean matchesCategory(Category toCompare) { + return category == toCompare; + } + + public void addToPrice(double addition) { + currentPrice += addition; + } + + public void applyMultiplicand(double sale) { + currentPrice *= sale; + } + + @Override + public void reset() { + currentPrice = basePrice; + } + + public static void resetAlteredItems(@NotNull List alteredItems) { + alteredItems.forEach(Resettable::reset); + } + + public enum Category { + DAIRY, FRUIT, VEGETABLE, GRAIN, PROTEIN, OIL, SWEET, CARE, WATER, OTHER + } +} diff --git a/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItems.java b/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItems.java deleted file mode 100644 index 3f70a857..00000000 --- a/src/main/java/bomb/modules/c/cheap_checkout/CheckoutItems.java +++ /dev/null @@ -1,31 +0,0 @@ -package bomb.modules.c.cheap_checkout; - -public enum CheckoutItems { - ; - - private final boolean byThePound; - private final Category category; - private final double price; - - CheckoutItems(boolean byThePound, Category category, double price) { - this.byThePound = byThePound; - this.category = category; - this.price = price; - } - - public boolean isByThePound() { - return byThePound; - } - - public Category getCategory() { - return category; - } - - public double getPrice() { - return price; - } - - enum Category { - DAIRY, FRUIT, VEGETABLE, GRAIN, PROTEIN, OIL, GRAIN_OIL, SWEET, CLOTHING, CARE, WATER, BEAN, EXTRA - } -} diff --git a/src/main/java/bomb/modules/c/chess/Chess.java b/src/main/java/bomb/modules/c/chess/Chess.java index 274d54e1..6549a605 100644 --- a/src/main/java/bomb/modules/c/chess/Chess.java +++ b/src/main/java/bomb/modules/c/chess/Chess.java @@ -3,6 +3,7 @@ import bomb.Widget; import bomb.modules.s.souvenir.Souvenir; import bomb.tools.Coordinates; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -23,7 +24,7 @@ public class Chess extends Widget { private static final char INT_CONVERSION_LETTER = 'A'; - public static String solve(List inputCoordinateList) + public static String solve(@NotNull List inputCoordinateList) throws IllegalArgumentException, IllegalStateException { checkSerialCode(); validateList(inputCoordinateList); diff --git a/src/main/java/bomb/modules/c/chords/ChordQualities.java b/src/main/java/bomb/modules/c/chords/ChordQualities.java index c5f9fdb1..ed9f93da 100644 --- a/src/main/java/bomb/modules/c/chords/ChordQualities.java +++ b/src/main/java/bomb/modules/c/chords/ChordQualities.java @@ -3,6 +3,7 @@ import bomb.Widget; import bomb.modules.s.souvenir.Souvenir; import bomb.tools.data.structures.ring.ArrayRing; +import org.jetbrains.annotations.NotNull; import java.util.Set; import java.util.TreeSet; @@ -16,7 +17,7 @@ public class ChordQualities extends Widget { ALL_NOTES = new ArrayRing<>("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"); } - public static String solve(String input) throws IllegalArgumentException { + public static String solve(@NotNull String input) throws IllegalArgumentException { Set sortedSet = validateInput(input); if (isSouvenirActive) Souvenir.addRelic("Chord Quality Original Notes", input); diff --git a/src/main/java/bomb/modules/c/colored_switches/ColoredSwitches.java b/src/main/java/bomb/modules/c/colored_switches/ColoredSwitches.java index 8df2dd08..bc513626 100644 --- a/src/main/java/bomb/modules/c/colored_switches/ColoredSwitches.java +++ b/src/main/java/bomb/modules/c/colored_switches/ColoredSwitches.java @@ -2,6 +2,7 @@ import bomb.modules.s.switches.Switches; import org.javatuples.Pair; +import org.jetbrains.annotations.NotNull; import org.jgrapht.Graph; import org.jgrapht.alg.interfaces.AStarAdmissibleHeuristic; import org.jgrapht.alg.shortestpath.AStarShortestPath; @@ -62,7 +63,8 @@ private static ColoredSwitchNode getNodeByState(byte startingState) throws Illeg throw new IllegalStateException(); } - public static List produceFinalMoveList(SwitchColor[] startingColors, byte desiredState) throws IllegalStateException, IllegalArgumentException { + public static List produceFinalMoveList(@NotNull SwitchColor[] startingColors, byte desiredState) + throws IllegalStateException, IllegalArgumentException { validateByte(desiredState); validateSwitchColors(startingColors); diff --git a/src/main/java/bomb/modules/dh/emoji/Emoji.java b/src/main/java/bomb/modules/dh/emoji/Emoji.java index c2aaa0dc..95f879b2 100644 --- a/src/main/java/bomb/modules/dh/emoji/Emoji.java +++ b/src/main/java/bomb/modules/dh/emoji/Emoji.java @@ -11,6 +11,8 @@ public enum Emoji implements Labeled { EQUAL_CLOSED("=)"), OPEN_EQUAL("(="), COLON_BAR(":|"), BAR_COLON("|:"); + static final Emoji[] EMOJI_ARRAY = values(); + private final String label; @Override @@ -19,24 +21,12 @@ public String getLabel() { } public static Emoji getEmojiFromText(String incoming) { - return stream(values()) + return stream(EMOJI_ARRAY) .filter(emoji -> emoji.label.equals(incoming)) .findFirst() .orElse(null); } - public static String generateCaptureGroup() { - StringBuilder sb = new StringBuilder("(?:"); - String expression = stream(values()) - .map(Labeled::getLabel) - .map(symbol -> symbol.replace("(", "\\(")) - .map(symbol -> symbol.replace(")", "\\)")) - .map(symbol -> symbol.replace("|", "\\|")) - .collect(joining("|")); - - return sb.append(expression).append("){1,2}").toString(); - } - Emoji(String label) { this.label = label; } diff --git a/src/main/java/bomb/modules/dh/emoji/EmojiMath.java b/src/main/java/bomb/modules/dh/emoji/EmojiMath.java index e90f5a49..7584a19e 100644 --- a/src/main/java/bomb/modules/dh/emoji/EmojiMath.java +++ b/src/main/java/bomb/modules/dh/emoji/EmojiMath.java @@ -2,17 +2,22 @@ import bomb.Widget; import bomb.tools.filter.Regex; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NotNull; + +import static bomb.modules.dh.emoji.Emoji.EMOJI_ARRAY; /** * This class deals with the Emoji Math module. * It's simple math, but replacing numbers with text emojis. */ public class EmojiMath extends Widget { + @Language("regexp") + private static final String EMOJI_PATTERN = "(?:[=:][|()]|[|()][=:]){1,2}"; private static final Regex VALIDATION; static { - String emojiRegex = Emoji.generateCaptureGroup(); - VALIDATION = new Regex("(? tileList) throws IllegalArgumentException { + public static String solve(@NotNull List tileList) throws IllegalArgumentException { Maze maze = new Maze(); List nodeList = tileList.stream() .map(HexTile::getInternalNode) diff --git a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/maze_finding/MazeSearch.java b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/maze_finding/MazeSearch.java index 43be7362..ba2d5aa2 100644 --- a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/maze_finding/MazeSearch.java +++ b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/maze_finding/MazeSearch.java @@ -6,6 +6,7 @@ import bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.HexagonalPlane; import bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.Maze; import bomb.tools.data.structures.queue.BufferedQueue; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; @@ -16,7 +17,7 @@ public class MazeSearch { public static final int ROTATION_COUNT = 6; - public static Grid search(Maze maze, Grid grid) { + public static Grid search(@NotNull Maze maze, @NotNull Grid grid) { int gridSpan = grid.getHexagon().getSpan(); int lastIndex = maze.getHexagon().getSpan() - gridSpan; BufferedQueue> pillar; diff --git a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/ExitChecker.java b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/ExitChecker.java index 6efe18b2..10027ff1 100644 --- a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/ExitChecker.java +++ b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/ExitChecker.java @@ -7,6 +7,7 @@ import bomb.tools.data.structures.queue.BufferedQueue; import javafx.scene.paint.Color; import org.javatuples.Pair; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.EnumSet; @@ -27,7 +28,8 @@ import static java.util.stream.Collectors.toList; public class ExitChecker { - public static Pair> findPossibleExits(Grid grid) throws IllegalArgumentException { + public static Pair> findPossibleExits(@NotNull Grid grid) + throws IllegalArgumentException { int pegCount = countPegsOnGrid(grid.getHexagon().getBufferedQueues()); if (pegCount == 0) return null; diff --git a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/MazeRunner.java b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/MazeRunner.java index 6c8430c1..75821349 100644 --- a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/MazeRunner.java +++ b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/pathfinding/MazeRunner.java @@ -5,6 +5,7 @@ import bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.HexNode.HexWall; import bomb.tools.Coordinates; import bomb.tools.data.structures.queue.BufferedQueue; +import org.jetbrains.annotations.NotNull; import org.jgrapht.Graph; import org.jgrapht.GraphPath; import org.jgrapht.alg.shortestpath.DijkstraShortestPath; @@ -28,7 +29,7 @@ public class MazeRunner { LEFT_SIDE_MOVE_DOWN_RIGHT = new Coordinates(1, 1), RIGHT_SIDE_MOVE_TOP_RIGHT = new Coordinates(1, -1); - public static List runMaze(Grid grid, List possibleExits) + public static List runMaze(@NotNull Grid grid, @NotNull List possibleExits) throws IllegalArgumentException { Coordinates startingLocation = findStartingLocation(grid); Graph mappedGraph = convertGridToGraph(grid); diff --git a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/storage/HexagonalPlane.java b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/storage/HexagonalPlane.java index cc50d24e..460c119e 100644 --- a/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/storage/HexagonalPlane.java +++ b/src/main/java/bomb/modules/dh/hexamaze_redesign/hexalgorithm/storage/HexagonalPlane.java @@ -24,6 +24,7 @@ import static bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.HexNode.HexWall.TOP; import static bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.HexNode.HexWall.TOP_LEFT; import static bomb.modules.dh.hexamaze_redesign.hexalgorithm.storage.HexNode.HexWall.TOP_RIGHT; +import static bomb.tools.number.MathUtils.isAnInteger; import static java.util.Arrays.stream; import static java.util.stream.Collectors.toList; @@ -31,8 +32,7 @@ public class HexagonalPlane implements Iterable> { public static final IntUnaryOperator CALCULATE_SPAN = length -> 2 * length - 1, NODAL_SIDE_LENGTH = area -> { double result = (3 + Math.sqrt(12 * area - 3)) / 6; - return result % 1 != 0.0 ? -1 : (int) result; - //If is not an integer + return isAnInteger(result) ? (int) result : -1; }; private final int sideLength; diff --git a/src/main/java/bomb/modules/il/ice_cream/IceCream.java b/src/main/java/bomb/modules/il/ice_cream/IceCream.java index 82f84a7b..41db4b10 100644 --- a/src/main/java/bomb/modules/il/ice_cream/IceCream.java +++ b/src/main/java/bomb/modules/il/ice_cream/IceCream.java @@ -1,6 +1,7 @@ package bomb.modules.il.ice_cream; import bomb.Widget; +import org.jetbrains.annotations.NotNull; import java.util.EnumMap; import java.util.EnumSet; @@ -20,7 +21,8 @@ import static bomb.modules.il.ice_cream.Flavor.VANILLA; public class IceCream extends Widget { - public static Flavor findFlavor(Person person, EnumSet possibleFlavors, boolean hasEmptyPortPlate) + public static Flavor findFlavor(@NotNull Person person, @NotNull EnumSet possibleFlavors, + boolean hasEmptyPortPlate) throws IllegalArgumentException, IllegalStateException { validateInput(possibleFlavors); diff --git a/src/main/java/bomb/modules/il/laundry/Laundry.java b/src/main/java/bomb/modules/il/laundry/Laundry.java index ca1f1125..36ba6f1e 100644 --- a/src/main/java/bomb/modules/il/laundry/Laundry.java +++ b/src/main/java/bomb/modules/il/laundry/Laundry.java @@ -1,6 +1,7 @@ package bomb.modules.il.laundry; import bomb.Widget; +import org.jetbrains.annotations.NotNull; import java.util.Set; import java.util.stream.Stream; @@ -49,7 +50,7 @@ public class Laundry extends Widget { * @return The array of Strings containing the solve conditions * @throws IllegalArgumentException Whether serial code, needy or solved fields are empty */ - public static String[] clean(String solved, String needy) throws IllegalArgumentException { + public static String[] clean(@NotNull String solved, @NotNull String needy) throws IllegalArgumentException { validateInput(solved, needy); Laundry.needy = Integer.parseInt(needy); setClothing(Integer.parseInt(solved)); diff --git a/src/main/java/bomb/modules/m/microcontroller/MicroController.java b/src/main/java/bomb/modules/m/microcontroller/MicroController.java index c37994b5..5b91bfda 100644 --- a/src/main/java/bomb/modules/m/microcontroller/MicroController.java +++ b/src/main/java/bomb/modules/m/microcontroller/MicroController.java @@ -6,13 +6,14 @@ import bomb.modules.m.microcontroller.chip.AbstractController; import bomb.tools.filter.Regex; import javafx.scene.paint.Color; +import org.jetbrains.annotations.NotNull; import java.util.List; import static bomb.tools.filter.RegexFilter.filter; public class MicroController extends Widget { - public static List getPinColors(String moduleSerialNumbers, AbstractController controller) + public static List getPinColors(@NotNull String moduleSerialNumbers, AbstractController controller) throws IllegalArgumentException { validateInput(moduleSerialNumbers, controller); if (containsRequiredNumbers(moduleSerialNumbers)) diff --git a/src/main/java/bomb/modules/m/morsematics/MorsematicsController.java b/src/main/java/bomb/modules/m/morsematics/MorsematicsController.java new file mode 100644 index 00000000..d8e589be --- /dev/null +++ b/src/main/java/bomb/modules/m/morsematics/MorsematicsController.java @@ -0,0 +1,10 @@ +package bomb.modules.m.morsematics; + +import bomb.abstractions.Resettable; + +public class MorsematicsController implements Resettable { + @Override + public void reset() { + + } +} diff --git a/src/main/java/bomb/modules/m/murder/Murder.java b/src/main/java/bomb/modules/m/murder/Murder.java index d40ec163..f83e3a4f 100644 --- a/src/main/java/bomb/modules/m/murder/Murder.java +++ b/src/main/java/bomb/modules/m/murder/Murder.java @@ -4,6 +4,7 @@ import com.opencsv.exceptions.CsvException; import org.javatuples.Pair; import org.javatuples.Triplet; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.EnumMap; @@ -28,8 +29,8 @@ import static java.util.stream.Collectors.toMap; public class Murder extends Widget { - public static String solve(Location bodyFoundRoom, EnumSet possibleWeapons, - EnumSet possibleSuspects) throws IllegalArgumentException { + public static String solve(Location bodyFoundRoom, @NotNull EnumSet possibleWeapons, + @NotNull EnumSet possibleSuspects) throws IllegalArgumentException { validateInput(possibleWeapons, possibleSuspects, bodyFoundRoom); Pair>, EnumMap>> mapPair; diff --git a/src/main/java/bomb/modules/np/number_pad/NumberPad.java b/src/main/java/bomb/modules/np/number_pad/NumberPad.java index 08b9fad6..1f5b7285 100644 --- a/src/main/java/bomb/modules/np/number_pad/NumberPad.java +++ b/src/main/java/bomb/modules/np/number_pad/NumberPad.java @@ -3,7 +3,5 @@ import bomb.Widget; public class NumberPad extends Widget { - public void a() { -// int a = portArray[1]; - } + } diff --git a/src/main/java/bomb/modules/r/round_keypads/Keypad.java b/src/main/java/bomb/modules/r/round_keypads/Keypad.java index 37e187fa..010b8b7c 100644 --- a/src/main/java/bomb/modules/r/round_keypads/Keypad.java +++ b/src/main/java/bomb/modules/r/round_keypads/Keypad.java @@ -32,6 +32,8 @@ public enum Keypad implements Flaggable { PUZZLE, AE, PSI2, RUSSIAN_NH, OMEGA; + static final Keypad[] KEYPAD_ARRAY = values(); + private boolean flag; private Image memory = null; diff --git a/src/main/java/bomb/modules/r/round_keypads/RoundKeypads.java b/src/main/java/bomb/modules/r/round_keypads/RoundKeypads.java index 143ba901..498be1bf 100644 --- a/src/main/java/bomb/modules/r/round_keypads/RoundKeypads.java +++ b/src/main/java/bomb/modules/r/round_keypads/RoundKeypads.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.function.UnaryOperator; +import static bomb.modules.r.round_keypads.Keypad.KEYPAD_ARRAY; import static java.util.Arrays.stream; import static java.util.function.UnaryOperator.identity; import static java.util.stream.Collectors.counting; @@ -20,7 +21,7 @@ public class RoundKeypads extends Widget { new Color(0, previousColor.getGreen(), previousColor.getBlue(), 1); public static int determineBadColumn() { - Map frequencyCounter = stream(Keypad.values()) + Map frequencyCounter = stream(KEYPAD_ARRAY) .filter(Flaggable::getFlag) .mapToInt(Enum::ordinal) .mapToObj(num -> Math.floorDiv(num, IMAGES_PER_COLUMN)) @@ -63,7 +64,7 @@ private static Image highLightImage(Image original) { } public static void reset() { - for (Keypad currentKeypad : Keypad.values()) + for (Keypad currentKeypad : KEYPAD_ARRAY) currentKeypad.setFlag(false); } } diff --git a/src/main/java/bomb/modules/r/round_keypads/RoundKeypadsController.java b/src/main/java/bomb/modules/r/round_keypads/RoundKeypadsController.java index e5e9c6ec..b99b30a5 100644 --- a/src/main/java/bomb/modules/r/round_keypads/RoundKeypadsController.java +++ b/src/main/java/bomb/modules/r/round_keypads/RoundKeypadsController.java @@ -21,6 +21,7 @@ import static bomb.modules.r.round_keypads.Keypad.HARRY_POTTER; import static bomb.modules.r.round_keypads.Keypad.HOLLOW_STAR1; import static bomb.modules.r.round_keypads.Keypad.HOLLOW_STAR2; +import static bomb.modules.r.round_keypads.Keypad.KEYPAD_ARRAY; import static bomb.modules.r.round_keypads.Keypad.NOT_THREE; import static bomb.modules.r.round_keypads.Keypad.OMEGA; import static bomb.modules.r.round_keypads.Keypad.PARAGRAPH1; @@ -169,7 +170,7 @@ private void resetImageViews() { russianSix1, paragraph1, tB1, russianCat2, russianX2, spanishQuestion2, smile1, psi1, smile2, tB2, cDot, paragraph2, shrekThree, star, russianSix2, backEuro2, puzzlePiece, aeyyLmao, psi2, russianHN, omega); - List keypads = asList(Keypad.values()); + List keypads = asList(KEYPAD_ARRAY); int size = keypads.size(); for (int i = 0; i < size; i++) { diff --git a/src/main/java/bomb/modules/s/shape_shift/ShapeEnd.java b/src/main/java/bomb/modules/s/shape_shift/ShapeEnd.java index 72a89692..58534758 100644 --- a/src/main/java/bomb/modules/s/shape_shift/ShapeEnd.java +++ b/src/main/java/bomb/modules/s/shape_shift/ShapeEnd.java @@ -1,5 +1,7 @@ package bomb.modules.s.shape_shift; public enum ShapeEnd { - ROUND, POINT, FLAT, TICKET + ROUND, POINT, FLAT, TICKET; + + static final ShapeEnd[] END_ARRAY = values(); } diff --git a/src/main/java/bomb/modules/s/shape_shift/ShapeShift.java b/src/main/java/bomb/modules/s/shape_shift/ShapeShift.java index 84b617ed..98904cb3 100644 --- a/src/main/java/bomb/modules/s/shape_shift/ShapeShift.java +++ b/src/main/java/bomb/modules/s/shape_shift/ShapeShift.java @@ -19,6 +19,7 @@ import static bomb.enumerations.Port.PS2; import static bomb.enumerations.Port.RCA; import static bomb.enumerations.Port.RJ45; +import static bomb.modules.s.shape_shift.ShapeEnd.END_ARRAY; import static bomb.tools.logic.BitConverter.TO_INT; public class ShapeShift extends Widget { @@ -28,15 +29,15 @@ public class ShapeShift extends Widget { // static { - int size = ShapeEnd.values().length; + int size = END_ARRAY.length; COUNT_TRACKER = new int[size][size]; zeroOutArray(); initializeGraph(); } private static void zeroOutArray() { - for (ShapeEnd leftSide : ShapeEnd.values()) { - for (ShapeEnd rightSide : ShapeEnd.values()) + for (ShapeEnd leftSide : END_ARRAY) { + for (ShapeEnd rightSide : END_ARRAY) COUNT_TRACKER[leftSide.ordinal()][rightSide.ordinal()] = 0; } } @@ -48,8 +49,8 @@ private static void initializeGraph() { private static List> createList() { List> list = new ArrayList<>(); - for (ShapeEnd left : ShapeEnd.values()) { - for (ShapeEnd right : ShapeEnd.values()) + for (ShapeEnd left : END_ARRAY) { + for (ShapeEnd right : END_ARRAY) list.add(new Pair<>(left, right)); } return list; diff --git a/src/main/java/bomb/modules/s/shape_shift/ShapeShiftController.java b/src/main/java/bomb/modules/s/shape_shift/ShapeShiftController.java index 4b0e1e14..53166867 100644 --- a/src/main/java/bomb/modules/s/shape_shift/ShapeShiftController.java +++ b/src/main/java/bomb/modules/s/shape_shift/ShapeShiftController.java @@ -4,12 +4,14 @@ import bomb.tools.data.structures.ring.ArrayRing; import javafx.fxml.FXML; +import static bomb.modules.s.shape_shift.ShapeEnd.END_ARRAY; + public class ShapeShiftController implements Resettable { private final ArrayRing leftSide, rightSide; public ShapeShiftController() { - leftSide = new ArrayRing<>(ShapeEnd.values()); - rightSide = new ArrayRing<>(ShapeEnd.values()); + leftSide = new ArrayRing<>(END_ARRAY); + rightSide = new ArrayRing<>(END_ARRAY); } public void initialize() { diff --git a/src/main/java/bomb/modules/s/simon/screams/SimonScreams.java b/src/main/java/bomb/modules/s/simon/screams/SimonScreams.java index 9af3a3a7..d8b67850 100644 --- a/src/main/java/bomb/modules/s/simon/screams/SimonScreams.java +++ b/src/main/java/bomb/modules/s/simon/screams/SimonScreams.java @@ -2,14 +2,12 @@ import bomb.Widget; import bomb.modules.s.simon.SimonColors.ScreamColor; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -/** - * - */ public class SimonScreams extends Widget { private static final int MAX_OUTPUT_RULES = 6; private static final List CURRENT_OUTPUT_NUMBERS; @@ -44,7 +42,7 @@ public class SimonScreams extends Widget { * @throws IllegalArgumentException - The serial code isn't 6 characters long OR * The array is not 6 elements long */ - public static void initialize(ScreamColor[] order) throws IllegalArgumentException { + public static void initialize(@NotNull ScreamColor[] order) throws IllegalArgumentException { checkSerialCode(); initialized = true; setOutputRules(); @@ -58,8 +56,8 @@ public static void initialize(ScreamColor[] order) throws IllegalArgumentExcepti * @return - The resulting colors to pressed * @throws IllegalArgumentException - The init() method wasn't called first */ - public static String nextSolve(ScreamColor[] flashingOrder) throws IllegalArgumentException { - if (flashingOrder == null || flashingOrder.length == 0) + public static String nextSolve(@NotNull ScreamColor[] flashingOrder) throws IllegalArgumentException { + if (flashingOrder.length == 0) throw new IllegalArgumentException("No colors were selected"); if (!initialized) throw new IllegalArgumentException("Initialization wasn't started"); String letter = String.valueOf(getStringLetter(flashingOrder)); diff --git a/src/main/java/bomb/modules/s/simon/screams/Star.java b/src/main/java/bomb/modules/s/simon/screams/Star.java index c47c5014..ac4e5d3c 100644 --- a/src/main/java/bomb/modules/s/simon/screams/Star.java +++ b/src/main/java/bomb/modules/s/simon/screams/Star.java @@ -2,25 +2,27 @@ import bomb.modules.s.simon.SimonColors.ScreamColor; import bomb.tools.data.structures.ring.ArrayRing; +import org.jetbrains.annotations.NotNull; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; +import java.util.EnumSet; import java.util.Set; +import static java.util.Arrays.asList; + public class Star { private static final byte LIMIT = 6; private final ArrayRing colorOrder; - public Star(ScreamColor[] order) { + public Star(@NotNull ScreamColor[] order) { checkUniqueColors(order); colorOrder = new ArrayRing<>(LIMIT); for (ScreamColor instance : order) colorOrder.add(instance); } private static void checkUniqueColors(ScreamColor[] order) { - Set set = new HashSet<>(Arrays.asList(order)); + Set set = EnumSet.copyOf(asList(order)); if (set.size() != LIMIT) throw new IllegalArgumentException("Size doesn't equal 6"); } @@ -54,7 +56,7 @@ private int sameColor(ScreamColor[] flashOrder) { //If there are one or less primary colors are flashing public boolean primaryRule(ScreamColor[] flashOrder) { - Set unique = new HashSet<>(); + Set unique = EnumSet.noneOf(ScreamColor.class); Collections.addAll(unique, flashOrder); int counter = 0; diff --git a/src/main/java/bomb/modules/s/simon/states/SimonStates.java b/src/main/java/bomb/modules/s/simon/states/SimonStates.java index 503ceac1..4a0f0b38 100644 --- a/src/main/java/bomb/modules/s/simon/states/SimonStates.java +++ b/src/main/java/bomb/modules/s/simon/states/SimonStates.java @@ -51,7 +51,7 @@ public static void setDominantColor(@NotNull StateColor dominantColor) { dominantColorIndex = dominantColor.ordinal(); } - public static List calculateNextColorPress(EnumSet colorsFlashed) + public static List calculateNextColorPress(@NotNull EnumSet colorsFlashed) throws IllegalArgumentException { validate(colorsFlashed); if (isSouvenirActive) @@ -154,7 +154,7 @@ private static StateColor getColorFlashed(EnumSet colorsFlashed) { } private static StateColor getFirstInOrder(BiPredicate, StateColor> condition, - EnumSet colorsFlashed, List priorityOrder) throws IllegalArgumentException { + EnumSet colorsFlashed, List priorityOrder)throws IllegalArgumentException { return filter(condition, colorsFlashed, priorityOrder) .findFirst() .orElseThrow(() -> new IllegalArgumentException(ERROR_MESSAGE)); @@ -191,7 +191,7 @@ private static boolean areAllPressesDistinct() { private static void validate(EnumSet colorsFlashed) throws IllegalArgumentException { if (dominantColorIndex == -1) throw new IllegalArgumentException("Priority has not been set"); - if (colorsFlashed == null || colorsFlashed.isEmpty()) + if (colorsFlashed.isEmpty()) throw new IllegalArgumentException("Empty set is not allowed"); } diff --git a/src/main/java/bomb/modules/s/square/SquareButton.java b/src/main/java/bomb/modules/s/square/SquareButton.java index f43e1d3d..1562f6df 100644 --- a/src/main/java/bomb/modules/s/square/SquareButton.java +++ b/src/main/java/bomb/modules/s/square/SquareButton.java @@ -2,6 +2,7 @@ import bomb.Widget; import bomb.tools.number.MathUtils; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; @@ -29,9 +30,9 @@ public class SquareButton extends Widget { private static final Set COLOR_WORDS = new TreeSet<>(asList("Purple", "Indigo", "Maroon", "Jade")); - public static String solve(int buttonColor, String buttonText) throws IllegalArgumentException { + public static String solve(int buttonColor, @NotNull String buttonText) throws IllegalArgumentException { checkSerialCode(); - validateButtonInput(buttonColor, buttonText); + validateButtonColor(buttonColor); buttonText = FIRST_LETTER_CAPITAL.apply(buttonText); if (buttonColor == BLUE && numDoubleAs > numDBatteries) return HOLD; @@ -47,11 +48,9 @@ public static String solve(int buttonColor, String buttonText) throws IllegalArg return HOLD; } - private static void validateButtonInput(int buttonColor, String buttonText) throws IllegalArgumentException { + private static void validateButtonColor(int buttonColor) throws IllegalArgumentException { if (buttonColor < BLUE || buttonColor > WHITE) throw new IllegalArgumentException("Invalid button color"); - if (buttonText == null) - throw new IllegalArgumentException("Text cannot be null"); } private static boolean matchesGreatestSerialCodeNumber(String buttonText) { diff --git a/src/main/java/bomb/modules/s/square/SquareButtonController.java b/src/main/java/bomb/modules/s/square/SquareButtonController.java new file mode 100644 index 00000000..06f169c0 --- /dev/null +++ b/src/main/java/bomb/modules/s/square/SquareButtonController.java @@ -0,0 +1,10 @@ +package bomb.modules.s.square; + +import bomb.abstractions.Resettable; + +public class SquareButtonController implements Resettable { + @Override + public void reset() { + + } +} diff --git a/src/main/java/bomb/modules/t/bulb/TheBulb.java b/src/main/java/bomb/modules/t/bulb/TheBulb.java index 65f202f8..e4a331df 100644 --- a/src/main/java/bomb/modules/t/bulb/TheBulb.java +++ b/src/main/java/bomb/modules/t/bulb/TheBulb.java @@ -6,6 +6,7 @@ import bomb.tools.filter.Regex; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -39,7 +40,7 @@ public class TheBulb extends Widget { private static boolean isLightOffAtStepOne; private static Indicator rememberedIndicator = null; - public static List solve(Bulb bulb) { + public static List solve(@NotNull Bulb bulb) { validateBulb(bulb); List outputList = new ArrayList<>(); stepOne(bulb, outputList); @@ -305,7 +306,7 @@ private static void stepFifteen(Bulb bulb, List outputList) { private static void sendInfoToSouvenir(List outputList) { Regex findButtonPresses = new Regex("Press [IO]"); - List matches = findButtonPresses.loadCollection(outputList); + List matches = findButtonPresses.filterCollection(outputList); String outputText = String.join("\n", matches); Souvenir.addRelic("The Bulb button presses", outputText); } diff --git a/src/main/java/bomb/modules/t/two_bit/TwoBit.java b/src/main/java/bomb/modules/t/two_bit/TwoBit.java index fdacb0dc..e88d777f 100644 --- a/src/main/java/bomb/modules/t/two_bit/TwoBit.java +++ b/src/main/java/bomb/modules/t/two_bit/TwoBit.java @@ -2,6 +2,7 @@ import bomb.Widget; import bomb.modules.s.souvenir.Souvenir; +import org.jetbrains.annotations.NotNull; import static bomb.enumerations.Port.RCA; import static bomb.enumerations.Port.RJ45; @@ -10,6 +11,7 @@ import static bomb.tools.filter.RegexFilter.CHAR_FILTER; import static bomb.tools.filter.RegexFilter.NUMBER_PATTERN; import static bomb.tools.filter.RegexFilter.filter; +import static bomb.tools.string.StringFormat.createOrdinalNumber; /** * @@ -69,7 +71,7 @@ public static String initialCode() throws IllegalArgumentException { * @return The next letter code along with a Query or Submit phrase * @throws IllegalArgumentException The given input was not 2 numbers */ - public static String nextCode(String code) throws IllegalArgumentException { + public static String nextCode(@NotNull String code) throws IllegalArgumentException { String newCode = filter(code, NUMBER_PATTERN); validateNextCode(code, newCode); int[] coords = translateToBitCoordinates(newCode); @@ -81,8 +83,8 @@ public static String nextCode(String code) throws IllegalArgumentException { if (isSouvenirActive) { Souvenir.addRelic( - "TwoBit" + determineSouvenirOrdinal() + " Query", newCode + " - " + - CODE_GRID[coords[0]][coords[1]] + String.format("TwoBit %s Query", createOrdinalNumber(currentState.ordinal())), + String.format("%s - %s", newCode, CODE_GRID[coords[0]][coords[1]]) ); } currentState = currentState.nextState(); @@ -110,10 +112,6 @@ private static int[] translateToBitCoordinates(String code) { return codeOut; } - private static String determineSouvenirOrdinal() { - return (currentState == SECOND_QUERY) ? "2nd" : "3rd"; - } - public static void resetStage() { currentState = SECOND_QUERY; } diff --git a/src/main/java/bomb/modules/wz/word_search/WordFinder.java b/src/main/java/bomb/modules/wz/word_search/WordFinder.java index dabd2664..f6b611f1 100644 --- a/src/main/java/bomb/modules/wz/word_search/WordFinder.java +++ b/src/main/java/bomb/modules/wz/word_search/WordFinder.java @@ -3,6 +3,8 @@ import bomb.tools.Coordinates; import bomb.tools.data.structures.trie.Trie; import org.javatuples.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -10,8 +12,9 @@ public class WordFinder { private static int currentGridLength, longestWordLength; - public static Pair findWordCoordinates(char[][] grid, Set possibleWords) { - validate(grid, possibleWords); + public static @Nullable Pair findWordCoordinates(char[][] grid, + @NotNull Set possibleWords) { + validate(grid); Coordinates startPosition, endPosition; Trie trie = new Trie(possibleWords); @@ -35,8 +38,7 @@ public static Pair findWordCoordinates(char[][] grid, return null; } - private static void validate(char[][] grid, Set possibleWords) throws IllegalArgumentException { - if (possibleWords == null) throw new IllegalArgumentException("Cannot have a null set"); + private static void validate(char[][] grid) throws IllegalArgumentException { int width = grid.length; for (char[] row : grid) { diff --git a/src/main/java/bomb/tools/data/structures/queue/BufferedQueue.java b/src/main/java/bomb/tools/data/structures/queue/BufferedQueue.java index 2fc94ff8..70631b7a 100644 --- a/src/main/java/bomb/tools/data/structures/queue/BufferedQueue.java +++ b/src/main/java/bomb/tools/data/structures/queue/BufferedQueue.java @@ -1,5 +1,7 @@ package bomb.tools.data.structures.queue; +import org.jetbrains.annotations.NotNull; + import java.lang.ref.WeakReference; import java.util.ArrayDeque; import java.util.ArrayList; @@ -11,7 +13,7 @@ import java.util.RandomAccess; import java.util.stream.Stream; -@SuppressWarnings("unchecked") +@SuppressWarnings({"unchecked", "NullableProblems"}) public class BufferedQueue implements List, Iterable, RandomAccess { private final int capacity; private final ArrayDeque dataDeque; @@ -24,7 +26,7 @@ public BufferedQueue(int capacity) { dataCache = new WeakReference<>(null); } - public BufferedQueue(Collection c) { + public BufferedQueue(@NotNull Collection c) { this.capacity = c.size(); dataDeque = new ArrayDeque<>(c); dataCache = new WeakReference<>(null); diff --git a/src/main/java/bomb/tools/data/structures/ring/ArrayRing.java b/src/main/java/bomb/tools/data/structures/ring/ArrayRing.java index c63b21ab..2943632b 100644 --- a/src/main/java/bomb/tools/data/structures/ring/ArrayRing.java +++ b/src/main/java/bomb/tools/data/structures/ring/ArrayRing.java @@ -1,5 +1,7 @@ package bomb.tools.data.structures.ring; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -21,12 +23,12 @@ public ArrayRing(int startingCapacity) { } @SafeVarargs - public ArrayRing(E... elements) { + public ArrayRing(E @NotNull ... elements) { this(elements.length); internalStructure.addAll(asList(elements)); } - public ArrayRing(Collection c) { + public ArrayRing(@NotNull Collection c) { if (c.size() < 1) throw new IllegalArgumentException(); internalStructure = c instanceof ArrayList ? diff --git a/src/main/java/bomb/tools/data/structures/trie/Trie.java b/src/main/java/bomb/tools/data/structures/trie/Trie.java index ca6562cd..2a9f980e 100644 --- a/src/main/java/bomb/tools/data/structures/trie/Trie.java +++ b/src/main/java/bomb/tools/data/structures/trie/Trie.java @@ -1,5 +1,7 @@ package bomb.tools.data.structures.trie; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -20,12 +22,12 @@ public Trie(Collection startWords) { addWords(startWords); } - public void addWords(Collection words) { + public void addWords(@NotNull Collection words) { for (String word : words) addWord(word); } - public void addWord(final String word) { + public void addWord(final @NotNull String word) { addWord(word.toLowerCase(), 0, root); } @@ -42,7 +44,7 @@ private static void addWord(final String word, int index, TrieNode currentNode) addWord(word, index + 1, currentNode.getNextNode(nextChar)); } - public Set getWordsStartingWith(String prefix) { + public Set getWordsStartingWith(@NotNull String prefix) { List words = new ArrayList<>(); StringBuilder builder = new StringBuilder(); TrieNode currentNode = root; @@ -96,8 +98,8 @@ private static void addIfIsWord(List words, StringBuilder builder, TrieN words.add(builder.toString()); } - public boolean containsWord(String word) { - if (word == null || word.isEmpty()) + public boolean containsWord(@NotNull String word) { + if (word.isEmpty()) return false; word = word.toLowerCase(); diff --git a/src/main/java/bomb/tools/filter/Regex.java b/src/main/java/bomb/tools/filter/Regex.java index b04de4f4..71a49bd0 100644 --- a/src/main/java/bomb/tools/filter/Regex.java +++ b/src/main/java/bomb/tools/filter/Regex.java @@ -1,6 +1,7 @@ package bomb.tools.filter; import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Iterator; @@ -9,70 +10,73 @@ import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @SuppressWarnings("MagicConstant") public class Regex implements Iterable { public static final Function CREATE_INSENSITIVE_SET = - input -> new Regex("[" + input + "]", Pattern.CASE_INSENSITIVE), + input -> new Regex("[" + input + "]", CASE_INSENSITIVE), CREATE_NEGATED_SET = input -> new Regex("[^" + input + "]"); private static final Function> RESULT_STREAM = matcher -> - matcher.results().map(MatchResult::group); + matcher.reset().results().map(MatchResult::group); private static final int MAX_FLAG_SIZE = 0x1ff; private final Pattern regPattern; private final Matcher textMatcher; - public Regex(@Language("regexp") String regex) { + public Regex(@Language("regexp") @NotNull String regex) { regPattern = Pattern.compile(regex); textMatcher = regPattern.matcher(""); } - public Regex(@Language("regexp") String regex, int flag) throws IllegalArgumentException { + public Regex(@Language("regexp") @NotNull String regex, int flag) throws IllegalArgumentException { maxFlagCheck(flag); regPattern = Pattern.compile(regex, flag); textMatcher = regPattern.matcher(""); } - public Regex(@Language("regexp") String regex, int... flags) throws IllegalArgumentException { + public Regex(@Language("regexp") @NotNull String regex, int... flags) throws IllegalArgumentException { int value = orMask(flags); maxFlagCheck(value); regPattern = Pattern.compile(regex, value); textMatcher = regPattern.matcher(""); } - public Regex(@Language("regexp") String regex, String matchText) { + public Regex(@Language("regexp") @NotNull String regex, @NotNull String matchText) { regPattern = Pattern.compile(regex); textMatcher = regPattern.matcher(matchText); } - public Regex(@Language("regexp") String regex, String matchText, int flag) throws IllegalArgumentException { + public Regex(@Language("regexp") @NotNull String regex, @NotNull String matchText, int flag) + throws IllegalArgumentException { maxFlagCheck(flag); regPattern = Pattern.compile(regex, flag); textMatcher = regPattern.matcher(matchText); } - public Regex(@Language("regexp") String regex, String matchText, int... flags) throws IllegalArgumentException { + public Regex(@Language("regexp") @NotNull String regex, @NotNull String matchText, int... flags) + throws IllegalArgumentException { int value = orMask(flags); maxFlagCheck(value); regPattern = Pattern.compile(regex, value); textMatcher = regPattern.matcher(matchText); } - public void loadText(String text) { + public void loadText(@NotNull String text) { textMatcher.reset(text); } - public List loadCollection(Collection textCollections) { + public List filterCollection(@NotNull Collection textCollections) { return textCollections.stream() - .map(regPattern::matcher) + .map(textMatcher::reset) .map(RESULT_STREAM) - .map(stream -> stream.collect(Collectors.joining())) + .map(stream -> stream.collect(joining())) .collect(toList()); } @@ -88,7 +92,7 @@ public String captureGroup(int group) { return textMatcher.group(group); } - public String captureGroup(String customGroup) { + public String captureGroup(@NotNull String customGroup) { return textMatcher.group(customGroup); } @@ -107,10 +111,10 @@ public String getOriginalPattern() { public String createFilteredString() { return RESULT_STREAM.apply(textMatcher) - .collect(Collectors.joining()); + .collect(joining()); } - public boolean collectionMatches(Collection c) { + public boolean doesCollectionMatch(@NotNull Collection c) { String pattern = regPattern.pattern(); return c.stream() @@ -134,7 +138,11 @@ public Stream stream() { @Override public Iterator iterator() { - return findAllMatches().iterator(); + return RESULT_STREAM.apply(textMatcher).iterator(); + } + + public Regex appendToPattern(@Language("regexp") @NotNull String pattern) { + return new Regex(this.regPattern.pattern() + pattern, regPattern.flags()); } private static void maxFlagCheck(int flags) { diff --git a/src/main/java/bomb/tools/filter/RegexFilter.java b/src/main/java/bomb/tools/filter/RegexFilter.java index 62c6c855..e80c2f34 100644 --- a/src/main/java/bomb/tools/filter/RegexFilter.java +++ b/src/main/java/bomb/tools/filter/RegexFilter.java @@ -19,8 +19,8 @@ public class RegexFilter { public static final Regex VOWEL_FILTER = new Regex("[aæąåàeêęèéiîïoôöóøœuûüŭ]+?", CASE_INSENSITIVE), LOGIC_SYMBOL_FILTER = new Regex(LOGIC_REGEX), - CHAR_FILTER = new Regex("[a-zæąåàêęèéîïôöóøœûüŭ]+?", CASE_INSENSITIVE), - ALL_CHAR_FILTER = new Regex("[a-z\\dæąåàêęèéîïôöóøœûüŭ]+?", CASE_INSENSITIVE); + CHAR_FILTER = new Regex("[a-zæąåàêęèéîïôöóøœûüŭ]+?", CASE_INSENSITIVE); +// ALL_CHAR_FILTER = new Regex("[a-z\\dæąåàêęèéîïôöóøœûüŭ]+?", CASE_INSENSITIVE); public static String filter(String input, Regex pattern) { pattern.loadText(input); diff --git a/src/main/java/bomb/tools/number/MathUtils.java b/src/main/java/bomb/tools/number/MathUtils.java index fc679d83..3410ef5e 100644 --- a/src/main/java/bomb/tools/number/MathUtils.java +++ b/src/main/java/bomb/tools/number/MathUtils.java @@ -1,5 +1,8 @@ package bomb.tools.number; +import static java.lang.Math.pow; +import static java.lang.Math.round; + public class MathUtils { public static final int HASHING_NUMBER = 5501; @@ -18,4 +21,33 @@ public static boolean isPrime(long n) { } return n != 1; } + + public static int digitalRoot(long number) { + long root = 0; + + while (number > 0 || root > 9) { + if (number == 0) { + number = root; + root = 0; + } + + root += number % 10; + number /= 10; + } + return (int) root; + } + + public static int digitalRoot(double number) { + number = Double.parseDouble(String.valueOf(number).replace(".", "")); + return digitalRoot((long) number); + } + + public static boolean isAnInteger(double number) { + return number % 1 == 0.0; + } + + public static double roundToNPlaces(double number, int places) { + double factor = pow(10.0, places); + return round(number * factor) / factor; + } } diff --git a/src/main/java/bomb/tools/pattern/factory/MorseCodeGraphFactory.java b/src/main/java/bomb/tools/pattern/factory/MorseCodeGraphFactory.java index 8152950c..b6e6af81 100644 --- a/src/main/java/bomb/tools/pattern/factory/MorseCodeGraphFactory.java +++ b/src/main/java/bomb/tools/pattern/factory/MorseCodeGraphFactory.java @@ -34,6 +34,4 @@ public static ListGraph createGraph() throws IllegalStateException { throw new IllegalStateException(e); } } - - } diff --git a/src/main/java/bomb/tools/pattern/factory/TextFormatterFactory.java b/src/main/java/bomb/tools/pattern/factory/TextFormatterFactory.java index 1cb55657..375ce61b 100644 --- a/src/main/java/bomb/tools/pattern/factory/TextFormatterFactory.java +++ b/src/main/java/bomb/tools/pattern/factory/TextFormatterFactory.java @@ -47,6 +47,10 @@ public static TextFormatter createNewLineRestrictionFormatter() { null); } + public static TextFormatter createSearchBarFormatter() { + return REGEX_MATCH_FORMATTER.apply("[A-Za-z3 ]{1,32}"); + } + public static TextFormatter createOneLetterFormatter() { return REGEX_MATCH_FORMATTER.apply("\\b[a-zA-Z]\\b"); } @@ -66,4 +70,8 @@ public static TextFormatter createSixLetterTextFormatter() { public static TextFormatter createBattleshipCounterTextFormatter() { return REGEX_MATCH_FORMATTER.apply("\\b[0-4]\\b"); } + + public static TextFormatter createDecimalNumberTextFormatter(int significantDigits) { + return REGEX_MATCH_FORMATTER.apply(String.format("\\b\\d\\.?\\d{0,%d}\\b", significantDigits)); + } } diff --git a/src/main/java/bomb/tools/pattern/observer/ObserverHub.java b/src/main/java/bomb/tools/pattern/observer/ObserverHub.java index 01c18b53..16b7aa2e 100644 --- a/src/main/java/bomb/tools/pattern/observer/ObserverHub.java +++ b/src/main/java/bomb/tools/pattern/observer/ObserverHub.java @@ -1,23 +1,24 @@ package bomb.tools.pattern.observer; -import java.util.ArrayList; -import java.util.List; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumMap; public class ObserverHub { public enum ObserverIndex { FORGET_ME_NOT_TOGGLE, SOUVENIR_TOGGLE, BLIND_ALLEY_PANE, SOUVENIR_PANE, RESET } - private static final List OBSERVER_LIST = new ArrayList<>(); + private static final EnumMap OBSERVER_MAP = new EnumMap<>(ObserverIndex.class); private ObserverHub() { } - public static void addObserver(Observer observer) { - OBSERVER_LIST.add(observer); + public static void addObserver(ObserverIndex index, Observer observer) { + OBSERVER_MAP.put(index, observer); } - public static void updateAtIndex(ObserverIndex index) { - OBSERVER_LIST.get(index.ordinal()).update(); + public static void updateAtIndex(@NotNull ObserverIndex index) { + OBSERVER_MAP.get(index).update(); } } diff --git a/src/main/java/bomb/tools/pattern/observer/ResetObserver.java b/src/main/java/bomb/tools/pattern/observer/ResetObserver.java index 4ba94d77..5b3d3e8b 100644 --- a/src/main/java/bomb/tools/pattern/observer/ResetObserver.java +++ b/src/main/java/bomb/tools/pattern/observer/ResetObserver.java @@ -14,8 +14,9 @@ public ResetObserver() { } public void addController(FXMLLoader loader) { - if (loader.getController() == null) return; - controllerList.add(loader.getController()); + Object controller = loader.getController(); + if (controller == null) return; + controllerList.add((Resettable) controller); } @Override diff --git a/src/main/java/bomb/tools/string/StringFormat.java b/src/main/java/bomb/tools/string/StringFormat.java index 5e2252b9..1b59a09e 100644 --- a/src/main/java/bomb/tools/string/StringFormat.java +++ b/src/main/java/bomb/tools/string/StringFormat.java @@ -1,8 +1,8 @@ package bomb.tools.string; -import java.util.Arrays; import java.util.function.UnaryOperator; +import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; public class StringFormat { @@ -12,7 +12,22 @@ public class StringFormat { sample.toUpperCase(); public static final UnaryOperator TO_TITLE_CASE = text -> - Arrays.stream(text.split("[-_ ]")) + stream(text.split("[-_ ]")) .map(FIRST_LETTER_CAPITAL) .collect(joining(" ")); + + public static final UnaryOperator TO_SCREAM_SNAKE_CASE = text -> + stream(text.split("[- ]")) + .map(String::toUpperCase) + .collect(joining("_")); + + public static String createOrdinalNumber(int number) { + if (number % 10 == 1) + return number + "st"; + if (number % 10 == 2) + return number + "nd"; + if (number % 10 == 3) + return number + "rd"; + return number + "th"; + } } diff --git a/src/test/java/bomb/modules/c/caesar/CaesarTest.java b/src/test/java/bomb/modules/c/caesar/CaesarTest.java new file mode 100644 index 00000000..5de526c9 --- /dev/null +++ b/src/test/java/bomb/modules/c/caesar/CaesarTest.java @@ -0,0 +1,69 @@ +package bomb.modules.c.caesar; + +import bomb.ConditionSetter; +import bomb.Widget; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static bomb.enumerations.Indicator.CAR; +import static bomb.enumerations.Indicator.NSA; +import static bomb.enumerations.Port.PARALLEL; +import static bomb.enumerations.TrinarySwitch.ON; +import static org.testng.Assert.assertEquals; + +public class CaesarTest { + @BeforeMethod + public void setUp() { + Widget.resetProperties(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void validationTest() { + Caesar.reshuffle(""); + } + + @DataProvider + public Object[][] validInputTestProvider() { + final String serialCode = "A65WU8"; + ConditionSetter firstBranchCondition = () -> { + Widget.setSerialCode(serialCode); + Widget.setIndicator(ON, NSA); + Widget.setPortValue(PARALLEL, 1); + }; + + ConditionSetter secondBranchCondition = () -> { + Widget.setSerialCode(serialCode); + Widget.setIndicator(ON, NSA); + Widget.setIndicator(ON, CAR); + }; + + ConditionSetter thirdBranchCondition = () -> { + Widget.setSerialCode("BJ3WL1"); + Widget.setDoubleAs(2); + Widget.setPortValue(PARALLEL, 1); + }; + ConditionSetter fourthBranchCondition = () -> Widget.setSerialCode("A65WU7"); + + String text = "ANWMDL"; + return new Object[][]{ + {firstBranchCondition, text, text}, {secondBranchCondition, text, "ZMVLCK"}, + {thirdBranchCondition, text, "YLUKBJ"}, {fourthBranchCondition, "ZAJRMF", "ABKSNG"} + }; + } + + @Test(dataProvider = "validInputTestProvider") + public void validInputTest(ConditionSetter widgetSetter, String input, String expected) { + widgetSetter.setCondition(); + + String result = Caesar.reshuffle(input); + + assertEquals(result, expected); + } + + @AfterClass + public void tearDown() { + Widget.resetProperties(); + } +} diff --git a/src/test/java/bomb/modules/c/cheap_checkout/CheapCheckoutTest.java b/src/test/java/bomb/modules/c/cheap_checkout/CheapCheckoutTest.java new file mode 100644 index 00000000..175dc833 --- /dev/null +++ b/src/test/java/bomb/modules/c/cheap_checkout/CheapCheckoutTest.java @@ -0,0 +1,91 @@ +package bomb.modules.c.cheap_checkout; + +import org.testng.annotations.AfterTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.time.DayOfWeek; +import java.util.EnumSet; +import java.util.List; + +import static bomb.modules.c.cheap_checkout.CheckoutItem.BANANAS; +import static bomb.modules.c.cheap_checkout.CheckoutItem.CHEESE; +import static bomb.modules.c.cheap_checkout.CheckoutItem.CHOCOLATE_BAR; +import static bomb.modules.c.cheap_checkout.CheckoutItem.CHOCOLATE_MILK; +import static bomb.modules.c.cheap_checkout.CheckoutItem.COFFEE_BEANS; +import static bomb.modules.c.cheap_checkout.CheckoutItem.COOKIES; +import static bomb.modules.c.cheap_checkout.CheckoutItem.DEODORANT; +import static bomb.modules.c.cheap_checkout.CheckoutItem.GUM; +import static bomb.modules.c.cheap_checkout.CheckoutItem.HONEY; +import static bomb.modules.c.cheap_checkout.CheckoutItem.ORANGES; +import static bomb.modules.c.cheap_checkout.CheckoutItem.STEAK; +import static bomb.modules.c.cheap_checkout.CheckoutItem.TEA; +import static java.time.DayOfWeek.FRIDAY; +import static java.time.DayOfWeek.MONDAY; +import static java.time.DayOfWeek.SATURDAY; +import static java.time.DayOfWeek.SUNDAY; +import static java.time.DayOfWeek.THURSDAY; +import static java.time.DayOfWeek.TUESDAY; +import static java.time.DayOfWeek.WEDNESDAY; +import static org.testng.Assert.assertEquals; + +public class CheapCheckoutTest { + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = "Must have 6 distinct items") + public void firstValidationTest() { + CheapCheckout.calculateTotalPrice(List.of(STEAK, STEAK, STEAK, STEAK, STEAK, STEAK), MONDAY, + new double[] {1.5, 1.5}, 15.00); + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = "Must have 2 weights for the 2 items that are \"by-the-pound\"") + public void secondValidationTest() { + CheapCheckout.calculateTotalPrice(List.of(CHOCOLATE_MILK, COOKIES, DEODORANT, GUM, BANANAS, STEAK), MONDAY, + new double[] {1.5, 1.5, 1.5}, 15.00); + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = "The 5th and 6th items must be \"by-the-pound\"") + public void thirdValidationTest() { + CheapCheckout.calculateTotalPrice(List.of(CHOCOLATE_MILK, COOKIES, DEODORANT, GUM, BANANAS, CHOCOLATE_BAR), + MONDAY, new double[] {1.5, 1.5}, 15.00); + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = "Items 1-4 shouldn't be weighted") + public void fourthValidationTest() { + CheapCheckout.calculateTotalPrice(List.of(CHOCOLATE_MILK, COOKIES, DEODORANT, ORANGES, BANANAS, STEAK), + MONDAY, new double[] {1.5, 1.5}, 15.00); + } + + @DataProvider + public Object[][] allWeekTestProvider() { + List items = List.of(HONEY, COFFEE_BEANS, TEA, CHEESE, STEAK, ORANGES); + double[] weights = {0.5, 1.0}; + double givenCash = 25.00; + + return new Object[][]{ + {items, SUNDAY, weights, givenCash, "$30.53 Must get more money from customer"}, + {items, MONDAY, weights, givenCash, "$24.52"}, + {items, TUESDAY, weights, givenCash, "$43.23 Must get more money from customer"}, + {items, WEDNESDAY, weights, givenCash, "$43.19 Must get more money from customer"}, + {items, THURSDAY, weights, givenCash, "$19.68"}, + {items, FRIDAY, weights, givenCash, "$26.43 Must get more money from customer"}, + {items, SATURDAY, weights, givenCash, "$23.34"} + }; + } + + @Test(dataProvider = "allWeekTestProvider") + public void allWeekTest(List items, DayOfWeek dayOfWeek, double[] perPoundWeights, + double givenCash, String expectedText) { + String results = CheapCheckout.calculateTotalPrice(items, dayOfWeek, perPoundWeights, givenCash); + + assertEquals(results, expectedText); + } + + @AfterTest + public void verifyReset() { + EnumSet.allOf(CheckoutItem.class) + .forEach(item -> assertEquals(item.getBasePrice(), item.getCurrentPiece())); + } +} diff --git a/src/test/java/bomb/modules/c/cheap_checkout/CheckoutItemTest.java b/src/test/java/bomb/modules/c/cheap_checkout/CheckoutItemTest.java new file mode 100644 index 00000000..2bc2f96c --- /dev/null +++ b/src/test/java/bomb/modules/c/cheap_checkout/CheckoutItemTest.java @@ -0,0 +1,49 @@ +package bomb.modules.c.cheap_checkout; + +import org.testng.annotations.Test; + +import java.util.EnumSet; + +import static bomb.modules.c.cheap_checkout.CheckoutItem.BANANAS; +import static bomb.modules.c.cheap_checkout.CheckoutItem.BROCCOLI; +import static bomb.modules.c.cheap_checkout.CheckoutItem.CHICKEN; +import static bomb.modules.c.cheap_checkout.CheckoutItem.GRAPEFRUIT; +import static bomb.modules.c.cheap_checkout.CheckoutItem.LEMONS; +import static bomb.modules.c.cheap_checkout.CheckoutItem.LETTUCE; +import static bomb.modules.c.cheap_checkout.CheckoutItem.ORANGES; +import static bomb.modules.c.cheap_checkout.CheckoutItem.PASTA_SAUCE; +import static bomb.modules.c.cheap_checkout.CheckoutItem.PEANUT_BUTTER; +import static bomb.modules.c.cheap_checkout.CheckoutItem.PORK; +import static bomb.modules.c.cheap_checkout.CheckoutItem.POTATOES; +import static bomb.modules.c.cheap_checkout.CheckoutItem.STEAK; +import static bomb.modules.c.cheap_checkout.CheckoutItem.TOMATOES; +import static bomb.modules.c.cheap_checkout.CheckoutItem.TURKEY; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +public class CheckoutItemTest { + @Test + public void byThePoundValidationTest() { + EnumSet allByThePoundItems = EnumSet.of( + BANANAS, BROCCOLI, CHICKEN, GRAPEFRUIT, LEMONS, LETTUCE, ORANGES, PORK, POTATOES, + STEAK, TOMATOES, TURKEY + ); + + allByThePoundItems.forEach(item -> assertTrue(item.isByThePound())); + } + + @Test + public void otherProteinAndVegetableTest() { + EnumSet.of(PASTA_SAUCE, PEANUT_BUTTER).forEach(item -> assertFalse(item.isByThePound())); + } + + @Test + public void fixedPriceItemTest() { + EnumSet fixedPriceItems = EnumSet.complementOf(EnumSet.of( + BANANAS, BROCCOLI, CHICKEN, GRAPEFRUIT, LEMONS, LETTUCE, ORANGES, PORK, POTATOES, + STEAK, TOMATOES, TURKEY + )); + + fixedPriceItems.forEach(item -> assertFalse(item.isByThePound())); + } +} diff --git a/src/test/java/bomb/modules/dh/fast_math/FastMathTest.java b/src/test/java/bomb/modules/dh/fast_math/FastMathTest.java index 1910740f..d753a8e2 100644 --- a/src/test/java/bomb/modules/dh/fast_math/FastMathTest.java +++ b/src/test/java/bomb/modules/dh/fast_math/FastMathTest.java @@ -25,7 +25,7 @@ public void setUp() { public Object[][] exceptionTestProvider() { ConditionSetter setSerialCode = () -> Widget.setSerialCode("fr4op2"); return new Object[][]{ - {EMPTY_SETTER, ""}, {EMPTY_SETTER, null}, {EMPTY_SETTER, "AZ"}, {setSerialCode, "AY"} + {EMPTY_SETTER, ""}, {EMPTY_SETTER, "AZ"}, {setSerialCode, "AY"} }; } diff --git a/src/test/java/bomb/modules/s/simon/screams/SimonScreamsTest.java b/src/test/java/bomb/modules/s/simon/screams/SimonScreamsTest.java index cda08525..d8150575 100644 --- a/src/test/java/bomb/modules/s/simon/screams/SimonScreamsTest.java +++ b/src/test/java/bomb/modules/s/simon/screams/SimonScreamsTest.java @@ -45,13 +45,6 @@ public void initMethodExceptionTest(ConditionSetter setter, ScreamColor[] arr) { SimonScreams.initialize(arr); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void nextSolveExceptionTest() { - testReset(); - - SimonScreams.nextSolve(null); - } - @DataProvider public Object[][] trainingVideoTestProviderOne() { testReset(); @@ -63,7 +56,6 @@ public Object[][] trainingVideoTestProviderOne() { }; } - @Test(dataProvider = "trainingVideoTestProviderOne") public void trainingVideoTestOne(ScreamColor[] flashOrder, String expected) { assertEquals(SimonScreams.nextSolve(flashOrder), expected); diff --git a/src/test/java/bomb/modules/s/square/SquareButtonTest.java b/src/test/java/bomb/modules/s/square/SquareButtonTest.java index bf17f6b4..3ef5160f 100644 --- a/src/test/java/bomb/modules/s/square/SquareButtonTest.java +++ b/src/test/java/bomb/modules/s/square/SquareButtonTest.java @@ -35,8 +35,7 @@ public void setUp() { @DataProvider public Object[][] exceptionSolveTestProvider() { return new Object[][]{ - {"", 0, ""}, {VALID_SERIAL_CODE, -1, null}, - {VALID_SERIAL_CODE, 5, null}, {VALID_SERIAL_CODE, 1, null} + {"", 0, ""}, {VALID_SERIAL_CODE, -1, null}, {VALID_SERIAL_CODE, 5, null} }; } diff --git a/src/test/java/bomb/modules/wz/word_search/WordFinderTest.java b/src/test/java/bomb/modules/wz/word_search/WordFinderTest.java index 194807b2..207028c6 100644 --- a/src/test/java/bomb/modules/wz/word_search/WordFinderTest.java +++ b/src/test/java/bomb/modules/wz/word_search/WordFinderTest.java @@ -23,18 +23,6 @@ public void irregularGridValidationTest() { WordFinder.findWordCoordinates(grid, Set.of("MATH", "SEE", "HELP", "FOUND")); } - @Test(expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = "Cannot have a null set") - public void nullSetValidationTest() { - int length = 3; - char[][] grid = new char[length][]; - - for (int i = 0; i < length; i++) { - grid[i] = new char[length]; - } - WordFinder.findWordCoordinates(grid, null); - } - @DataProvider public Object[][] nonNullTestProvider() { return new Object[][]{ diff --git a/src/test/resources/suites/suiteOne.xml b/src/test/resources/suites/suiteOne.xml index a8c3bd28..dfa78b21 100644 --- a/src/test/resources/suites/suiteOne.xml +++ b/src/test/resources/suites/suiteOne.xml @@ -15,6 +15,9 @@ + + +