From 25d59bedbfd84dcbadd00cfbca9c49cd1c55b73e Mon Sep 17 00:00:00 2001 From: Daniel <59575049+lumijiez@users.noreply.github.com> Date: Tue, 15 Oct 2024 02:11:01 +0300 Subject: [PATCH] better styling, fixed some logic --- pom.xml | 1 + .../lumijiez/monoalpha/MainController.java | 117 ++------ .../org/lumijiez/monoalpha/MonoAlpha.java | 10 +- .../monoalpha/util/CharacterSwitcher.java | 33 ++- .../lumijiez/monoalpha/util/GlobalVars.java | 5 + .../monoalpha/util/InputAnalyzer.java | 97 +++++-- .../monoalpha/util/PatternGenerator.java | 82 ++++++ .../org/lumijiez/monoalpha/monoalpha.fxml | 271 +++++++++--------- 8 files changed, 363 insertions(+), 253 deletions(-) create mode 100644 src/main/java/org/lumijiez/monoalpha/util/GlobalVars.java create mode 100644 src/main/java/org/lumijiez/monoalpha/util/PatternGenerator.java diff --git a/pom.xml b/pom.xml index b5af8ca..b1e0477 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ atlantafx-base 2.0.1 + org.junit.jupiter junit-jupiter-api diff --git a/src/main/java/org/lumijiez/monoalpha/MainController.java b/src/main/java/org/lumijiez/monoalpha/MainController.java index 745a938..3e48d6b 100644 --- a/src/main/java/org/lumijiez/monoalpha/MainController.java +++ b/src/main/java/org/lumijiez/monoalpha/MainController.java @@ -2,26 +2,27 @@ package org.lumijiez.monoalpha; import javafx.fxml.FXML; import javafx.scene.chart.BarChart; -import javafx.scene.chart.XYChart; import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; +import javafx.scene.text.Text; +import javafx.scene.text.TextFlow; import org.lumijiez.monoalpha.util.CharacterSwitcher; import org.lumijiez.monoalpha.util.InputAnalyzer; +import org.lumijiez.monoalpha.util.PatternGenerator; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.lumijiez.monoalpha.util.GlobalVars.RAINBOW; +import static org.lumijiez.monoalpha.util.PatternGenerator.matchPattern; + public class MainController { @FXML - private BarChart barChart; + private BarChart barChart; @FXML private TextArea inputArea; @@ -30,7 +31,7 @@ public class MainController { private TextArea ruleArea; @FXML - private TextArea outputArea; + private TextFlow outputArea; @FXML private TextField patternInput; @@ -41,98 +42,38 @@ public class MainController { @FXML private TextArea patternOutput; - private Map> dictionaryMap; + @FXML + private CheckBox rainbowCheckbox; + + private final Map> dictionaryMap = new HashMap<>(); @FXML private void initialize() { analyzeText(); - loadDictionary(); - barChart.setStyle("-fx-font-size: 18px;"); + PatternGenerator.loadDictionary(dictionaryMap, patternOutput); + //barChart.setStyle("-fx-font-size: 18px;"); inputArea.textProperty().addListener((observable, oldValue, newValue) -> { analyzeText(); - applyChanges(); + applyChanges(ruleArea.getText()); + }); + ruleArea.textProperty().addListener((observable, oldValue, newValue) -> applyChanges(newValue)); + patternButton.setOnAction(e -> matchPattern(patternInput.getText().trim(), patternOutput, dictionaryMap)); + rainbowCheckbox.selectedProperty().addListener((observable, oldValue, newValue) -> { + RAINBOW = newValue; + analyzeText(); }); - ruleArea.textProperty().addListener((observable, oldValue, newValue) -> applyChanges()); - patternButton.setOnAction(e -> matchPattern()); } @FXML private void analyzeText() { - String inputText = inputArea.getText(); - Map frequencyMap = InputAnalyzer.analyzeFrequency(inputText); - List> barChartData = InputAnalyzer.getBarChartData(frequencyMap); - InputAnalyzer.updateBarChart(barChart, barChartData); + String input = inputArea.getText(); + Map frequencyMap = InputAnalyzer.analyzeFrequency(input); + InputAnalyzer.updateBarChart(barChart, frequencyMap); } - private void applyChanges() { - String rules = ruleArea.getText(); - String changedText = CharacterSwitcher.applyRules(rules, inputArea.getText()); - outputArea.setText(changedText); - } - - private void loadDictionary() { - dictionaryMap = new HashMap<>(); - - try (InputStream is = getClass().getResourceAsStream("/org/lumijiez/monoalpha/dictionary.txt")) { - assert is != null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { - - String line; - while ((line = reader.readLine()) != null) { - String[] parts = line.split(" "); - if (parts.length == 2) { - String pattern = parts[0]; - String word = parts[1]; - dictionaryMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word); - } - } - - } - } catch (IOException e) { - e.printStackTrace(); - patternOutput.setText("Error loading dictionary"); - } - } - - private void matchPattern() { - String inputWord = patternInput.getText().trim(); - if (inputWord.isEmpty()) { - patternOutput.setText("Please enter a word."); - return; - } - - String inputPattern = generatePattern(inputWord); - - List matchingWords = dictionaryMap.getOrDefault(inputPattern, new ArrayList<>()); - - if (matchingWords.isEmpty()) { - patternOutput.setText("No matching words found."); - } else { - patternOutput.setText(String.join("\n", matchingWords)); - } - } - - private String generatePattern(String word) { - StringBuilder pattern = new StringBuilder(); - char nextLower = 'a'; - char nextUpper = 'A'; - Map charMap = new HashMap<>(); - - for (char c : word.toCharArray()) { - if (Character.isLowerCase(c)) { - if (!charMap.containsKey(c)) { - charMap.put(c, nextLower++); - } - pattern.append(charMap.get(c)); - } else if (Character.isUpperCase(c)) { - if (!charMap.containsKey(c)) { - charMap.put(c, nextUpper++); - } - pattern.append(charMap.get(c)); - } else { - pattern.append(c); - } - } - return pattern.toString(); + private void applyChanges(String input) { + List textNodes = CharacterSwitcher.applyRules(input, inputArea.getText()); + outputArea.getChildren().clear(); + outputArea.getChildren().addAll(textNodes); } } \ No newline at end of file diff --git a/src/main/java/org/lumijiez/monoalpha/MonoAlpha.java b/src/main/java/org/lumijiez/monoalpha/MonoAlpha.java index ea989c6..41fd15a 100644 --- a/src/main/java/org/lumijiez/monoalpha/MonoAlpha.java +++ b/src/main/java/org/lumijiez/monoalpha/MonoAlpha.java @@ -1,24 +1,18 @@ package org.lumijiez.monoalpha; -import atlantafx.base.theme.Dracula; +import atlantafx.base.theme.PrimerLight; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; -import javafx.scene.image.Image; -import javafx.scene.layout.BackgroundImage; -import javafx.scene.layout.BackgroundPosition; -import javafx.scene.layout.BackgroundRepeat; -import javafx.scene.layout.BackgroundSize; import javafx.stage.Stage; import java.io.IOException; -import java.util.Objects; public class MonoAlpha extends Application { @Override public void start(Stage stage) throws IOException { - Application.setUserAgentStylesheet(new Dracula().getUserAgentStylesheet()); + Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet()); FXMLLoader fxmlLoader = new FXMLLoader(MonoAlpha.class.getResource("monoalpha.fxml")); Scene scene = new Scene(fxmlLoader.load(), 1280, 720); diff --git a/src/main/java/org/lumijiez/monoalpha/util/CharacterSwitcher.java b/src/main/java/org/lumijiez/monoalpha/util/CharacterSwitcher.java index 6b53ec9..6f66b4c 100644 --- a/src/main/java/org/lumijiez/monoalpha/util/CharacterSwitcher.java +++ b/src/main/java/org/lumijiez/monoalpha/util/CharacterSwitcher.java @@ -1,30 +1,53 @@ package org.lumijiez.monoalpha.util; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; + +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class CharacterSwitcher { - public static String applyRules(String rulesInput, String text) { + + public static List applyRules(String rulesInput, String text) { Map ruleMap = new HashMap<>(); String[] rules = rulesInput.split(";"); + for (String rule : rules) { String[] parts = rule.split(">"); if (parts.length != 2 || parts[0].trim().length() != 1 || parts[1].trim().length() != 1) { - return "BAD RULE"; + List errorText = new ArrayList<>(); + errorText.add(createErrorText()); + return errorText; } char from = parts[0].trim().charAt(0); char to = parts[1].trim().charAt(0); ruleMap.put(from, to); } - StringBuilder result = new StringBuilder(); + text = text.replaceAll("\\r?\\n", ""); + + List textNodes = new ArrayList<>(); for (char c : text.toCharArray()) { char newChar = ruleMap.getOrDefault(c, c); - result.append(newChar); + Text textNode = new Text(newChar + ""); + + if (c != newChar) { + textNode.setFill(Color.RED); + } + + textNodes.add(textNode); } - return result.toString(); + return textNodes; + } + + private static Text createErrorText() { + Text errorText = new Text("BAD RULE"); + errorText.setFill(Color.RED); + return errorText; } } diff --git a/src/main/java/org/lumijiez/monoalpha/util/GlobalVars.java b/src/main/java/org/lumijiez/monoalpha/util/GlobalVars.java new file mode 100644 index 0000000..ff5b4f7 --- /dev/null +++ b/src/main/java/org/lumijiez/monoalpha/util/GlobalVars.java @@ -0,0 +1,5 @@ +package org.lumijiez.monoalpha.util; + +public class GlobalVars { + public static boolean RAINBOW = false; +} diff --git a/src/main/java/org/lumijiez/monoalpha/util/InputAnalyzer.java b/src/main/java/org/lumijiez/monoalpha/util/InputAnalyzer.java index efda703..c3e3961 100644 --- a/src/main/java/org/lumijiez/monoalpha/util/InputAnalyzer.java +++ b/src/main/java/org/lumijiez/monoalpha/util/InputAnalyzer.java @@ -8,45 +8,102 @@ import javafx.util.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.stream.Collectors; +import static org.lumijiez.monoalpha.util.GlobalVars.RAINBOW; + public class InputAnalyzer { + private static final Map ENGLISH_FREQUENCIES = createEnglishFrequencies(); + private static final Random RANDOM = new Random(); + + private static Map createEnglishFrequencies() { + Map frequencies = new HashMap<>(); + String[] letters = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", + "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", + "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", + "y", "z"}; + double[] frequenciesValues = {8.17, 1.49, 2.78, 4.25, 12.70, 2.23, 2.01, 6.09, 6.97, 0.15, + 0.77, 4.03, 2.41, 6.75, 7.51, 1.93, 0.09, 5.99, 6.33, 9.06, + 2.76, 0.98, 2.36, 0.15, 1.97, 0.07, 8.17, 1.49, 2.78, 4.25, + 12.70, 2.23, 2.01, 6.09, 6.97, 0.15, 0.77, 4.03, 2.41, 6.75, + 7.51, 1.93, 0.09, 5.99, 6.33, 9.06, 2.76, 0.98, 2.36, 0.15, + 1.97, 0.07}; + + for (int i = 0; i < letters.length; i++) { + frequencies.put(letters[i], frequenciesValues[i]); + } + return frequencies; + } + public static Map analyzeFrequency(String text) { Map frequencyMap = new HashMap<>(); - for (char ch : text.toCharArray()) { - if (Character.isLetter(ch)) { - frequencyMap.put(ch, frequencyMap.getOrDefault(ch, 0) + 1); - } - } + text.chars() + .filter(Character::isLetter) + .forEach(ch -> frequencyMap.merge((char) ch, 1, Integer::sum)); return frequencyMap; } - public static List> getBarChartData(Map frequencyMap) { + public static List> getBarChartData(Map frequencyMap) { + int totalCount = frequencyMap.values().stream().mapToInt(Integer::intValue).sum(); return frequencyMap.entrySet().stream() - .map(entry -> new XYChart.Data<>(entry.getKey().toString(), entry.getValue())) + .map(entry -> new XYChart.Data<>(entry.getKey().toString(), (entry.getValue() / (double) totalCount) * 100)) .collect(Collectors.toList()); } - public static void updateBarChart(BarChart barChart, List> data) { + public static List> getStaticEnglishFrequencies() { + return ENGLISH_FREQUENCIES.entrySet().stream() + .map(entry -> new XYChart.Data<>(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } + + public static void updateBarChart(BarChart barChart, Map frequencyMap) { barChart.getData().clear(); - XYChart.Series series = new XYChart.Series<>(); - for (XYChart.Data datum : data) { - series.getData().add(new XYChart.Data<>(datum.getXValue(), datum.getYValue())); + List> actualData = getBarChartData(frequencyMap); + List> englishData = getStaticEnglishFrequencies(); + + barChart.getData().add(createSeries("Actual Frequency", actualData, true)); // Random colors + barChart.getData().add(createSeries("English Frequency", englishData, false)); // Constant color + + setTooltips(barChart.getData().get(0)); + setTooltips(barChart.getData().get(1)); + } + + private static XYChart.Series createSeries(String name, List> data, boolean randomizeColor) { + XYChart.Series series = new XYChart.Series<>(); + series.setName(name); + for (XYChart.Data datum : data) { + XYChart.Data barData = new XYChart.Data<>(datum.getXValue(), datum.getYValue()); + barData.nodeProperty().addListener((obs, oldNode, newNode) -> { + if (RAINBOW && randomizeColor && newNode != null) { + String color = randomColor(); + newNode.setStyle("-fx-bar-fill: " + color + ";"); + } + }); + series.getData().add(barData); } + setTooltips(series); + return series; + } - barChart.getXAxis().setAnimated(false); - barChart.getData().add(series); - - for (XYChart.Data datum : series.getData()) { - Tooltip tooltip = new Tooltip("Frequency: " + datum.getYValue()); - - tooltip.setShowDelay(new Duration(0)); - tooltip.setHideDelay(new Duration(0)); + private static String randomColor() { + int r = RANDOM.nextInt(256); + int g = RANDOM.nextInt(256); + int b = RANDOM.nextInt(256); + return String.format("rgb(%d,%d,%d)", r, g, b); + } + private static void setTooltips(XYChart.Series series) { + for (XYChart.Data datum : series.getData()) { + String tooltipText = String.format("%s: %.2f%%", series.getName(), (Double) datum.getYValue()); + Tooltip tooltip = new Tooltip(tooltipText); + tooltip.setShowDelay(Duration.ZERO); + tooltip.setHideDelay(Duration.ZERO); Tooltip.install(datum.getNode(), tooltip); } } } - diff --git a/src/main/java/org/lumijiez/monoalpha/util/PatternGenerator.java b/src/main/java/org/lumijiez/monoalpha/util/PatternGenerator.java new file mode 100644 index 0000000..380e238 --- /dev/null +++ b/src/main/java/org/lumijiez/monoalpha/util/PatternGenerator.java @@ -0,0 +1,82 @@ +package org.lumijiez.monoalpha.util; + +import javafx.scene.control.TextArea; +import org.lumijiez.monoalpha.MainController; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PatternGenerator { + + public static String generatePattern(String word) { + StringBuilder pattern = new StringBuilder(); + char nextLower = 'a'; + char nextUpper = 'A'; + Map charMap = new HashMap<>(); + + for (char c : word.toCharArray()) { + if (Character.isLowerCase(c)) { + if (!charMap.containsKey(c)) { + charMap.put(c, nextLower++); + } + pattern.append(charMap.get(c)); + } else if (Character.isUpperCase(c)) { + if (!charMap.containsKey(c)) { + charMap.put(c, nextUpper++); + } + pattern.append(charMap.get(c)); + } else { + pattern.append(c); + } + } + return pattern.toString(); + } + + public static void loadDictionary(Map> dictionaryMap, TextArea textArea) { + + try (InputStream is = MainController.class.getResourceAsStream("/org/lumijiez/monoalpha/dictionary.txt")) { + assert is != null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split(" "); + if (parts.length == 2) { + String pattern = parts[0]; + String word = parts[1]; + dictionaryMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word); + } + } + + } + } catch (IOException e) { + System.out.println(e.getMessage()); + textArea.setText("Error loading dictionary"); + } + } + + public static void matchPattern(String inputWord, TextArea patternOutput, Map> dictionaryMap) { + + if (inputWord.isEmpty()) { + patternOutput.setText("Please enter a word."); + return; + } + + String inputPattern = generatePattern(inputWord); + + List matchingWords = dictionaryMap.getOrDefault(inputPattern, new ArrayList<>()); + + if (matchingWords.isEmpty()) { + patternOutput.setText("No matching words found."); + } else { + patternOutput.setText(String.join("\n", matchingWords)); + } + } + +} diff --git a/src/main/resources/org/lumijiez/monoalpha/monoalpha.fxml b/src/main/resources/org/lumijiez/monoalpha/monoalpha.fxml index 3ab276d..9ebefdf 100644 --- a/src/main/resources/org/lumijiez/monoalpha/monoalpha.fxml +++ b/src/main/resources/org/lumijiez/monoalpha/monoalpha.fxml @@ -4,161 +4,168 @@ + + - + - - - - - - - - - - + + + + + + + + - + - - + + - - - - + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + -