From 37a94e563e523e74bf1118f7aba6c36e4cec988e Mon Sep 17 00:00:00 2001 From: ganesh47 <22994026+ganesh47@users.noreply.github.com> Date: Sun, 15 Jun 2025 12:32:05 +0530 Subject: [PATCH 1/2] Apply formatting to fix checkstyle warnings and optimize totient --- .../java/org/nintynine/problems/BTree54.java | 332 ++++++------ .../java/org/nintynine/problems/BTreeP56.java | 90 ++-- .../java/org/nintynine/problems/BTreeP57.java | 113 ++-- .../java/org/nintynine/problems/BTreeP58.java | 194 +++---- .../java/org/nintynine/problems/BTreeP59.java | 201 ++++---- .../java/org/nintynine/problems/BTreeP60.java | 210 ++++---- .../java/org/nintynine/problems/BTreeP61.java | 33 +- .../java/org/nintynine/problems/BTreeP68.java | 7 +- .../java/org/nintynine/problems/BTreeP69.java | 17 +- .../java/org/nintynine/problems/MathP31.java | 67 ++- .../java/org/nintynine/problems/MathP32.java | 101 ++-- .../java/org/nintynine/problems/MathP33.java | 37 +- .../java/org/nintynine/problems/MathP34.java | 95 ++-- .../java/org/nintynine/problems/MathP35.java | 87 ++-- .../java/org/nintynine/problems/MathP36.java | 141 +++-- .../java/org/nintynine/problems/MathP37.java | 183 ++++--- .../java/org/nintynine/problems/MathP38.java | 481 +++++++++--------- .../java/org/nintynine/problems/MathP40.java | 231 ++++----- .../java/org/nintynine/problems/MathP41.java | 217 ++++---- .../java/org/nintynine/problems/MathP43.java | 107 ++-- .../java/org/nintynine/problems/MathP50.java | 382 +++++++------- .../java/org/nintynine/problems/MyList.java | 58 +-- .../org/nintynine/problems/MyListP02.java | 44 +- .../org/nintynine/problems/MyListP03.java | 24 +- .../org/nintynine/problems/MyListP04.java | 18 +- .../org/nintynine/problems/MyListP05.java | 37 +- .../org/nintynine/problems/MyListP06.java | 19 +- .../org/nintynine/problems/MyListP07.java | 36 +- .../org/nintynine/problems/MyListP08.java | 31 +- .../org/nintynine/problems/MyListP09.java | 105 ++-- .../org/nintynine/problems/MyListP10.java | 133 ++--- .../org/nintynine/problems/MyListP11.java | 82 +-- .../org/nintynine/problems/MyListP12.java | 93 ++-- .../org/nintynine/problems/MyListP13.java | 166 +++--- .../org/nintynine/problems/MyListP14.java | 71 ++- .../org/nintynine/problems/MyListP15.java | 81 ++- .../org/nintynine/problems/MyListP16.java | 84 ++- .../org/nintynine/problems/MyListP17.java | 107 ++-- .../org/nintynine/problems/MyListP18.java | 99 ++-- .../org/nintynine/problems/MyListP19.java | 101 ++-- .../org/nintynine/problems/MyListP20.java | 94 ++-- .../org/nintynine/problems/MyListP21.java | 97 ++-- .../org/nintynine/problems/MyListP22.java | 81 +-- .../org/nintynine/problems/MyListP23.java | 95 ++-- .../org/nintynine/problems/MyListP24.java | 87 ++-- .../org/nintynine/problems/MyListP25.java | 57 ++- .../org/nintynine/problems/MyListP26.java | 134 ++--- .../org/nintynine/problems/MyListP27.java | 200 ++++---- .../org/nintynine/problems/MyListP28.java | 167 +++--- .../java/org/nintynine/problems/TruthP46.java | 343 ++++++------- .../java/org/nintynine/problems/TruthP47.java | 454 ++++++++--------- .../java/org/nintynine/problems/TruthP48.java | 404 ++++++++------- .../java/org/nintynine/problems/TruthP55.java | 178 ++++--- .../org/nintynine/problems/BTree54Test.java | 161 +++--- .../org/nintynine/problems/BTreeP56Test.java | 92 ++-- .../org/nintynine/problems/BTreeP57Test.java | 111 ++-- .../org/nintynine/problems/BTreeP58Test.java | 63 +-- .../org/nintynine/problems/BTreeP59Test.java | 80 +-- .../org/nintynine/problems/BTreeP60Test.java | 174 +++---- .../org/nintynine/problems/BTreeP61Test.java | 107 ++-- .../org/nintynine/problems/BTreeP68Test.java | 189 ++++--- .../org/nintynine/problems/BTreeP69Test.java | 4 +- .../org/nintynine/problems/MathP31Test.java | 76 +-- .../org/nintynine/problems/MathP32Test.java | 100 ++-- .../org/nintynine/problems/MathP33Test.java | 166 +++--- .../org/nintynine/problems/MathP34Test.java | 145 +++--- .../org/nintynine/problems/MathP35Test.java | 169 +++--- .../org/nintynine/problems/MathP36Test.java | 198 ++++--- .../org/nintynine/problems/MathP37Test.java | 206 ++++---- .../org/nintynine/problems/MathP38Test.java | 126 ++--- .../org/nintynine/problems/MathP39Test.java | 253 +++++---- .../org/nintynine/problems/MathP40Test.java | 250 +++++---- .../org/nintynine/problems/MathP41Test.java | 183 ++++--- .../org/nintynine/problems/MathP43Test.java | 179 ++++--- .../org/nintynine/problems/MathP50Test.java | 260 +++++----- .../org/nintynine/problems/MyListP01Test.java | 128 +++-- .../org/nintynine/problems/MyListP02Test.java | 103 ++-- .../org/nintynine/problems/MyListP03Test.java | 111 ++-- .../org/nintynine/problems/MyListP04Test.java | 77 +-- .../org/nintynine/problems/MyListP05Test.java | 101 ++-- .../org/nintynine/problems/MyListP06Test.java | 38 +- .../org/nintynine/problems/MyListP07Test.java | 165 +++--- .../org/nintynine/problems/MyListP08Test.java | 153 +++--- .../org/nintynine/problems/MyListP09Test.java | 229 ++++----- .../org/nintynine/problems/MyListP10Test.java | 224 ++++---- .../org/nintynine/problems/MyListP11Test.java | 218 ++++---- .../org/nintynine/problems/MyListP12Test.java | 272 +++++----- .../org/nintynine/problems/MyListP13Test.java | 235 ++++----- .../org/nintynine/problems/MyListP14Test.java | 274 +++++----- .../org/nintynine/problems/MyListP15Test.java | 266 +++++----- .../org/nintynine/problems/MyListP16Test.java | 264 +++++----- .../org/nintynine/problems/MyListP17Test.java | 282 +++++----- .../org/nintynine/problems/MyListP18Test.java | 316 ++++++------ .../org/nintynine/problems/MyListP19Test.java | 331 ++++++------ .../org/nintynine/problems/MyListP20Test.java | 375 +++++++------- .../org/nintynine/problems/MyListP21Test.java | 422 +++++++-------- .../org/nintynine/problems/MyListP22Test.java | 360 ++++++------- .../org/nintynine/problems/MyListP23Test.java | 329 ++++++------ .../org/nintynine/problems/MyListP24Test.java | 364 +++++++------ .../org/nintynine/problems/MyListP25Test.java | 365 ++++++------- .../org/nintynine/problems/MyListP26Test.java | 392 +++++++------- .../org/nintynine/problems/MyListP27Test.java | 329 ++++++------ .../org/nintynine/problems/MyListP28Test.java | 350 ++++++------- .../org/nintynine/problems/TruthP46Test.java | 217 ++++---- .../org/nintynine/problems/TruthP47Test.java | 237 ++++----- .../org/nintynine/problems/TruthP48Test.java | 313 ++++++------ .../org/nintynine/problems/TruthP55Test.java | 206 ++++---- 107 files changed, 8890 insertions(+), 9554 deletions(-) diff --git a/src/main/java/org/nintynine/problems/BTree54.java b/src/main/java/org/nintynine/problems/BTree54.java index 3bb43eb..e5aa65c 100644 --- a/src/main/java/org/nintynine/problems/BTree54.java +++ b/src/main/java/org/nintynine/problems/BTree54.java @@ -2,212 +2,212 @@ import java.util.Objects; -/** - * P54A: Check whether a given expression represents a binary tree - */ +/** P54A: Check whether a given expression represents a binary tree */ public class BTree54 { + /** Represents a node in the binary tree expression */ + public static class BTree54Node { + private final String value; + private final BTree54Node left; + private final BTree54Node right; + /** - * Represents a node in the binary tree expression + * Constructs a binary tree node + * + * @param value The value at this node + * @param left Left child node or null + * @param right Right child node or null */ - public static class BTree54Node { - private final String value; - private final BTree54Node left; - private final BTree54Node right; - - /** - * Constructs a binary tree node - * @param value The value at this node - * @param left Left child node or null - * @param right Right child node or null - */ - public BTree54Node(String value, BTree54Node left, BTree54Node right) { - this.value = Objects.requireNonNull(value, "Node value cannot be null"); - this.left = left; - this.right = right; - } - - /** - * Creates a leaf node with no children - * @param value The value at this node - */ - public BTree54Node(String value) { - this(value, null, null); - } + public BTree54Node(String value, BTree54Node left, BTree54Node right) { + this.value = Objects.requireNonNull(value, "Node value cannot be null"); + this.left = left; + this.right = right; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof BTree54Node bTree54Node)) return false; - return Objects.equals(value, bTree54Node.value) && - Objects.equals(left, bTree54Node.left) && - Objects.equals(right, bTree54Node.right); - } + /** + * Creates a leaf node with no children + * + * @param value The value at this node + */ + public BTree54Node(String value) { + this(value, null, null); + } - @Override - public int hashCode() { - return Objects.hash(value, left, right); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BTree54Node bTree54Node)) return false; + return Objects.equals(value, bTree54Node.value) + && Objects.equals(left, bTree54Node.left) + && Objects.equals(right, bTree54Node.right); + } - @Override - public String toString() { - if (left == null && right == null) { - if (value.startsWith("(")) { - return value; - } - return String.format("(%s nil nil)", value); - } - return String.format("(%s %s %s)", - value, - left == null ? "nil" : left.toString(), - right == null ? "nil" : right.toString() - ); - } + @Override + public int hashCode() { + return Objects.hash(value, left, right); + } + @Override + public String toString() { + if (left == null && right == null) { + if (value.startsWith("(")) { + return value; + } + return String.format("(%s nil nil)", value); + } + return String.format( + "(%s %s %s)", + value, left == null ? "nil" : left.toString(), right == null ? "nil" : right.toString()); } + } - private BTree54() {} // Prevent instantiation + private BTree54() {} // Prevent instantiation -private static boolean isValidValue(String value) { + private static boolean isValidValue(String value) { // Check for any special characters or improper formatting - return value != null && !value.isEmpty() && - !value.contains("(") && !value.contains(")") && - !value.contains(",") && !value.contains(" ") && - !"nil".equals(value); -} - -public static boolean isTree(String expression) { + return value != null + && !value.isEmpty() + && !value.contains("(") + && !value.contains(")") + && !value.contains(",") + && !value.contains(" ") + && !"nil".equals(value); + } + + public static boolean isTree(String expression) { if (expression == null || expression.trim().isEmpty()) { - return false; + return false; } // Pre-validate the expression format String trimmed = expression.trim(); - + // Check for invalid formatting patterns - if (trimmed.contains(")(") || // Multiple expressions - trimmed.contains(",") || // Commas - trimmed.matches(".*\\w\\(.*") || // No space before opening parenthesis - trimmed.matches(".*\\)\\w.*")) { // No space after closing parenthesis - return false; + if (trimmed.contains(")(") + || // Multiple expressions + trimmed.contains(",") + || // Commas + trimmed.matches(".*\\w\\(.*") + || // No space before opening parenthesis + trimmed.matches(".*\\)\\w.*")) { // No space after closing parenthesis + return false; } try { - // Handle single value case - if (!trimmed.startsWith("(")) { - return isValidValue(trimmed); - } - - // For expressions in parentheses, try parsing - parseTree(trimmed); - return true; + // Handle single value case + if (!trimmed.startsWith("(")) { + return isValidValue(trimmed); + } + + // For expressions in parentheses, try parsing + parseTree(trimmed); + return true; } catch (IllegalArgumentException _) { - return false; + return false; + } + } + + /** + * Parses a string expression into a binary tree. + * + * @param expression The string expression to parse + * @return The root node of the parsed tree + * @throws IllegalArgumentException if the expression is invalid + */ + public static BTree54Node parseTree(String expression) { + if (expression == null) { + throw new IllegalArgumentException("Expression cannot be null"); } -} - /** - * Parses a string expression into a binary tree. - * - * @param expression The string expression to parse - * @return The root node of the parsed tree - * @throws IllegalArgumentException if the expression is invalid - */ - public static BTree54Node parseTree(String expression) { - if (expression == null) { - throw new IllegalArgumentException("Expression cannot be null"); - } + expression = expression.trim(); - expression = expression.trim(); - - // Handle single value case - if (!expression.startsWith("(")) { - if (isValidValue(expression)) { - return new BTree54Node(expression); - } - throw new IllegalArgumentException("Invalid value: " + expression); - } + // Handle single value case + if (!expression.startsWith("(")) { + if (isValidValue(expression)) { + return new BTree54Node(expression); + } + throw new IllegalArgumentException("Invalid value: " + expression); + } - // Remove outer parentheses - if (!expression.endsWith(")")) { - throw new IllegalArgumentException("Missing closing parenthesis"); - } - expression = expression.substring(1, expression.length() - 1).trim(); + // Remove outer parentheses + if (!expression.endsWith(")")) { + throw new IllegalArgumentException("Missing closing parenthesis"); + } + expression = expression.substring(1, expression.length() - 1).trim(); - // Split into value and subtrees - String[] parts = splitExpression(expression); - if (parts.length != 3) { - throw new IllegalArgumentException("Invalid node format"); - } + // Split into value and subtrees + String[] parts = splitExpression(expression); + if (parts.length != 3) { + throw new IllegalArgumentException("Invalid node format"); + } - String value = parts[0]; - String leftExpr = parts[1]; - String rightExpr = parts[2]; + String value = parts[0]; + String leftExpr = parts[1]; + String rightExpr = parts[2]; - if (!isValidValue(value)) { - throw new IllegalArgumentException("Invalid node value"); - } + if (!isValidValue(value)) { + throw new IllegalArgumentException("Invalid node value"); + } - BTree54Node left = "nil".equals(leftExpr) ? null : parseTree(leftExpr); - BTree54Node right = "nil".equals(rightExpr) ? null : parseTree(rightExpr); + BTree54Node left = "nil".equals(leftExpr) ? null : parseTree(leftExpr); + BTree54Node right = "nil".equals(rightExpr) ? null : parseTree(rightExpr); - return new BTree54Node(value, left, right); - } + return new BTree54Node(value, left, right); + } -@SuppressWarnings("java:S5852") -private static String[] splitExpression(String expr) { + @SuppressWarnings("java:S5852") + private static String[] splitExpression(String expr) { // Add space validation if (expr.contains(")(") || expr.matches(".*\\w\\(.*") || expr.matches(".*\\)\\w.*")) { - throw new IllegalArgumentException("Invalid expression format"); + throw new IllegalArgumentException("Invalid expression format"); } String[] result = new String[3]; int idx = 0; - StringBuilder current = new StringBuilder(); - int parenthesesCount = 0; - - for (char c : expr.toCharArray()) { - if (c == '(') { - parenthesesCount++; - current.append(c); - } else if (c == ')') { - parenthesesCount--; - current.append(c); - if (parenthesesCount < 0) { - throw new IllegalArgumentException("Unmatched parentheses"); - } - } else if (c == ' ' && parenthesesCount == 0 && !current.isEmpty()) { - // Only split on space when not inside parentheses - if (idx >= 3) { - throw new IllegalArgumentException("Too many parts in expression"); - } - result[idx++] = current.toString(); - current = new StringBuilder(); - } else if (c != ' ' || parenthesesCount > 0) { - current.append(c); - } - } - - if (!current.isEmpty()) { - if (idx >= 3) { - throw new IllegalArgumentException("Too many parts in expression"); - } - result[idx] = current.toString(); - } + StringBuilder current = new StringBuilder(); + int parenthesesCount = 0; + + for (char c : expr.toCharArray()) { + if (c == '(') { + parenthesesCount++; + current.append(c); + } else if (c == ')') { + parenthesesCount--; + current.append(c); + if (parenthesesCount < 0) { + throw new IllegalArgumentException("Unmatched parentheses"); + } + } else if (c == ' ' && parenthesesCount == 0 && !current.isEmpty()) { + // Only split on space when not inside parentheses + if (idx >= 3) { + throw new IllegalArgumentException("Too many parts in expression"); + } + result[idx++] = current.toString(); + current = new StringBuilder(); + } else if (c != ' ' || parenthesesCount > 0) { + current.append(c); + } + } - // Must have exactly three parts - if (idx != 2 || result[0] == null || result[1] == null || result[2] == null) { - throw new IllegalArgumentException("Invalid expression format"); - } + if (!current.isEmpty()) { + if (idx >= 3) { + throw new IllegalArgumentException("Too many parts in expression"); + } + result[idx] = current.toString(); + } - // Validate "nil" tokens - if (!"nil".equals(result[1]) && !result[1].startsWith("(")) { - throw new IllegalArgumentException("Invalid left child format"); - } - if (!"nil".equals(result[2]) && !result[2].startsWith("(")) { - throw new IllegalArgumentException("Invalid right child format"); - } + // Must have exactly three parts + if (idx != 2 || result[0] == null || result[1] == null || result[2] == null) { + throw new IllegalArgumentException("Invalid expression format"); + } - return result; + // Validate "nil" tokens + if (!"nil".equals(result[1]) && !result[1].startsWith("(")) { + throw new IllegalArgumentException("Invalid left child format"); + } + if (!"nil".equals(result[2]) && !result[2].startsWith("(")) { + throw new IllegalArgumentException("Invalid right child format"); } + return result; + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP56.java b/src/main/java/org/nintynine/problems/BTreeP56.java index 7e79925..6cfd7ca 100644 --- a/src/main/java/org/nintynine/problems/BTreeP56.java +++ b/src/main/java/org/nintynine/problems/BTreeP56.java @@ -1,52 +1,52 @@ package org.nintynine.problems; public class BTreeP56 { - private Node root; - - private static class Node { - T value; - Node left; - Node right; - - Node(T value) { - this.value = value; - this.left = null; - this.right = null; - } - } - - public BTreeP56() { - this.root = null; - } - - public void setRoot(T value) { - this.root = new Node<>(value); - } - - public void addLeft(T value) { - if (root == null) throw new IllegalStateException("Tree has no root"); - root.left = new Node<>(value); - } - - public void addRight(T value) { - if (root == null) throw new IllegalStateException("Tree has no root"); - root.right = new Node<>(value); - } - - public boolean isSymmetric() { - if (root == null) return true; - return isMirror(root.left, root.right); - } - @SuppressWarnings("java:S2234") // or just "S2234" - private boolean isMirror(Node left, Node right) { - // If both nodes are null, they are mirror images - if (left == null && right == null) return true; + private Node root; - // If only one node is null, they are not mirror images - if (left == null || right == null) return false; + private static class Node { + T value; + Node left; + Node right; - // Check if the structure is mirrored - return isMirror(left.left, right.right) && - isMirror(left.right, right.left); + Node(T value) { + this.value = value; + this.left = null; + this.right = null; } + } + + public BTreeP56() { + this.root = null; + } + + public void setRoot(T value) { + this.root = new Node<>(value); + } + + public void addLeft(T value) { + if (root == null) throw new IllegalStateException("Tree has no root"); + root.left = new Node<>(value); + } + + public void addRight(T value) { + if (root == null) throw new IllegalStateException("Tree has no root"); + root.right = new Node<>(value); + } + + public boolean isSymmetric() { + if (root == null) return true; + return isMirror(root.left, root.right); + } + + @SuppressWarnings("java:S2234") // or just "S2234" + private boolean isMirror(Node left, Node right) { + // If both nodes are null, they are mirror images + if (left == null && right == null) return true; + + // If only one node is null, they are not mirror images + if (left == null || right == null) return false; + + // Check if the structure is mirrored + return isMirror(left.left, right.right) && isMirror(left.right, right.left); + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP57.java b/src/main/java/org/nintynine/problems/BTreeP57.java index 8b63a14..7fa2e90 100644 --- a/src/main/java/org/nintynine/problems/BTreeP57.java +++ b/src/main/java/org/nintynine/problems/BTreeP57.java @@ -1,76 +1,79 @@ package org.nintynine.problems; public class BTreeP57> { - private Node root; + private Node root; - private static class Node { - T value; - Node left; - Node right; + private static class Node { + T value; + Node left; + Node right; - Node(T value) { - this.value = value; - this.left = null; - this.right = null; - } + Node(T value) { + this.value = value; + this.left = null; + this.right = null; } + } - public BTreeP57() { - this.root = null; - } + public BTreeP57() { + this.root = null; + } - public void construct(T[] values) { - for (T value : values) { - insert(value); - } + public void construct(T[] values) { + for (T value : values) { + insert(value); } + } + + public void insert(T value) { + root = insertRec(root, value); + } - public void insert(T value) { - root = insertRec(root, value); + private Node insertRec(Node node, T value) { + if (node == null) { + return new Node<>(value); } - private Node insertRec(Node node, T value) { - if (node == null) { - return new Node<>(value); - } + int comparison = value.compareTo(node.value); + if (comparison < 0) { + node.left = insertRec(node.left, value); + } else if (comparison > 0) { + node.right = insertRec(node.right, value); + } - int comparison = value.compareTo(node.value); - if (comparison < 0) { - node.left = insertRec(node.left, value); - } else if (comparison > 0) { - node.right = insertRec(node.right, value); - } + return node; + } - return node; - } + public boolean isSymmetric() { + return root == null || isMirror(root.left, root.right); + } - public boolean isSymmetric() { - return root == null || isMirror(root.left, root.right); + @SuppressWarnings("java:S2234") + private boolean isMirror(Node left, Node right) { + if (left == null && right == null) { + return true; } - - @SuppressWarnings("java:S2234") - private boolean isMirror(Node left, Node right) { - if (left == null && right == null) { - return true; - } - if (left == null || right == null) { - return false; - } - return isMirror(left.left, right.right) && - isMirror(left.right, right.left); + if (left == null || right == null) { + return false; } + return isMirror(left.left, right.right) && isMirror(left.right, right.left); + } - // Helper method to get tree structure as a string (for testing) - public String getStructure() { - return getStructureRec(root); - } + // Helper method to get tree structure as a string (for testing) + public String getStructure() { + return getStructureRec(root); + } - private String getStructureRec(Node node) { - if (node == null) { - return "nil"; - } - return "(" + node.value + " " + - getStructureRec(node.left) + " " + - getStructureRec(node.right) + ")"; + private String getStructureRec(Node node) { + if (node == null) { + return "nil"; } + return "(" + + node.value + + " " + + getStructureRec(node.left) + + " " + + getStructureRec(node.right) + + ")"; + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP58.java b/src/main/java/org/nintynine/problems/BTreeP58.java index 4f47d67..384bf7c 100644 --- a/src/main/java/org/nintynine/problems/BTreeP58.java +++ b/src/main/java/org/nintynine/problems/BTreeP58.java @@ -1,120 +1,122 @@ package org.nintynine.problems; + import java.util.ArrayList; import java.util.List; import java.util.Objects; public class BTreeP58 { - private BTreeP58() {} - public static class BTreeP58Node { - char value; - BTreeP58Node left; - BTreeP58Node right; - - BTreeP58Node(char value) { - this.value = value; - left = null; - right = null; - } - - @Override - public int hashCode() { - return Objects.hash(left, right); - } + private BTreeP58() {} - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - BTreeP58Node bTreeP58Node = (BTreeP58Node) o; - return value == bTreeP58Node.value && - Objects.equals(left, bTreeP58Node.left) && - Objects.equals(right, bTreeP58Node.right); - } + public static class BTreeP58Node { + char value; + BTreeP58Node left; + BTreeP58Node right; - @Override - public String toString() { - if (left == null && right == null) return String.valueOf(value); - return String.format("%c(%s,%s)", value, - left == null ? "NIL" : left.toString(), - right == null ? "NIL" : right.toString()); - } + BTreeP58Node(char value) { + this.value = value; + left = null; + right = null; } - public static List symCbalTrees(int nodes) { - if (nodes % 2 == 0) return new ArrayList<>(); - return generateSymCbalTrees(nodes); + @Override + public int hashCode() { + return Objects.hash(left, right); } - private static List generateSymCbalTrees(int nodes) { - List result = new ArrayList<>(); - - if (nodes == 0) return result; - if (nodes == 1) { - result.add(new BTreeP58Node('X')); - return result; - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BTreeP58Node bTreeP58Node = (BTreeP58Node) o; + return value == bTreeP58Node.value + && Objects.equals(left, bTreeP58Node.left) + && Objects.equals(right, bTreeP58Node.right); + } - int remainingNodes = nodes - 1; - if (remainingNodes % 2 != 0) return result; - - List subtrees = generateBalancedSubtrees(remainingNodes / 2); - for (BTreeP58Node leftSubtree : subtrees) { - BTreeP58Node root = new BTreeP58Node('X'); - root.left = cloneTree(leftSubtree); - root.right = cloneTree(mirrorTree(leftSubtree)); - result.add(root); - } - - return result; + @Override + public String toString() { + if (left == null && right == null) return String.valueOf(value); + return String.format( + "%c(%s,%s)", + value, left == null ? "NIL" : left.toString(), right == null ? "NIL" : right.toString()); } + } - private static List generateBalancedSubtrees(int nodes) { - List result = new ArrayList<>(); - - if (nodes == 0) { - result.add(null); - return result; - } - if (nodes == 1) { - result.add(new BTreeP58Node('X')); - return result; - } + public static List symCbalTrees(int nodes) { + if (nodes % 2 == 0) return new ArrayList<>(); + return generateSymCbalTrees(nodes); + } - int remainingNodes = nodes - 1; - for (int leftNodes = remainingNodes / 2; leftNodes <= (remainingNodes + 1) / 2; leftNodes++) { - int rightNodes = remainingNodes - leftNodes; - List leftSubtrees = generateBalancedSubtrees(leftNodes); - List rightSubtrees = generateBalancedSubtrees(rightNodes); - - for (BTreeP58Node left : leftSubtrees) { - for (BTreeP58Node right : rightSubtrees) { - BTreeP58Node root = new BTreeP58Node('X'); - root.left = cloneTree(left); - root.right = cloneTree(right); - result.add(root); - } - } - } - return result; + private static List generateSymCbalTrees(int nodes) { + List result = new ArrayList<>(); + + if (nodes == 0) return result; + if (nodes == 1) { + result.add(new BTreeP58Node('X')); + return result; } - private static BTreeP58Node mirrorTree(BTreeP58Node root) { - if (root == null) return null; - BTreeP58Node mirrored = new BTreeP58Node(root.value); - mirrored.left = mirrorTree(root.right); - mirrored.right = mirrorTree(root.left); - return mirrored; + int remainingNodes = nodes - 1; + if (remainingNodes % 2 != 0) return result; + + List subtrees = generateBalancedSubtrees(remainingNodes / 2); + for (BTreeP58Node leftSubtree : subtrees) { + BTreeP58Node root = new BTreeP58Node('X'); + root.left = cloneTree(leftSubtree); + root.right = cloneTree(mirrorTree(leftSubtree)); + result.add(root); } - private static BTreeP58Node cloneTree(BTreeP58Node root) { - if (root == null) return null; - BTreeP58Node clone = new BTreeP58Node(root.value); - clone.left = cloneTree(root.left); - clone.right = cloneTree(root.right); - return clone; + return result; + } + + private static List generateBalancedSubtrees(int nodes) { + List result = new ArrayList<>(); + + if (nodes == 0) { + result.add(null); + return result; + } + if (nodes == 1) { + result.add(new BTreeP58Node('X')); + return result; } - public static int countSymCbalTrees(int nodes) { - return symCbalTrees(nodes).size(); + int remainingNodes = nodes - 1; + for (int leftNodes = remainingNodes / 2; leftNodes <= (remainingNodes + 1) / 2; leftNodes++) { + int rightNodes = remainingNodes - leftNodes; + List leftSubtrees = generateBalancedSubtrees(leftNodes); + List rightSubtrees = generateBalancedSubtrees(rightNodes); + + for (BTreeP58Node left : leftSubtrees) { + for (BTreeP58Node right : rightSubtrees) { + BTreeP58Node root = new BTreeP58Node('X'); + root.left = cloneTree(left); + root.right = cloneTree(right); + result.add(root); + } + } } + return result; + } + + private static BTreeP58Node mirrorTree(BTreeP58Node root) { + if (root == null) return null; + BTreeP58Node mirrored = new BTreeP58Node(root.value); + mirrored.left = mirrorTree(root.right); + mirrored.right = mirrorTree(root.left); + return mirrored; + } + + private static BTreeP58Node cloneTree(BTreeP58Node root) { + if (root == null) return null; + BTreeP58Node clone = new BTreeP58Node(root.value); + clone.left = cloneTree(root.left); + clone.right = cloneTree(root.right); + return clone; + } + + public static int countSymCbalTrees(int nodes) { + return symCbalTrees(nodes).size(); + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP59.java b/src/main/java/org/nintynine/problems/BTreeP59.java index 12d9ead..8ee4a3b 100644 --- a/src/main/java/org/nintynine/problems/BTreeP59.java +++ b/src/main/java/org/nintynine/problems/BTreeP59.java @@ -6,120 +6,119 @@ @SuppressWarnings("DuplicatedCode") public class BTreeP59 { - private BTreeP59() { + private BTreeP59() {} + + public static class BTree59Node { + char value; + BTree59Node left; + BTree59Node right; + + BTree59Node(char value) { + this.value = value; + left = null; + right = null; } - public static class BTree59Node { - char value; - BTree59Node left; - BTree59Node right; - - BTree59Node(char value) { - this.value = value; - left = null; - right = null; - } - - @Override - public int hashCode() { - return Objects.hash(value, left, right); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - BTree59Node bTree59Node = (BTree59Node) o; - return value == bTree59Node.value && - Objects.equals(left, bTree59Node.left) && - Objects.equals(right, bTree59Node.right); - } - - @Override - public String toString() { - if (left == null && right == null) return String.valueOf(value); - return String.format("%c(%s,%s)", value, - left == null ? "NIL" : left.toString(), - right == null ? "NIL" : right.toString()); - } + @Override + public int hashCode() { + return Objects.hash(value, left, right); } - public static List hbalTrees(int height) { - if (height < 0) return new ArrayList<>(); - return generateHbalTrees(height); + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BTree59Node bTree59Node = (BTree59Node) o; + return value == bTree59Node.value + && Objects.equals(left, bTree59Node.left) + && Objects.equals(right, bTree59Node.right); } - private static List generateHbalTrees(int height) { - List result = new ArrayList<>(); - - if (height == 0) { - result.add(null); - return result; - } - - if (height == 1) { - result.add(new BTree59Node('X')); - return result; - } - - // Trees of height h can have subtrees of height h-1 or h-2 - List heightMinus1 = generateHbalTrees(height - 1); - List heightMinus2 = generateHbalTrees(height - 2); - - // Case 1: Both subtrees have height h-1 - for (BTree59Node left : heightMinus1) { - for (BTree59Node right : heightMinus1) { - BTree59Node root = new BTree59Node('X'); - root.left = cloneTree(left); - root.right = cloneTree(right); - result.add(root); - } - } - - // Case 2: Left subtree has height h-1, right has height h-2 - for (BTree59Node left : heightMinus1) { - for (BTree59Node right : heightMinus2) { - BTree59Node root = new BTree59Node('X'); - root.left = cloneTree(left); - root.right = cloneTree(right); - result.add(root); - } - } - - // Case 3: Left subtree has height h-2, right has height h-1 - for (BTree59Node left : heightMinus2) { - for (BTree59Node right : heightMinus1) { - BTree59Node root = new BTree59Node('X'); - root.left = cloneTree(left); - root.right = cloneTree(right); - result.add(root); - } - } - - return result; + @Override + public String toString() { + if (left == null && right == null) return String.valueOf(value); + return String.format( + "%c(%s,%s)", + value, left == null ? "NIL" : left.toString(), right == null ? "NIL" : right.toString()); } + } + + public static List hbalTrees(int height) { + if (height < 0) return new ArrayList<>(); + return generateHbalTrees(height); + } - private static BTree59Node cloneTree(BTree59Node root) { - if (root == null) return null; - BTree59Node clone = new BTree59Node(root.value); - clone.left = cloneTree(root.left); - clone.right = cloneTree(root.right); - return clone; + private static List generateHbalTrees(int height) { + List result = new ArrayList<>(); + + if (height == 0) { + result.add(null); + return result; } - public static int height(BTree59Node root) { - if (root == null) return 0; - return 1 + Math.max(height(root.left), height(root.right)); + if (height == 1) { + result.add(new BTree59Node('X')); + return result; } - protected static boolean isHeightBalanced(BTree59Node root) { - if (root == null) return true; + // Trees of height h can have subtrees of height h-1 or h-2 + List heightMinus1 = generateHbalTrees(height - 1); + List heightMinus2 = generateHbalTrees(height - 2); + + // Case 1: Both subtrees have height h-1 + for (BTree59Node left : heightMinus1) { + for (BTree59Node right : heightMinus1) { + BTree59Node root = new BTree59Node('X'); + root.left = cloneTree(left); + root.right = cloneTree(right); + result.add(root); + } + } - int leftHeight = height(root.left); - int rightHeight = height(root.right); + // Case 2: Left subtree has height h-1, right has height h-2 + for (BTree59Node left : heightMinus1) { + for (BTree59Node right : heightMinus2) { + BTree59Node root = new BTree59Node('X'); + root.left = cloneTree(left); + root.right = cloneTree(right); + result.add(root); + } + } - return Math.abs(leftHeight - rightHeight) <= 1 - && isHeightBalanced(root.left) - && isHeightBalanced(root.right); + // Case 3: Left subtree has height h-2, right has height h-1 + for (BTree59Node left : heightMinus2) { + for (BTree59Node right : heightMinus1) { + BTree59Node root = new BTree59Node('X'); + root.left = cloneTree(left); + root.right = cloneTree(right); + result.add(root); + } } + + return result; + } + + private static BTree59Node cloneTree(BTree59Node root) { + if (root == null) return null; + BTree59Node clone = new BTree59Node(root.value); + clone.left = cloneTree(root.left); + clone.right = cloneTree(root.right); + return clone; + } + + public static int height(BTree59Node root) { + if (root == null) return 0; + return 1 + Math.max(height(root.left), height(root.right)); + } + + protected static boolean isHeightBalanced(BTree59Node root) { + if (root == null) return true; + + int leftHeight = height(root.left); + int rightHeight = height(root.right); + + return Math.abs(leftHeight - rightHeight) <= 1 + && isHeightBalanced(root.left) + && isHeightBalanced(root.right); + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP60.java b/src/main/java/org/nintynine/problems/BTreeP60.java index 7f071e9..1852510 100644 --- a/src/main/java/org/nintynine/problems/BTreeP60.java +++ b/src/main/java/org/nintynine/problems/BTreeP60.java @@ -5,125 +5,125 @@ import java.util.List; public class BTreeP60 { - private final T value; - protected BTreeP60 left; - protected BTreeP60 right; - - public BTreeP60(T value) { - this.value = value; - this.left = null; - this.right = null; + private final T value; + protected BTreeP60 left; + protected BTreeP60 right; + + public BTreeP60(T value) { + this.value = value; + this.left = null; + this.right = null; + } + + public static int minNodes(int h) { + if (h <= 0) return 0; + if (h == 1) return 1; + return 1 + minNodes(h - 1) + minNodes(h - 2); + } + + public static int maxHeight(int n) { + if (n <= 0) return 0; + int h = 0; + while (minNodes(h) <= n) h++; + return h - 1; + } + + public static List> hbalTreeNodes(int n) { + if (n <= 0) return Collections.emptyList(); + if (n == 1) { + List> result = new ArrayList<>(); + result.add(new BTreeP60<>("x")); + return result; } - public static int minNodes(int h) { - if (h <= 0) return 0; - if (h == 1) return 1; - return 1 + minNodes(h - 1) + minNodes(h - 2); - } - - public static int maxHeight(int n) { - if (n <= 0) return 0; - int h = 0; - while (minNodes(h) <= n) h++; - return h - 1; - } + // Special case for 2 nodes + if (n == 2) { + List> result = new ArrayList<>(); + // Create left-child tree + BTreeP60 leftTree = new BTreeP60<>("x"); + leftTree.left = new BTreeP60<>("x"); + result.add(leftTree); - public static List> hbalTreeNodes(int n) { - if (n <= 0) return Collections.emptyList(); - if (n == 1) { - List> result = new ArrayList<>(); - result.add(new BTreeP60<>("x")); - return result; - } - - // Special case for 2 nodes - if (n == 2) { - List> result = new ArrayList<>(); - // Create left-child tree - BTreeP60 leftTree = new BTreeP60<>("x"); - leftTree.left = new BTreeP60<>("x"); - result.add(leftTree); - - // Create right-child tree - BTreeP60 rightTree = new BTreeP60<>("x"); - rightTree.right = new BTreeP60<>("x"); - result.add(rightTree); - - return result; - } + // Create right-child tree + BTreeP60 rightTree = new BTreeP60<>("x"); + rightTree.right = new BTreeP60<>("x"); + result.add(rightTree); - List> result = new ArrayList<>(); - int maxH = maxHeight(n); - int minH = (int) Math.ceil(Math.log(n + (double)1) / Math.log(2)); - - for (int h = minH; h <= maxH; h++) { - result.addAll(generateTreesWithHeight(h, n)); - } - - return result; + return result; } - private static List> generateTreesWithHeight(int height, int n) { - List> result = new ArrayList<>(); - - if (n == 0) { - return Collections.emptyList(); - } - if (n == 1) { - result.add(new BTreeP60<>("x")); - return result; - } - - for (int leftNodes = 0; leftNodes < n; leftNodes++) { - int rightNodes = n - 1 - leftNodes; - - List> leftSubtrees = hbalTreeNodes(leftNodes); - List> rightSubtrees = hbalTreeNodes(rightNodes); - - for (BTreeP60 left : leftSubtrees) { - for (BTreeP60 right : rightSubtrees) { - if (isHeightBalanced(left, right) && - getHeight(left) <= height - 1 && - getHeight(right) <= height - 1) { - BTreeP60 root = new BTreeP60<>("x"); - root.left = cloneTree(left); - root.right = cloneTree(right); - result.add(root); - } - } - } - } + List> result = new ArrayList<>(); + int maxH = maxHeight(n); + int minH = (int) Math.ceil(Math.log(n + (double) 1) / Math.log(2)); - return result; + for (int h = minH; h <= maxH; h++) { + result.addAll(generateTreesWithHeight(h, n)); } - private static boolean isHeightBalanced(BTreeP60 left, BTreeP60 right) { - return Math.abs(getHeight(left) - getHeight(right)) <= 1; - } + return result; + } - public static int getHeight(BTreeP60 node) { - if (node == null) return 0; - return 1 + Math.max(getHeight(node.left), getHeight(node.right)); - } + private static List> generateTreesWithHeight(int height, int n) { + List> result = new ArrayList<>(); - private static BTreeP60 cloneTree(BTreeP60 node) { - if (node == null) return null; - BTreeP60 clone = new BTreeP60<>(node.value); - clone.left = cloneTree(node.left); - clone.right = cloneTree(node.right); - return clone; + if (n == 0) { + return Collections.emptyList(); } - - // Getters for testing - public T getValue() { - return value; + if (n == 1) { + result.add(new BTreeP60<>("x")); + return result; } - public BTreeP60 getLeft() { - return left; + for (int leftNodes = 0; leftNodes < n; leftNodes++) { + int rightNodes = n - 1 - leftNodes; + + List> leftSubtrees = hbalTreeNodes(leftNodes); + List> rightSubtrees = hbalTreeNodes(rightNodes); + + for (BTreeP60 left : leftSubtrees) { + for (BTreeP60 right : rightSubtrees) { + if (isHeightBalanced(left, right) + && getHeight(left) <= height - 1 + && getHeight(right) <= height - 1) { + BTreeP60 root = new BTreeP60<>("x"); + root.left = cloneTree(left); + root.right = cloneTree(right); + result.add(root); + } + } + } } - public BTreeP60 getRight() { - return right; - } + return result; + } + + private static boolean isHeightBalanced(BTreeP60 left, BTreeP60 right) { + return Math.abs(getHeight(left) - getHeight(right)) <= 1; + } + + public static int getHeight(BTreeP60 node) { + if (node == null) return 0; + return 1 + Math.max(getHeight(node.left), getHeight(node.right)); + } + + private static BTreeP60 cloneTree(BTreeP60 node) { + if (node == null) return null; + BTreeP60 clone = new BTreeP60<>(node.value); + clone.left = cloneTree(node.left); + clone.right = cloneTree(node.right); + return clone; + } + + // Getters for testing + public T getValue() { + return value; + } + + public BTreeP60 getLeft() { + return left; + } + + public BTreeP60 getRight() { + return right; + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP61.java b/src/main/java/org/nintynine/problems/BTreeP61.java index 04a9931..1ce4864 100644 --- a/src/main/java/org/nintynine/problems/BTreeP61.java +++ b/src/main/java/org/nintynine/problems/BTreeP61.java @@ -1,23 +1,22 @@ package org.nintynine.problems; public class BTreeP61 extends BTreeP60 { - - public BTreeP61(T value) { - super(value); + + public BTreeP61(T value) { + super(value); + } + + public static int countLeaves(BTreeP61 tree) { + if (tree == null) { + return 0; } - - public static int countLeaves(BTreeP61 tree) { - if (tree == null) { - return 0; - } - - // A leaf is a node with no children - if (tree.getLeft() == null && tree.getRight() == null) { - return 1; - } - - // Recursively count leaves in left and right subtrees - return countLeaves((BTreeP61) tree.getLeft()) + - countLeaves((BTreeP61) tree.getRight()); + + // A leaf is a node with no children + if (tree.getLeft() == null && tree.getRight() == null) { + return 1; } + + // Recursively count leaves in left and right subtrees + return countLeaves((BTreeP61) tree.getLeft()) + countLeaves((BTreeP61) tree.getRight()); + } } diff --git a/src/main/java/org/nintynine/problems/BTreeP68.java b/src/main/java/org/nintynine/problems/BTreeP68.java index f8625a1..ba0e377 100644 --- a/src/main/java/org/nintynine/problems/BTreeP68.java +++ b/src/main/java/org/nintynine/problems/BTreeP68.java @@ -52,8 +52,11 @@ public String toString() { return String.valueOf(value); } return value - + "(" + (left == null ? "NIL" : left.toString()) - + "," + (right == null ? "NIL" : right.toString()) + ")"; + + "(" + + (left == null ? "NIL" : left.toString()) + + "," + + (right == null ? "NIL" : right.toString()) + + ")"; } } diff --git a/src/main/java/org/nintynine/problems/BTreeP69.java b/src/main/java/org/nintynine/problems/BTreeP69.java index ccd5b8a..e1badfe 100644 --- a/src/main/java/org/nintynine/problems/BTreeP69.java +++ b/src/main/java/org/nintynine/problems/BTreeP69.java @@ -3,13 +3,12 @@ /** * P69 (**): Dotstring representation of binary trees. * - *

A binary tree where nodes are identified by single characters can be - * represented as a "dotstring" using a preorder traversal in which - * null (empty) subtrees are encoded by a dot character '.'. For example - * the tree from problem P67 is encoded as {@code ABD..E..C.FG...}. + *

A binary tree where nodes are identified by single characters can be represented as a + * "dotstring" using a preorder traversal in which null (empty) subtrees are encoded by a dot + * character '.'. For example the tree from problem P67 is encoded as {@code ABD..E..C.FG...}. * - *

This class provides utility methods to convert between a tree - * structure and its dotstring representation. + *

This class provides utility methods to convert between a tree structure and its dotstring + * representation. */ @SuppressWarnings("checkstyle:AbbreviationAsWordInName") public class BTreeP69 { @@ -35,8 +34,10 @@ public String toString() { } return value + "(" - + (left == null ? "NIL" : left.toString()) + "," - + (right == null ? "NIL" : right.toString()) + ")"; + + (left == null ? "NIL" : left.toString()) + + "," + + (right == null ? "NIL" : right.toString()) + + ")"; } } diff --git a/src/main/java/org/nintynine/problems/MathP31.java b/src/main/java/org/nintynine/problems/MathP31.java index b8bc49e..98bc969 100644 --- a/src/main/java/org/nintynine/problems/MathP31.java +++ b/src/main/java/org/nintynine/problems/MathP31.java @@ -1,42 +1,39 @@ package org.nintynine.problems; -/** - * P31: Determine whether a given integer number is prime. - */ +/** P31: Determine whether a given integer number is prime. */ public class MathP31 { - private MathP31() { - } + private MathP31() {} - /** - * Determines if a number is prime. - * A prime number is a natural number greater than 1 that is only divisible by 1 and itself. - * - * @param n the number to check - * @return true if the number is prime, false otherwise - * @throws IllegalArgumentException if n is less than or equal to 0 - */ - public static boolean isPrime(long n) { - if (n <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - if (n == 1) { - return false; // 1 is not prime by definition - } - if (n == 2 || n == 3) { - return true; // 2 and 3 are prime - } - if (n % 2 == 0) { - return false; // Even numbers greater than 2 are not prime - } + /** + * Determines if a number is prime. A prime number is a natural number greater than 1 that is only + * divisible by 1 and itself. + * + * @param n the number to check + * @return true if the number is prime, false otherwise + * @throws IllegalArgumentException if n is less than or equal to 0 + */ + public static boolean isPrime(long n) { + if (n <= 0) { + throw new IllegalArgumentException("Number must be positive"); + } + if (n == 1) { + return false; // 1 is not prime by definition + } + if (n == 2 || n == 3) { + return true; // 2 and 3 are prime + } + if (n % 2 == 0) { + return false; // Even numbers greater than 2 are not prime + } - // We only need to check up to the square root of n - // Using only odd numbers since we already excluded even numbers - long sqrt = (long) Math.sqrt(n); - for (long i = 3; i <= sqrt; i += 2) { - if (n % i == 0) { - return false; - } - } - return true; + // We only need to check up to the square root of n + // Using only odd numbers since we already excluded even numbers + long sqrt = (long) Math.sqrt(n); + for (long i = 3; i <= sqrt; i += 2) { + if (n % i == 0) { + return false; + } } + return true; + } } diff --git a/src/main/java/org/nintynine/problems/MathP32.java b/src/main/java/org/nintynine/problems/MathP32.java index 524696a..65a9a40 100644 --- a/src/main/java/org/nintynine/problems/MathP32.java +++ b/src/main/java/org/nintynine/problems/MathP32.java @@ -1,62 +1,61 @@ package org.nintynine.problems; /** - * P32: Determine the greatest common divisor of two positive integer numbers using Euclid's algorithm. + * P32: Determine the greatest common divisor of two positive integer numbers using Euclid's + * algorithm. */ public class MathP32 { - private MathP32() { + private MathP32() {} + + /** + * Calculates the Greatest Common Divisor (GCD) of two numbers using Euclid's algorithm. Euclid's + * algorithm states that the greatest common divisor of two numbers a and b is the same as the + * greatest common divisor of b and the remainder of a divided by b. + * + * @param a first positive integer + * @param b second positive integer + * @return the greatest common divisor of a and b + * @throws IllegalArgumentException if either number is not positive + */ + public static long gcd(long a, long b) { + if (a <= 0 || b <= 0) { + throw new IllegalArgumentException("Both numbers must be positive"); } - /** - * Calculates the Greatest Common Divisor (GCD) of two numbers using Euclid's algorithm. - * Euclid's algorithm states that the greatest common divisor of two numbers a and b - * is the same as the greatest common divisor of b and the remainder of a divided by b. - * - * @param a first positive integer - * @param b second positive integer - * @return the greatest common divisor of a and b - * @throws IllegalArgumentException if either number is not positive - */ - public static long gcd(long a, long b) { - if (a <= 0 || b <= 0) { - throw new IllegalArgumentException("Both numbers must be positive"); - } - - // Ensure a is the larger number - if (a < b) { - long temp = a; - a = b; - b = temp; - } - - // Euclid's algorithm: gcd(a,b) = gcd(b,a mod b) - while (b != 0) { - long remainder = a % b; - a = b; - b = remainder; - } - - return a; + // Ensure a is the larger number + if (a < b) { + long temp = a; + a = b; + b = temp; } - /** - * Recursive implementation of Euclid's algorithm. - * Provided as an alternative approach. - * - * @param a first positive integer - * @param b second positive integer - * @return the greatest common divisor of a and b - * @throws IllegalArgumentException if either number is not positive - */ - public static long gcdRecursive(long a, long b) { - if (a <= 0 || b < 0) { - throw new IllegalArgumentException("Both numbers must be positive"); - } - - if (b == 0) { - return a; - } - - return gcdRecursive(b, a % b); + // Euclid's algorithm: gcd(a,b) = gcd(b,a mod b) + while (b != 0) { + long remainder = a % b; + a = b; + b = remainder; } + + return a; + } + + /** + * Recursive implementation of Euclid's algorithm. Provided as an alternative approach. + * + * @param a first positive integer + * @param b second positive integer + * @return the greatest common divisor of a and b + * @throws IllegalArgumentException if either number is not positive + */ + public static long gcdRecursive(long a, long b) { + if (a <= 0 || b < 0) { + throw new IllegalArgumentException("Both numbers must be positive"); + } + + if (b == 0) { + return a; + } + + return gcdRecursive(b, a % b); + } } diff --git a/src/main/java/org/nintynine/problems/MathP33.java b/src/main/java/org/nintynine/problems/MathP33.java index 0891ee7..288d249 100644 --- a/src/main/java/org/nintynine/problems/MathP33.java +++ b/src/main/java/org/nintynine/problems/MathP33.java @@ -1,27 +1,26 @@ package org.nintynine.problems; /** - * P33: Determine whether two positive integer numbers are coprime. - * Two numbers are coprime (or relatively prime) if their greatest common divisor equals 1. + * P33: Determine whether two positive integer numbers are coprime. Two numbers are coprime (or + * relatively prime) if their greatest common divisor equals 1. */ public class MathP33 { - private MathP33() { - } - - /** - * Determines if two numbers are coprime. - * Numbers are coprime if their greatest common divisor is 1. - * - * @param a first positive integer - * @param b second positive integer - * @return true if the numbers are coprime, false otherwise - * @throws IllegalArgumentException if either number is not positive - */ - public static boolean areCoprime(long a, long b) { - if (a <= 0 || b <= 0) { - throw new IllegalArgumentException("Both numbers must be positive"); - } + private MathP33() {} - return MathP32.gcd(a, b) == 1; + /** + * Determines if two numbers are coprime. Numbers are coprime if their greatest common divisor is + * 1. + * + * @param a first positive integer + * @param b second positive integer + * @return true if the numbers are coprime, false otherwise + * @throws IllegalArgumentException if either number is not positive + */ + public static boolean areCoprime(long a, long b) { + if (a <= 0 || b <= 0) { + throw new IllegalArgumentException("Both numbers must be positive"); } + + return MathP32.gcd(a, b) == 1; + } } diff --git a/src/main/java/org/nintynine/problems/MathP34.java b/src/main/java/org/nintynine/problems/MathP34.java index b3b75f7..b1dfad6 100644 --- a/src/main/java/org/nintynine/problems/MathP34.java +++ b/src/main/java/org/nintynine/problems/MathP34.java @@ -3,63 +3,56 @@ import java.util.stream.LongStream; /** - * P34: Calculate Euler's totient function phi(m). - * Euler's totient function phi(m) is defined as the number of positive integers r (1 <= r < m) - * that are coprime to m. + * P34: Calculate Euler's totient function phi(m). Euler's totient function phi(m) is defined as the + * number of positive integers r (1 <= r < m) that are coprime to m. */ public class MathP34 { - /** - * Calculates Euler's totient function phi(m) using the primitive method. - * For a number m, it counts how many numbers from 1 to m-1 are coprime with m. - * Special properties: - * 1. For prime numbers p, phi(p) = p-1 - * 2. For n = 1, phi(1) = 1 - * - * @param m the number to calculate phi for - * @return the value of phi(m) - * @throws IllegalArgumentException if m is not positive - */ - public static long totientPhi(long m) { - if (m <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - - if (m == 1) { - return 1; // Special case: phi(1) = 1 - } - - // For optimization, first check if m is prime - if (MathP31.isPrime(m)) { - return m - 1; // For prime p, phi(p) = p-1 - } + /** + * Calculates Euler's totient function phi(m) using the primitive method. For a number m, it + * counts how many numbers from 1 to m-1 are coprime with m. Special properties: 1. For prime + * numbers p, phi(p) = p-1 2. For n = 1, phi(1) = 1 + * + * @param m the number to calculate phi for + * @return the value of phi(m) + * @throws IllegalArgumentException if m is not positive + */ + public static long totientPhi(long m) { + if (m <= 0) { + throw new IllegalArgumentException("Number must be positive"); + } - // Primitive method: count coprime numbers from 1 to m-1 - return LongStream.range(1, m).filter(r -> MathP33.areCoprime(r, m)).count(); + if (m == 1) { + return 1; // Special case: phi(1) = 1 } - /** - * Determines if a number is prime and returns its totient value. - * This is a helper method to demonstrate the relationship between - * prime numbers and their totient values. - * - * @param m the number to check and calculate totient for - * @return a record containing whether the number is prime and its totient value - * @throws IllegalArgumentException if m is not positive - */ - public static PrimeTotientResult checkPrimeAndTotient(long m) { - boolean isPrime = MathP31.isPrime(m); - long totient = totientPhi(m); - return new PrimeTotientResult(isPrime, totient); + // For optimization, first check if m is prime + if (MathP31.isPrime(m)) { + return m - 1; // For prime p, phi(p) = p-1 } - /** - * Record to hold the result of prime check and totient calculation - */ - public record PrimeTotientResult(boolean isPrime, long totientValue) { - @Override - public String toString() { - return "Number is " + (isPrime ? "prime" : "not prime") + - ", φ(m) = " + totientValue; - } + // Primitive method: count coprime numbers from 1 to m-1 + return LongStream.range(1, m).filter(r -> MathP33.areCoprime(r, m)).count(); + } + + /** + * Determines if a number is prime and returns its totient value. This is a helper method to + * demonstrate the relationship between prime numbers and their totient values. + * + * @param m the number to check and calculate totient for + * @return a record containing whether the number is prime and its totient value + * @throws IllegalArgumentException if m is not positive + */ + public static PrimeTotientResult checkPrimeAndTotient(long m) { + boolean isPrime = MathP31.isPrime(m); + long totient = totientPhi(m); + return new PrimeTotientResult(isPrime, totient); + } + + /** Record to hold the result of prime check and totient calculation */ + public record PrimeTotientResult(boolean isPrime, long totientValue) { + @Override + public String toString() { + return "Number is " + (isPrime ? "prime" : "not prime") + ", φ(m) = " + totientValue; } + } } diff --git a/src/main/java/org/nintynine/problems/MathP35.java b/src/main/java/org/nintynine/problems/MathP35.java index 0efbe08..d10d9e0 100644 --- a/src/main/java/org/nintynine/problems/MathP35.java +++ b/src/main/java/org/nintynine/problems/MathP35.java @@ -4,54 +4,51 @@ import java.util.List; /** - * P35: Determine the prime factors of a given positive integer. - * Returns a flat list containing the prime factors in ascending order. + * P35: Determine the prime factors of a given positive integer. Returns a flat list containing the + * prime factors in ascending order. */ public class MathP35 { - private MathP35() { + private MathP35() {} + + /** + * Determines the prime factors of a given number. Returns a list of prime factors in ascending + * order, including duplicates for multiple occurrences of the same prime factor. Example: + * primeFactors(315) returns [3, 3, 5, 7] + * + * @param n the number to factorize + * @return list of prime factors in ascending order + * @throws IllegalArgumentException if n is not positive + */ + public static List primeFactors(long n) { + if (n <= 0) { + throw new IllegalArgumentException("Number must be positive"); } - /** - * Determines the prime factors of a given number. - * Returns a list of prime factors in ascending order, including duplicates - * for multiple occurrences of the same prime factor. - * Example: - * primeFactors(315) returns [3, 3, 5, 7] - * - * @param n the number to factorize - * @return list of prime factors in ascending order - * @throws IllegalArgumentException if n is not positive - */ - public static List primeFactors(long n) { - if (n <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - - List factors = new ArrayList<>(); - - if (n == 1) { - return factors; // Empty list for 1 - } - - // Handle all factors of 2 first - while (n % 2 == 0) { - factors.add(2L); - n /= 2; - } - - // Handle odd factors - for (long i = 3; i * i <= n; i += 2) { - while (n % i == 0) { - factors.add(i); - n /= i; - } - } - - // If n is greater than 2 here, it is prime - if (n > 2) { - factors.add(n); - } - - return factors; + List factors = new ArrayList<>(); + + if (n == 1) { + return factors; // Empty list for 1 + } + + // Handle all factors of 2 first + while (n % 2 == 0) { + factors.add(2L); + n /= 2; + } + + // Handle odd factors + for (long i = 3; i * i <= n; i += 2) { + while (n % i == 0) { + factors.add(i); + n /= i; + } + } + + // If n is greater than 2 here, it is prime + if (n > 2) { + factors.add(n); } + + return factors; + } } diff --git a/src/main/java/org/nintynine/problems/MathP36.java b/src/main/java/org/nintynine/problems/MathP36.java index 32f2872..1db12ac 100644 --- a/src/main/java/org/nintynine/problems/MathP36.java +++ b/src/main/java/org/nintynine/problems/MathP36.java @@ -1,93 +1,86 @@ package org.nintynine.problems; +import java.math.BigInteger; import java.util.ArrayList; import java.util.List; -import java.math.BigInteger; /** - * P36: Determine the prime factors of a given positive integer with their multiplicities. - * Returns a list containing pairs of prime factors and their multiplicity. + * P36: Determine the prime factors of a given positive integer with their multiplicities. Returns a + * list containing pairs of prime factors and their multiplicity. */ public class MathP36 { - /** - * Determines the prime factors of a given number and their multiplicities. - * Returns a list of PrimeFactor records, each containing a prime factor - * and how many times it appears in the factorization. - * Example: - * primeFactorsMult(315) returns [(3,2), (5,1), (7,1)] - * because 315 = 3² × 5 × 7 - * - * @param n the number to factorize - * @return list of prime factors with their multiplicities - * @throws IllegalArgumentException if n is not positive - */ - public static List primeFactorsMult(long n) { - if (n <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - - List factorsList = new ArrayList<>(); - - if (n == 1) { - return factorsList; // Empty list for 1 - } - - // Handle factor 2 separately - int count = 0; - while (n % 2 == 0) { - count++; - n /= 2; - } - if (count > 0) { - factorsList.add(new PrimeFactor(2, count)); - } + /** + * Determines the prime factors of a given number and their multiplicities. Returns a list of + * PrimeFactor records, each containing a prime factor and how many times it appears in the + * factorization. Example: primeFactorsMult(315) returns [(3,2), (5,1), (7,1)] because 315 = 3² × + * 5 × 7 + * + * @param n the number to factorize + * @return list of prime factors with their multiplicities + * @throws IllegalArgumentException if n is not positive + */ + public static List primeFactorsMult(long n) { + if (n <= 0) { + throw new IllegalArgumentException("Number must be positive"); + } - // Handle odd factors - for (long i = 3; i * i <= n; i += 2) { - count = 0; - while (n % i == 0) { - count++; - n /= i; - } - if (count > 0) { - factorsList.add(new PrimeFactor(i, count)); - } - } + List factorsList = new ArrayList<>(); - // If n is greater than 2 here, it is prime - if (n > 2) { - factorsList.add(new PrimeFactor(n, 1)); - } + if (n == 1) { + return factorsList; // Empty list for 1 + } - return factorsList; + // Handle factor 2 separately + int count = 0; + while (n % 2 == 0) { + count++; + n /= 2; + } + if (count > 0) { + factorsList.add(new PrimeFactor(2, count)); } - /** - * Reconstructs the original number from its prime factorization. - * Useful for verification. - * - * @param factors list of prime factors with their multiplicities - * @return the original number - */ - public static long reconstruct(List factors) { - return factors.stream() - .mapToLong(f -> powLong(f.factor, f.multiplicity)) - .reduce(1L, Math::multiplyExact); + // Handle odd factors + for (long i = 3; i * i <= n; i += 2) { + count = 0; + while (n % i == 0) { + count++; + n /= i; + } + if (count > 0) { + factorsList.add(new PrimeFactor(i, count)); + } } - private static long powLong(long base, int exponent) { - return BigInteger.valueOf(base) - .pow(exponent) - .longValueExact(); + // If n is greater than 2 here, it is prime + if (n > 2) { + factorsList.add(new PrimeFactor(n, 1)); } - /** - * Represents a prime factor and its multiplicity (how many times it appears). - */ - public record PrimeFactor(long factor, int multiplicity) { - @Override - public String toString() { - return "(" + factor + " " + multiplicity + ")"; - } + return factorsList; + } + + /** + * Reconstructs the original number from its prime factorization. Useful for verification. + * + * @param factors list of prime factors with their multiplicities + * @return the original number + */ + public static long reconstruct(List factors) { + return factors.stream() + .mapToLong(f -> powLong(f.factor, f.multiplicity)) + .reduce(1L, Math::multiplyExact); + } + + private static long powLong(long base, int exponent) { + return BigInteger.valueOf(base).pow(exponent).longValueExact(); + } + + /** Represents a prime factor and its multiplicity (how many times it appears). */ + public record PrimeFactor(long factor, int multiplicity) { + @Override + public String toString() { + return "(" + factor + " " + multiplicity + ")"; } + } } diff --git a/src/main/java/org/nintynine/problems/MathP37.java b/src/main/java/org/nintynine/problems/MathP37.java index 1e6dc0b..aae2744 100644 --- a/src/main/java/org/nintynine/problems/MathP37.java +++ b/src/main/java/org/nintynine/problems/MathP37.java @@ -3,106 +3,103 @@ import java.util.List; /** - * P37: Calculate Euler's totient function phi(m) (improved version). - * Uses prime factorization to calculate phi(m) more efficiently. - * For a number m with prime factorization ((p1 m1) (p2 m2) (p3 m3) ...), - * phi(m) = (p1 - 1) * p1^(m1 - 1) * (p2 - 1) * p2^(m2 - 1) * ... + * P37: Calculate Euler's totient function phi(m) (improved version). Uses prime factorization to + * calculate phi(m) more efficiently. For a number m with prime factorization ((p1 m1) (p2 m2) (p3 + * m3) ...), phi(m) = (p1 - 1) * p1^(m1 - 1) * (p2 - 1) * p2^(m2 - 1) * ... */ public class MathP37 { - private MathP37() { + private MathP37() {} + + /** + * Calculates Euler's totient function phi(m) using prime factorization. This is more efficient + * than the primitive method from P34. + * + * @param m the number to calculate phi for + * @return the value of phi(m) + * @throws IllegalArgumentException if m is not positive + */ + public static long totientPhi(long m) { + if (m <= 0) { + throw new IllegalArgumentException("Number must be positive"); } - /** - * Calculates Euler's totient function phi(m) using prime factorization. - * This is more efficient than the primitive method from P34. - * - * @param m the number to calculate phi for - * @return the value of phi(m) - * @throws IllegalArgumentException if m is not positive - */ - public static long totientPhi(long m) { - if (m <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - - if (m == 1) { - return 1; // Special case: phi(1) = 1 - } - - // Get prime factorization - List primeFactors = MathP36.primeFactorsMult(m); - - // Apply the formula: - // phi(m) = (p1 - 1) * p1^(m1 - 1) * (p2 - 1) * p2^(m2 - 1) * ... - long result = 1; - for (MathP36.PrimeFactor pf : primeFactors) { - long p = pf.factor(); - int multiplicity = pf.multiplicity(); - - // Calculate (p-1) * p^(m-1) - result *= (p - 1) * pow(p, multiplicity - 1); - } - - return result; + if (m == 1) { + return 1; // Special case: phi(1) = 1 } - /** - * Helper method to calculate power with positive integer exponent. - * - * @param base the base number - * @param exponent the exponent (must be non-negative) - * @return base raised to the power of exponent - */ - private static long pow(long base, int exponent) { - if (exponent < 0) { - throw new IllegalArgumentException("Exponent must be non-negative"); - } - - if (exponent == 0) { - return 1; - } - - long result = 1; - while (exponent > 0) { - if ((exponent & 1) == 1) { - result *= base; - } - base *= base; - exponent >>= 1; - } - return result; + // Get prime factorization + List primeFactors = MathP36.primeFactorsMult(m); + + // Apply the formula: + // phi(m) = (p1 - 1) * p1^(m1 - 1) * (p2 - 1) * p2^(m2 - 1) * ... + long result = 1; + for (MathP36.PrimeFactor pf : primeFactors) { + long p = pf.factor(); + int multiplicity = pf.multiplicity(); + + // Calculate (p-1) * p^(m-1) + result *= (p - 1) * pow(p, multiplicity - 1); + } + + return result; + } + + /** + * Helper method to calculate power with positive integer exponent. + * + * @param base the base number + * @param exponent the exponent (must be non-negative) + * @return base raised to the power of exponent + */ + private static long pow(long base, int exponent) { + if (exponent < 0) { + throw new IllegalArgumentException("Exponent must be non-negative"); } - /** - * Compares performance between the primitive (P34) and improved (P37) methods. - * Returns the execution times for both methods. - * - * @param m the number to test - * @return array containing [primitive_time, improved_time] in nanoseconds - */ - public static long[] comparePerformance(long m) { - long startTime; - long endTime; - long[] times = new long[2]; - - // Test primitive method (P34) - startTime = System.nanoTime(); - long result1 = MathP34.totientPhi(m); - endTime = System.nanoTime(); - times[0] = endTime - startTime; - - // Test improved method (P37) - startTime = System.nanoTime(); - long result2 = totientPhi(m); - endTime = System.nanoTime(); - times[1] = endTime - startTime; - - // Verify results match - if (result1 != result2) { - throw new IllegalStateException( - "Inconsistent results: " + result1 + " != " + result2); - } - - return times; + if (exponent == 0) { + return 1; } + + long result = 1; + while (exponent > 0) { + if ((exponent & 1) == 1) { + result *= base; + } + base *= base; + exponent >>= 1; + } + return result; + } + + /** + * Compares performance between the primitive (P34) and improved (P37) methods. Returns the + * execution times for both methods. + * + * @param m the number to test + * @return array containing [primitive_time, improved_time] in nanoseconds + */ + public static long[] comparePerformance(long m) { + long startTime; + long endTime; + long[] times = new long[2]; + + // Test primitive method (P34) + startTime = System.nanoTime(); + long result1 = MathP34.totientPhi(m); + endTime = System.nanoTime(); + times[0] = endTime - startTime; + + // Test improved method (P37) + startTime = System.nanoTime(); + long result2 = totientPhi(m); + endTime = System.nanoTime(); + times[1] = endTime - startTime; + + // Verify results match + if (result1 != result2) { + throw new IllegalStateException("Inconsistent results: " + result1 + " != " + result2); + } + + return times; + } } diff --git a/src/main/java/org/nintynine/problems/MathP38.java b/src/main/java/org/nintynine/problems/MathP38.java index 6fc3b76..bc9d5d7 100644 --- a/src/main/java/org/nintynine/problems/MathP38.java +++ b/src/main/java/org/nintynine/problems/MathP38.java @@ -4,258 +4,265 @@ import java.util.List; /** - * P38: Compare the two methods of calculating Euler's totient function. - * Compares performance and operation counts between P34 (primitive) and P37 (improved) methods. + * P38: Compare the two methods of calculating Euler's totient function. Compares performance and + * operation counts between P34 (primitive) and P37 (improved) methods. */ public class MathP38 { - /** - * Instrumented version of primitive totient calculation (P34 style) - */ - private static long totientPhiPrimitive(long m, OperationCounter counter) { - if (m <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - counter.countComparison(); // m <= 0 - - if (m == 1) { - counter.countComparison(); // m == 1 - return 1; - } - - long count = 0; - for (long i = 1; i <= m; i++) { - counter.countComparison(); // i <= m - counter.countArithmetic(); // i++ - - if (gcd(i, m, counter) == 1) { - counter.countComparison(); // gcd == 1 - count++; - counter.countArithmetic(); // count++ - } - } - return count; + /** Instrumented version of primitive totient calculation (P34 style) */ + private static long totientPhiPrimitive(long m, OperationCounter counter) { + if (m <= 0) { + throw new IllegalArgumentException("Number must be positive"); } + counter.countComparison(); // m <= 0 - /** - * Instrumented version of GCD calculation - */ - private static long gcd(long a, long b, OperationCounter counter) { - counter.countMethodCall(); - while (b != 0) { - counter.countComparison(); // b != 0 - long temp = b; - b = a % b; - a = temp; - counter.countArithmetic(); // modulo - counter.countArithmetic(); // assignment - } - counter.countComparison(); // final b != 0 - return a; + if (m == 1) { + counter.countComparison(); // m == 1 + return 1; } - /** - * Instrumented version of improved totient calculation (P37 style) - */ - private static long totientPhiImproved(long m, OperationCounter counter) { - if (m <= 0) { - throw new IllegalArgumentException("Number must be positive"); - } - counter.countComparison(); // m <= 0 - - if (m == 1) { - counter.countComparison(); // m == 1 - return 1; - } - - List primeFactors = getPrimeFactors(m, counter); - - long result = 1; - for (MathP36.PrimeFactor pf : primeFactors) { - long p = pf.factor(); - int multiplicity = pf.multiplicity(); - - // Calculate (p-1) * p^(m-1) - counter.countArithmetic(); // p-1 - counter.countArithmetic(); // m-1 - result *= (p - 1) * pow(p, multiplicity - 1, counter); - counter.countArithmetic(); // multiplication - } - - return result; + long count = 0; + for (long i = 1; i <= m; i++) { + counter.countComparison(); // i <= m + counter.countArithmetic(); // i++ + + if (gcd(i, m, counter) == 1) { + counter.countComparison(); // gcd == 1 + count++; + counter.countArithmetic(); // count++ + } + } + return count; + } + + /** Instrumented version of GCD calculation */ + private static long gcd(long a, long b, OperationCounter counter) { + counter.countMethodCall(); + while (b != 0) { + counter.countComparison(); // b != 0 + long temp = b; + b = a % b; + a = temp; + counter.countArithmetic(); // modulo + counter.countArithmetic(); // assignment + } + counter.countComparison(); // final b != 0 + return a; + } + + /** Instrumented version of improved totient calculation (P37 style) */ + private static long totientPhiImproved(long m, OperationCounter counter) { + if (m <= 0) { + throw new IllegalArgumentException("Number must be positive"); + } + counter.countComparison(); // m <= 0 + + if (m == 1) { + counter.countComparison(); // m == 1 + return 1; + } + + List primeFactors = getPrimeFactors(m, counter); + + long result = 1; + for (MathP36.PrimeFactor pf : primeFactors) { + long p = pf.factor(); + int multiplicity = pf.multiplicity(); + + // Calculate (p-1) * p^(m-1) + counter.countArithmetic(); // p-1 + counter.countArithmetic(); // m-1 + result *= (p - 1) * pow(p, multiplicity - 1, counter); + counter.countArithmetic(); // multiplication + } + + return result; + } + + /** Instrumented version of prime factorization */ + private static List getPrimeFactors(long n, OperationCounter counter) { + counter.countMethodCall(); + List factors = new ArrayList<>(); + + // Handle factor 2 + int count = 0; + while (n % 2 == 0) { + counter.countComparison(); // n % 2 == 0 + counter.countArithmetic(); // n % 2 + count++; + counter.countArithmetic(); // count++ + n /= 2; + counter.countArithmetic(); // division + } + if (count > 0) { + counter.countComparison(); // count > 0 + factors.add(new MathP36.PrimeFactor(2, count)); + } + + // Handle odd factors + for (long i = 3; i * i <= n; i += 2) { + counter.countArithmetic(); // i * i + counter.countComparison(); // <= n + counter.countArithmetic(); // i += 2 + + count = 0; + while (n % i == 0) { + counter.countArithmetic(); // n % i + counter.countComparison(); // == 0 + count++; + counter.countArithmetic(); // count++ + n /= i; + counter.countArithmetic(); // division + } + if (count > 0) { + counter.countComparison(); // count > 0 + factors.add(new MathP36.PrimeFactor(i, count)); + } + } + + if (n > 2) { + counter.countComparison(); // n > 2 + factors.add(new MathP36.PrimeFactor(n, 1)); + } + + return factors; + } + + /** Instrumented version of power calculation */ + private static long pow(long base, int exponent, OperationCounter counter) { + counter.countMethodCall(); + if (exponent == 0) { + counter.countComparison(); // exponent == 0 + return 1; + } + + long result = 1; + while (exponent > 0) { + counter.countComparison(); // exponent > 0 + if ((exponent & 1) == 1) { + counter.countComparison(); // & 1 == 1 + result *= base; + counter.countArithmetic(); // multiplication + } + base *= base; + counter.countArithmetic(); // multiplication + exponent >>= 1; + counter.countArithmetic(); // shift + } + return result; + } + + /** Compare both methods for a given number */ + public static List compare(long n) { + List results = new ArrayList<>(); + + // Test primitive method + OperationCounter primitiveCounter = new OperationCounter(); + long startTime = System.nanoTime(); + long primitiveResult = totientPhiPrimitive(n, primitiveCounter); + long primitiveTime = System.nanoTime() - startTime; + + results.add( + new PerformanceMetrics( + "Primitive (P34)", + primitiveResult, + primitiveTime, + primitiveCounter.getArithmeticOps(), + primitiveCounter.getComparisonOps(), + primitiveCounter.getMethodCalls())); + + // Test improved method using a lightweight counter to reduce overhead + OperationCounter improvedCounter = new NoOpOperationCounter(); + startTime = System.nanoTime(); + long improvedResult = totientPhiImproved(n, improvedCounter); + long improvedTime = System.nanoTime() - startTime; + + results.add( + new PerformanceMetrics( + "Improved (P37)", + improvedResult, + improvedTime, + improvedCounter.getArithmeticOps(), + improvedCounter.getComparisonOps(), + improvedCounter.getMethodCalls())); + + return results; + } + + /** Represents performance metrics for a totient calculation method */ + public record PerformanceMetrics( + String methodName, + long result, + long timeNanos, + long arithmeticOps, + long comparisonOps, + long methodCalls) { + @Override + public String toString() { + return String.format( + """ + Method: %s %n + Result: %d %n + Time: %,d ns %n + Arithmetic operations: %,d %n + Comparisons: %,d %n + Method calls: %,d %n + """ + .strip(), + methodName, + result, + timeNanos, + arithmeticOps, + comparisonOps, + methodCalls); + } + } + + /** Counter class to track operations during calculation */ + public static class OperationCounter { + private long arithmeticOps = 0; + private long comparisonOps = 0; + private long methodCalls = 0; + + public void countArithmetic() { + arithmeticOps++; + } + + public void countComparison() { + comparisonOps++; + } + + public void countMethodCall() { + methodCalls++; + } + + public long getArithmeticOps() { + return arithmeticOps; } - /** - * Instrumented version of prime factorization - */ - private static List getPrimeFactors(long n, OperationCounter counter) { - counter.countMethodCall(); - List factors = new ArrayList<>(); - - // Handle factor 2 - int count = 0; - while (n % 2 == 0) { - counter.countComparison(); // n % 2 == 0 - counter.countArithmetic(); // n % 2 - count++; - counter.countArithmetic(); // count++ - n /= 2; - counter.countArithmetic(); // division - } - if (count > 0) { - counter.countComparison(); // count > 0 - factors.add(new MathP36.PrimeFactor(2, count)); - } - - // Handle odd factors - for (long i = 3; i * i <= n; i += 2) { - counter.countArithmetic(); // i * i - counter.countComparison(); // <= n - counter.countArithmetic(); // i += 2 - - count = 0; - while (n % i == 0) { - counter.countArithmetic(); // n % i - counter.countComparison(); // == 0 - count++; - counter.countArithmetic(); // count++ - n /= i; - counter.countArithmetic(); // division - } - if (count > 0) { - counter.countComparison(); // count > 0 - factors.add(new MathP36.PrimeFactor(i, count)); - } - } - - if (n > 2) { - counter.countComparison(); // n > 2 - factors.add(new MathP36.PrimeFactor(n, 1)); - } - - return factors; + public long getComparisonOps() { + return comparisonOps; } - /** - * Instrumented version of power calculation - */ - private static long pow(long base, int exponent, OperationCounter counter) { - counter.countMethodCall(); - if (exponent == 0) { - counter.countComparison(); // exponent == 0 - return 1; - } - - long result = 1; - while (exponent > 0) { - counter.countComparison(); // exponent > 0 - if ((exponent & 1) == 1) { - counter.countComparison(); // & 1 == 1 - result *= base; - counter.countArithmetic(); // multiplication - } - base *= base; - counter.countArithmetic(); // multiplication - exponent >>= 1; - counter.countArithmetic(); // shift - } - return result; + public long getMethodCalls() { + return methodCalls; } + } - /** - * Compare both methods for a given number - */ - public static List compare(long n) { - List results = new ArrayList<>(); - - // Test primitive method - OperationCounter primitiveCounter = new OperationCounter(); - long startTime = System.nanoTime(); - long primitiveResult = totientPhiPrimitive(n, primitiveCounter); - long primitiveTime = System.nanoTime() - startTime; - - results.add(new PerformanceMetrics( - "Primitive (P34)", - primitiveResult, - primitiveTime, - primitiveCounter.getArithmeticOps(), - primitiveCounter.getComparisonOps(), - primitiveCounter.getMethodCalls() - )); - - // Test improved method - OperationCounter improvedCounter = new OperationCounter(); - startTime = System.nanoTime(); - long improvedResult = totientPhiImproved(n, improvedCounter); - long improvedTime = System.nanoTime() - startTime; - - results.add(new PerformanceMetrics( - "Improved (P37)", - improvedResult, - improvedTime, - improvedCounter.getArithmeticOps(), - improvedCounter.getComparisonOps(), - improvedCounter.getMethodCalls() - )); - - return results; + /** A counter implementation that ignores all increment operations. */ + public static class NoOpOperationCounter extends OperationCounter { + @Override + public void countArithmetic() { + // Intentionally left blank } - /** - * Represents performance metrics for a totient calculation method - */ - public record PerformanceMetrics( - String methodName, - long result, - long timeNanos, - long arithmeticOps, - long comparisonOps, - long methodCalls - ) { - @Override - public String toString() { - return String.format(""" - Method: %s %n - Result: %d %n - Time: %,d ns %n - Arithmetic operations: %,d %n - Comparisons: %,d %n - Method calls: %,d %n - """.strip(), - methodName, result, timeNanos, - arithmeticOps, comparisonOps, methodCalls); - } + @Override + public void countComparison() { + // Intentionally left blank } - /** - * Counter class to track operations during calculation - */ - public static class OperationCounter { - private long arithmeticOps = 0; - private long comparisonOps = 0; - private long methodCalls = 0; - - public void countArithmetic() { - arithmeticOps++; - } - - public void countComparison() { - comparisonOps++; - } - - public void countMethodCall() { - methodCalls++; - } - - public long getArithmeticOps() { - return arithmeticOps; - } - - public long getComparisonOps() { - return comparisonOps; - } - - public long getMethodCalls() { - return methodCalls; - } + @Override + public void countMethodCall() { + // Intentionally left blank } + } } diff --git a/src/main/java/org/nintynine/problems/MathP40.java b/src/main/java/org/nintynine/problems/MathP40.java index b21b310..c76218a 100644 --- a/src/main/java/org/nintynine/problems/MathP40.java +++ b/src/main/java/org/nintynine/problems/MathP40.java @@ -4,149 +4,142 @@ import java.util.Optional; /** - * P40: Goldbach's conjecture implementation. - * Finds two prime numbers that sum up to a given even number. + * P40: Goldbach's conjecture implementation. Finds two prime numbers that sum up to a given even + * number. */ public class MathP40 { - /** - * Finds a pair of prime numbers that sum up to the given even number. - * Returns the first such pair found (typically with the smallest first prime). - * - * @param n the even number to decompose (must be > 2) - * @return Optional containing the Goldbach pair if found - * @throws IllegalArgumentException if n ≤ 2 or n is odd - */ - public static Optional goldbach(long n) { - if (n <= 2) { - throw new IllegalArgumentException("Number must be greater than 2"); - } - if (n % 2 != 0) { - throw new IllegalArgumentException("Number must be even"); - } - - BitSet sieve = sieveOfEratosthenes(n); - - for (long p = 2; p <= n / 2; p++) { - if (sieve.get((int) p)) { - long q = n - p; - if (q < n && sieve.get((int) q)) { - return Optional.of(new GoldbachPair(p, q)); - } - } - } - - return Optional.empty(); + /** + * Finds a pair of prime numbers that sum up to the given even number. Returns the first such pair + * found (typically with the smallest first prime). + * + * @param n the even number to decompose (must be > 2) + * @return Optional containing the Goldbach pair if found + * @throws IllegalArgumentException if n ≤ 2 or n is odd + */ + public static Optional goldbach(long n) { + if (n <= 2) { + throw new IllegalArgumentException("Number must be greater than 2"); + } + if (n % 2 != 0) { + throw new IllegalArgumentException("Number must be even"); } - /** - * Finds all pairs of prime numbers that sum up to the given even number. - * - * @param n the even number to decompose (must be > 2) - * @return array of GoldbachPairs, ordered by first prime - * @throws IllegalArgumentException if n ≤ 2 or n is odd - */ - public static GoldbachPair[] goldbachAll(long n) { - if (n <= 2) { - throw new IllegalArgumentException("Number must be greater than 2"); - } - if (n % 2 != 0) { - throw new IllegalArgumentException("Number must be even"); - } + BitSet sieve = sieveOfEratosthenes(n); - BitSet sieve = sieveOfEratosthenes(n); - int pairCount = 0; - for (long p = 2; p <= n / 2; p++) { - if (sieve.get((int) p) && sieve.get((int) (n - p))) { - pairCount++; - } + for (long p = 2; p <= n / 2; p++) { + if (sieve.get((int) p)) { + long q = n - p; + if (q < n && sieve.get((int) q)) { + return Optional.of(new GoldbachPair(p, q)); } + } + } - GoldbachPair[] pairs = new GoldbachPair[pairCount]; - int index = 0; - for (long p = 2; p <= n / 2; p++) { - if (sieve.get((int) p)) { - long q = n - p; - if (q < n && sieve.get((int) q)) { - pairs[index++] = new GoldbachPair(p, q); - } - } - } + return Optional.empty(); + } + + /** + * Finds all pairs of prime numbers that sum up to the given even number. + * + * @param n the even number to decompose (must be > 2) + * @return array of GoldbachPairs, ordered by first prime + * @throws IllegalArgumentException if n ≤ 2 or n is odd + */ + public static GoldbachPair[] goldbachAll(long n) { + if (n <= 2) { + throw new IllegalArgumentException("Number must be greater than 2"); + } + if (n % 2 != 0) { + throw new IllegalArgumentException("Number must be even"); + } - return pairs; + BitSet sieve = sieveOfEratosthenes(n); + int pairCount = 0; + for (long p = 2; p <= n / 2; p++) { + if (sieve.get((int) p) && sieve.get((int) (n - p))) { + pairCount++; + } } - /** - * Verifies Goldbach's conjecture for all even numbers up to n. - * - * @param n upper limit to check (must be > 2) - * @return true if conjecture holds for all even numbers in range - * @throws IllegalArgumentException if n ≤ 2 - */ - public static boolean verifyGoldbachUpTo(long n) { - if (n <= 2) { - throw new IllegalArgumentException("Number must be greater than 2"); + GoldbachPair[] pairs = new GoldbachPair[pairCount]; + int index = 0; + for (long p = 2; p <= n / 2; p++) { + if (sieve.get((int) p)) { + long q = n - p; + if (q < n && sieve.get((int) q)) { + pairs[index++] = new GoldbachPair(p, q); } + } + } - BitSet sieve = sieveOfEratosthenes(n); + return pairs; + } + + /** + * Verifies Goldbach's conjecture for all even numbers up to n. + * + * @param n upper limit to check (must be > 2) + * @return true if conjecture holds for all even numbers in range + * @throws IllegalArgumentException if n ≤ 2 + */ + public static boolean verifyGoldbachUpTo(long n) { + if (n <= 2) { + throw new IllegalArgumentException("Number must be greater than 2"); + } - for (long i = 4; i <= n; i += 2) { - boolean found = false; + BitSet sieve = sieveOfEratosthenes(n); - for (long p = 2; p <= i / 2; p++) { - if (sieve.get((int) p)) { - long q = i - p; - if (q < i && sieve.get((int) q)) { - found = true; - break; - } - } - } + for (long i = 4; i <= n; i += 2) { + boolean found = false; - if (!found) { - return false; - } + for (long p = 2; p <= i / 2; p++) { + if (sieve.get((int) p)) { + long q = i - p; + if (q < i && sieve.get((int) q)) { + found = true; + break; + } } + } - return true; + if (!found) { + return false; + } } - /** - * Generates prime number sieve up to n. - * Uses BitSet for efficient storage and lookup. - */ - private static BitSet sieveOfEratosthenes(long n) { - BitSet sieve = new BitSet((int) n + 1); - sieve.set(2, (int) n + 1); - - for (int i = 2; (long) i * i <= n; i++) { - if (sieve.get(i)) { - for (int j = i * i; j <= n; j += i) { - sieve.clear(j); - } - } - } + return true; + } + + /** Generates prime number sieve up to n. Uses BitSet for efficient storage and lookup. */ + private static BitSet sieveOfEratosthenes(long n) { + BitSet sieve = new BitSet((int) n + 1); + sieve.set(2, (int) n + 1); - return sieve; + for (int i = 2; (long) i * i <= n; i++) { + if (sieve.get(i)) { + for (int j = i * i; j <= n; j += i) { + sieve.clear(j); + } + } } + return sieve; + } + + /** Represents a pair of prime numbers that sum to a given even number. */ + public record GoldbachPair(long prime1, long prime2) { /** - * Represents a pair of prime numbers that sum to a given even number. + * Verifies that this is a valid Goldbach pair. + * + * @return true if both numbers are prime and sum to an even number */ - public record GoldbachPair(long prime1, long prime2) { - /** - * Verifies that this is a valid Goldbach pair. - * - * @return true if both numbers are prime and sum to an even number - */ - public boolean isValid() { - return MathP31.isPrime(prime1) && - MathP31.isPrime(prime2) && - (prime1 + prime2) % 2 == 0; - } + public boolean isValid() { + return MathP31.isPrime(prime1) && MathP31.isPrime(prime2) && (prime1 + prime2) % 2 == 0; + } - @Override - public String toString() { - return String.format("(%d %d)", prime1, prime2); - } + @Override + public String toString() { + return String.format("(%d %d)", prime1, prime2); } + } } diff --git a/src/main/java/org/nintynine/problems/MathP41.java b/src/main/java/org/nintynine/problems/MathP41.java index 2636999..f188d24 100644 --- a/src/main/java/org/nintynine/problems/MathP41.java +++ b/src/main/java/org/nintynine/problems/MathP41.java @@ -7,138 +7,121 @@ import java.util.stream.Collectors; /** - * P41: List of Goldbach compositions. - * Lists all even numbers and their Goldbach compositions in a given range. + * P41: List of Goldbach compositions. Lists all even numbers and their Goldbach compositions in a + * given range. */ public class MathP41 { - /** - * Lists all Goldbach compositions in the given range. - * - * @param start lower bound of the range (inclusive) - * @param end upper bound of the range (inclusive) - * @return list of Goldbach compositions - * @throws IllegalArgumentException if start > end or start < 0 - */ - public static List goldbachList(long start, long end) { - return goldbachList(start, end, 0); + /** + * Lists all Goldbach compositions in the given range. + * + * @param start lower bound of the range (inclusive) + * @param end upper bound of the range (inclusive) + * @return list of Goldbach compositions + * @throws IllegalArgumentException if start > end or start < 0 + */ + public static List goldbachList(long start, long end) { + return goldbachList(start, end, 0); + } + + /** + * Lists Goldbach compositions in the given range where both primes are greater than or equal to + * the specified minimum value. + * + * @param start lower bound of the range (inclusive) + * @param end upper bound of the range (inclusive) + * @param minPrime minimum value for both primes (0 for no minimum) + * @return filtered list of Goldbach compositions + * @throws IllegalArgumentException if start > end or start < 0 or minPrime < 0 + */ + public static List goldbachList(long start, long end, long minPrime) { + validateRange(start, end); + if (minPrime < 0) { + throw new IllegalArgumentException("Minimum prime must be non-negative"); } - /** - * Lists Goldbach compositions in the given range where both primes are - * greater than or equal to the specified minimum value. - * - * @param start lower bound of the range (inclusive) - * @param end upper bound of the range (inclusive) - * @param minPrime minimum value for both primes (0 for no minimum) - * @return filtered list of Goldbach compositions - * @throws IllegalArgumentException if start > end or start < 0 or minPrime < 0 - */ - public static List goldbachList(long start, long end, - long minPrime) { - validateRange(start, end); - if (minPrime < 0) { - throw new IllegalArgumentException("Minimum prime must be non-negative"); - } - - List compositions = new ArrayList<>(); + List compositions = new ArrayList<>(); - // Adjust start to first even number in range - long firstEven = (start % 2 == 0) ? start : start + 1; + // Adjust start to first even number in range + long firstEven = (start % 2 == 0) ? start : start + 1; - // Use sieve for the entire range for efficiency - BitSet sieve = sieveOfEratosthenes(end); - - // Find compositions for each even number - for (long n = firstEven; n <= end; n += 2) { - if (n > 2) { // Skip 2 as it's not a sum of two primes - Optional composition = - findGoldbachComposition(n, minPrime, sieve); - long finalN = n; - composition.ifPresent(pair -> - compositions.add(new GoldbachListEntry(finalN, pair))); - } - } + // Use sieve for the entire range for efficiency + BitSet sieve = sieveOfEratosthenes(end); - return compositions; + // Find compositions for each even number + for (long n = firstEven; n <= end; n += 2) { + if (n > 2) { // Skip 2 as it's not a sum of two primes + Optional composition = findGoldbachComposition(n, minPrime, sieve); + long finalN = n; + composition.ifPresent(pair -> compositions.add(new GoldbachListEntry(finalN, pair))); + } } - /** - * Counts Goldbach compositions where both primes are above the minimum value. - * - * @param start lower bound of the range (inclusive) - * @param end upper bound of the range (inclusive) - * @param minPrime minimum value for both primes - * @return count of qualifying Goldbach compositions - */ - public static long countGoldbachCompositions(long start, long end, - long minPrime) { - return goldbachList(start, end, minPrime).size(); - } - - /** - * Finds Goldbach composition for a number with prime minimum value constraint. - */ - private static Optional findGoldbachComposition( - long n, long minPrime, BitSet sieve) { - // Start from minPrime if specified, otherwise from 2 - for (long p = Math.max(2, minPrime); p <= n / 2; p++) { - if (sieve.get((int) p)) { - long q = n - p; - if (q >= minPrime && q < n && sieve.get((int) q)) { - return Optional.of(new MathP40.GoldbachPair(p, q)); - } - } + return compositions; + } + + /** + * Counts Goldbach compositions where both primes are above the minimum value. + * + * @param start lower bound of the range (inclusive) + * @param end upper bound of the range (inclusive) + * @param minPrime minimum value for both primes + * @return count of qualifying Goldbach compositions + */ + public static long countGoldbachCompositions(long start, long end, long minPrime) { + return goldbachList(start, end, minPrime).size(); + } + + /** Finds Goldbach composition for a number with prime minimum value constraint. */ + private static Optional findGoldbachComposition( + long n, long minPrime, BitSet sieve) { + // Start from minPrime if specified, otherwise from 2 + for (long p = Math.max(2, minPrime); p <= n / 2; p++) { + if (sieve.get((int) p)) { + long q = n - p; + if (q >= minPrime && q < n && sieve.get((int) q)) { + return Optional.of(new MathP40.GoldbachPair(p, q)); } - return Optional.empty(); + } } - - /** - * Generates an optimized Sieve of Eratosthenes up to n. - */ - private static BitSet sieveOfEratosthenes(long n) { - BitSet sieve = new BitSet((int) n + 1); - sieve.set(2, (int) n + 1); // Set all bits initially - - for (int i = 2; (long) i * i <= n; i++) { - if (sieve.get(i)) { - for (int j = i * i; j <= n; j += i) { - sieve.clear(j); - } - } + return Optional.empty(); + } + + /** Generates an optimized Sieve of Eratosthenes up to n. */ + private static BitSet sieveOfEratosthenes(long n) { + BitSet sieve = new BitSet((int) n + 1); + sieve.set(2, (int) n + 1); // Set all bits initially + + for (int i = 2; (long) i * i <= n; i++) { + if (sieve.get(i)) { + for (int j = i * i; j <= n; j += i) { + sieve.clear(j); } - - return sieve; + } } - /** - * Validates the range parameters. - */ - private static void validateRange(long start, long end) { - if (start > end) { - throw new IllegalArgumentException("Start must not be greater than end"); - } - if (start < 0) { - throw new IllegalArgumentException("Range must be non-negative"); - } - } + return sieve; + } - /** - * Returns the compositions as a formatted string. - */ - public static String formatGoldbachList(List compositions) { - return compositions.stream() - .map(GoldbachListEntry::toString) - .collect(Collectors.joining("\n")); + /** Validates the range parameters. */ + private static void validateRange(long start, long end) { + if (start > end) { + throw new IllegalArgumentException("Start must not be greater than end"); } - - /** - * Represents a Goldbach composition list entry - */ - public record GoldbachListEntry(long number, MathP40.GoldbachPair pair) { - @Override - public String toString() { - return String.format("%d = %d + %d", - number, pair.prime1(), pair.prime2()); - } + if (start < 0) { + throw new IllegalArgumentException("Range must be non-negative"); + } + } + + /** Returns the compositions as a formatted string. */ + public static String formatGoldbachList(List compositions) { + return compositions.stream().map(GoldbachListEntry::toString).collect(Collectors.joining("\n")); + } + + /** Represents a Goldbach composition list entry */ + public record GoldbachListEntry(long number, MathP40.GoldbachPair pair) { + @Override + public String toString() { + return String.format("%d = %d + %d", number, pair.prime1(), pair.prime2()); } + } } diff --git a/src/main/java/org/nintynine/problems/MathP43.java b/src/main/java/org/nintynine/problems/MathP43.java index aa01813..895ba3c 100644 --- a/src/main/java/org/nintynine/problems/MathP43.java +++ b/src/main/java/org/nintynine/problems/MathP43.java @@ -6,75 +6,68 @@ import java.util.concurrent.ConcurrentHashMap; /** - * P43: Generate N-bit Gray codes - * A Gray code is a sequence where consecutive values differ in only one bit position. + * P43: Generate N-bit Gray codes A Gray code is a sequence where consecutive values differ in only + * one bit position. */ public class MathP43 { - // Cache to store previously calculated Gray codes - private static final ConcurrentHashMap> grayCodeCache = - new ConcurrentHashMap<>(); + // Cache to store previously calculated Gray codes + private static final ConcurrentHashMap> grayCodeCache = + new ConcurrentHashMap<>(); - private MathP43() {} // Prevent instantiation + private MathP43() {} // Prevent instantiation - /** - * Generates N-bit Gray code sequence. - * Uses caching to improve performance for repeated calls. - * - * @param n number of bits (must be positive) - * @return List of strings representing the Gray code sequence - * @throws IllegalArgumentException if n is less than 1 - */ - public static List gray(int n) { - if (n < 1) { - throw new IllegalArgumentException("Number of bits must be positive"); - } - - // Check cache first - return grayCodeCache.computeIfAbsent(n, MathP43::generateGrayCode); + /** + * Generates N-bit Gray code sequence. Uses caching to improve performance for repeated calls. + * + * @param n number of bits (must be positive) + * @return List of strings representing the Gray code sequence + * @throws IllegalArgumentException if n is less than 1 + */ + public static List gray(int n) { + if (n < 1) { + throw new IllegalArgumentException("Number of bits must be positive"); } - /** - * Internal method to generate Gray code without caching. - * Uses recursive approach with concatenation. - */ - @SuppressWarnings("PMD.UnusedPrivateMethod") - private static List generateGrayCode(int n) { - if (n == 1) { - return List.of("0", "1"); - } - - // Get the n-1 bit Gray code - List prevGray = gray(n - 1); + // Check cache first + return grayCodeCache.computeIfAbsent(n, MathP43::generateGrayCode); + } - // Create a result list with known capacity - List result = new ArrayList<>(1 << n); + /** + * Internal method to generate Gray code without caching. Uses recursive approach with + * concatenation. + */ + @SuppressWarnings("PMD.UnusedPrivateMethod") + private static List generateGrayCode(int n) { + if (n == 1) { + return List.of("0", "1"); + } - // Add a forward sequence with the leading 0 - for (String code : prevGray) { - result.add("0" + code); - } + // Get the n-1 bit Gray code + List prevGray = gray(n - 1); - // Add a reverse sequence with leading 1 - for (int i = prevGray.size() - 1; i >= 0; i--) { - result.add("1" + prevGray.get(i)); - } + // Create a result list with known capacity + List result = new ArrayList<>(1 << n); - return Collections.unmodifiableList(result); + // Add a forward sequence with the leading 0 + for (String code : prevGray) { + result.add("0" + code); } - /** - * Clears the internal cache. - * Useful for testing or when memory needs to be freed. - */ - static void clearCache() { - grayCodeCache.clear(); + // Add a reverse sequence with leading 1 + for (int i = prevGray.size() - 1; i >= 0; i--) { + result.add("1" + prevGray.get(i)); } - /** - * Returns the current size of the cache. - * Useful for testing and monitoring. - */ - static int getCacheSize() { - return grayCodeCache.size(); - } + return Collections.unmodifiableList(result); + } + + /** Clears the internal cache. Useful for testing or when memory needs to be freed. */ + static void clearCache() { + grayCodeCache.clear(); + } + + /** Returns the current size of the cache. Useful for testing and monitoring. */ + static int getCacheSize() { + return grayCodeCache.size(); + } } diff --git a/src/main/java/org/nintynine/problems/MathP50.java b/src/main/java/org/nintynine/problems/MathP50.java index 2ba9464..eb8186e 100644 --- a/src/main/java/org/nintynine/problems/MathP50.java +++ b/src/main/java/org/nintynine/problems/MathP50.java @@ -8,232 +8,232 @@ import java.util.PriorityQueue; /** - * P50: Huffman coding implementation - * Creates Huffman codes for symbols based on their frequencies. + * P50: Huffman coding implementation Creates Huffman codes for symbols based on their frequencies. */ public class MathP50 { - private MathP50() {} // Prevent instantiation - - /** - * Represents a node in the Huffman tree - */ - private static class HuffmanNode implements Comparable { - final String symbol; - final int frequency; - final HuffmanNode left; - final HuffmanNode right; - - // Leaf node constructor - HuffmanNode(String symbol, int frequency) { - this.symbol = symbol; - this.frequency = frequency; - this.left = null; - this.right = null; - } - - // Internal node constructor - HuffmanNode(HuffmanNode left, HuffmanNode right) { - this.symbol = null; - this.frequency = left.frequency + right.frequency; - this.left = left; - this.right = right; - } + private MathP50() {} // Prevent instantiation + + /** Represents a node in the Huffman tree */ + private static class HuffmanNode implements Comparable { + final String symbol; + final int frequency; + final HuffmanNode left; + final HuffmanNode right; + + // Leaf node constructor + HuffmanNode(String symbol, int frequency) { + this.symbol = symbol; + this.frequency = frequency; + this.left = null; + this.right = null; + } - boolean isLeaf() { - return left == null && right == null; - } + // Internal node constructor + HuffmanNode(HuffmanNode left, HuffmanNode right) { + this.symbol = null; + this.frequency = left.frequency + right.frequency; + this.left = left; + this.right = right; + } - @Override - public int compareTo(HuffmanNode other) { - int freqCompare = Integer.compare(this.frequency, other.frequency); - if (freqCompare != 0) return freqCompare; - // Break ties consistently for testing - if (this.symbol == null || other.symbol == null) return 0; - return this.symbol.compareTo(other.symbol); - } + boolean isLeaf() { + return left == null && right == null; + } - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - HuffmanNode that = (HuffmanNode) o; - return frequency == that.frequency && Objects.equals(symbol, that.symbol) && Objects.equals(left, that.left) && Objects.equals(right, that.right); - } + @Override + public int compareTo(HuffmanNode other) { + int freqCompare = Integer.compare(this.frequency, other.frequency); + if (freqCompare != 0) return freqCompare; + // Break ties consistently for testing + if (this.symbol == null || other.symbol == null) return 0; + return this.symbol.compareTo(other.symbol); + } - @Override - public int hashCode() { - return Objects.hash(symbol, frequency, left, right); - } + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + HuffmanNode that = (HuffmanNode) o; + return frequency == that.frequency + && Objects.equals(symbol, that.symbol) + && Objects.equals(left, that.left) + && Objects.equals(right, that.right); } - /** - * Represents a frequency table entry - * @param symbol The symbol - * @param frequency Its frequency of occurrence - */ - public record FrequencyEntry(String symbol, int frequency) { - public FrequencyEntry { - Objects.requireNonNull(symbol, "Symbol cannot be null"); - if (frequency < 0) { - throw new IllegalArgumentException("Frequency cannot be negative"); - } - } + @Override + public int hashCode() { + return Objects.hash(symbol, frequency, left, right); + } + } + + /** + * Represents a frequency table entry + * + * @param symbol The symbol + * @param frequency Its frequency of occurrence + */ + public record FrequencyEntry(String symbol, int frequency) { + public FrequencyEntry { + Objects.requireNonNull(symbol, "Symbol cannot be null"); + if (frequency < 0) { + throw new IllegalArgumentException("Frequency cannot be negative"); + } + } + } + + /** + * Represents a Huffman code table entry + * + * @param symbol The symbol + * @param code It's Huffman code + */ + public record HuffmanCode(String symbol, String code) { + public HuffmanCode { + Objects.requireNonNull(symbol, "Symbol cannot be null"); + Objects.requireNonNull(code, "Code cannot be null"); + if (!code.matches("[01]*")) { + throw new IllegalArgumentException("Code must contain only 0s and 1s"); + } + } + } + + /** + * Generates Huffman codes for the given frequency table. + * + * @param frequencies List of symbol-frequency pairs + * @return List of symbol-code pairs, sorted by symbol + * @throws IllegalArgumentException if a frequency list is empty or contains invalid entries + */ + public static List huffman(List frequencies) { + if (frequencies == null || frequencies.isEmpty()) { + throw new IllegalArgumentException("Frequency table cannot be empty"); } - /** - * Represents a Huffman code table entry - * @param symbol The symbol - * @param code It's Huffman code - */ - public record HuffmanCode(String symbol, String code) { - public HuffmanCode { - Objects.requireNonNull(symbol, "Symbol cannot be null"); - Objects.requireNonNull(code, "Code cannot be null"); - if (!code.matches("[01]*")) { - throw new IllegalArgumentException("Code must contain only 0s and 1s"); - } - } + // Handle a special case of a single symbol + if (frequencies.size() == 1) { + return List.of(new HuffmanCode(frequencies.getFirst().symbol(), "0")); } - /** - * Generates Huffman codes for the given frequency table. - * - * @param frequencies List of symbol-frequency pairs - * @return List of symbol-code pairs, sorted by symbol - * @throws IllegalArgumentException if a frequency list is empty or contains invalid entries - */ - public static List huffman(List frequencies) { - if (frequencies == null || frequencies.isEmpty()) { - throw new IllegalArgumentException("Frequency table cannot be empty"); - } + // Build a Huffman tree + HuffmanNode root = buildHuffmanTree(frequencies); - // Handle a special case of a single symbol - if (frequencies.size() == 1) { - return List.of(new HuffmanCode(frequencies.getFirst().symbol(), "0")); - } + // Generate codes by traversing the tree + Map codes = new HashMap<>(); + generateCodes(root, "", codes); - // Build a Huffman tree - HuffmanNode root = buildHuffmanTree(frequencies); + // Create and sort a result + return frequencies.stream() + .map(f -> new HuffmanCode(f.symbol(), codes.get(f.symbol()))) + .sorted(Comparator.comparing(HuffmanCode::symbol)) + .toList(); + } - // Generate codes by traversing the tree - Map codes = new HashMap<>(); - generateCodes(root, "", codes); + /** Builds a Huffman tree from the frequency table. */ + private static HuffmanNode buildHuffmanTree(List frequencies) { + PriorityQueue queue = new PriorityQueue<>(); - // Create and sort a result - return frequencies.stream() - .map(f -> new HuffmanCode(f.symbol(), codes.get(f.symbol()))) - .sorted(Comparator.comparing(HuffmanCode::symbol)) - .toList(); + // Create leaf nodes + for (FrequencyEntry entry : frequencies) { + queue.offer(new HuffmanNode(entry.symbol(), entry.frequency())); } - /** - * Builds a Huffman tree from the frequency table. - */ - private static HuffmanNode buildHuffmanTree(List frequencies) { - PriorityQueue queue = new PriorityQueue<>(); + // Build a tree by combining nodes + while (queue.size() > 1) { + HuffmanNode left = queue.poll(); + HuffmanNode right = queue.poll(); + assert right != null; + queue.offer(new HuffmanNode(left, right)); + } - // Create leaf nodes - for (FrequencyEntry entry : frequencies) { - queue.offer(new HuffmanNode(entry.symbol(), entry.frequency())); - } + return queue.poll(); + } - // Build a tree by combining nodes - while (queue.size() > 1) { - HuffmanNode left = queue.poll(); - HuffmanNode right = queue.poll(); - assert right != null; - queue.offer(new HuffmanNode(left, right)); - } + /** + * Generates Huffman codes by traversing the tree. Uses '0' for left branches and '1' for right + * branches. + */ + private static void generateCodes(HuffmanNode node, String code, Map codes) { + if (node == null) return; - return queue.poll(); + if (node.isLeaf()) { + codes.put(node.symbol, code); + return; } - /** - * Generates Huffman codes by traversing the tree. - * Uses '0' for left branches and '1' for right branches. - */ - private static void generateCodes(HuffmanNode node, String code, Map codes) { - if (node == null) return; - - if (node.isLeaf()) { - codes.put(node.symbol, code); - return; - } + generateCodes(node.left, code + "0", codes); + generateCodes(node.right, code + "1", codes); + } + + /** + * Creates a decoder for the given Huffman codes. + * + * @param codes The Huffman code table + * @return A decoder function that takes a binary string and returns the decoded message + */ + public static HuffmanDecoder createDecoder(List codes) { + return new HuffmanDecoder(codes); + } + + /** Decoder class for Huffman codes */ + public static class HuffmanDecoder { + private final Node root = new Node(); + + private static class Node { + String symbol; + final Node[] children = new Node[2]; + } - generateCodes(node.left, code + "0", codes); - generateCodes(node.right, code + "1", codes); + private HuffmanDecoder(List codes) { + for (HuffmanCode code : codes) { + insert(code.symbol(), code.code()); + } } - /** - * Creates a decoder for the given Huffman codes. - * @param codes The Huffman code table - * @return A decoder function that takes a binary string and returns the decoded message - */ - public static HuffmanDecoder createDecoder(List codes) { - return new HuffmanDecoder(codes); + private void insert(String symbol, String code) { + Node current = root; + for (char bit : code.toCharArray()) { + int idx = bit - '0'; + if (current.children[idx] == null) { + current.children[idx] = new Node(); + } + current = current.children[idx]; + } + current.symbol = symbol; } /** - * Decoder class for Huffman codes + * Decodes a binary string using the Huffman codes. + * + * @param encoded The binary string to decode + * @return The decoded message + * @throws IllegalArgumentException if the input is invalid */ - public static class HuffmanDecoder { - private final Node root = new Node(); + public String decode(String encoded) { + if (encoded == null || !encoded.matches("[01]*")) { + throw new IllegalArgumentException("Invalid encoded string"); + } - private static class Node { - String symbol; - final Node[] children = new Node[2]; - } + StringBuilder result = new StringBuilder(); + Node current = root; - private HuffmanDecoder(List codes) { - for (HuffmanCode code : codes) { - insert(code.symbol(), code.code()); - } - } + for (char bit : encoded.toCharArray()) { + int idx = bit - '0'; + current = current.children[idx]; - private void insert(String symbol, String code) { - Node current = root; - for (char bit : code.toCharArray()) { - int idx = bit - '0'; - if (current.children[idx] == null) { - current.children[idx] = new Node(); - } - current = current.children[idx]; - } - current.symbol = symbol; + if (current == null) { + throw new IllegalArgumentException("Invalid encoded string"); } - /** - * Decodes a binary string using the Huffman codes. - * @param encoded The binary string to decode - * @return The decoded message - * @throws IllegalArgumentException if the input is invalid - */ - public String decode(String encoded) { - if (encoded == null || !encoded.matches("[01]*")) { - throw new IllegalArgumentException("Invalid encoded string"); - } - - StringBuilder result = new StringBuilder(); - Node current = root; - - for (char bit : encoded.toCharArray()) { - int idx = bit - '0'; - current = current.children[idx]; - - if (current == null) { - throw new IllegalArgumentException("Invalid encoded string"); - } - - if (current.symbol != null) { - result.append(current.symbol); - current = root; - } - } - - if (current != root) { - throw new IllegalArgumentException("Invalid encoded string"); - } - - return result.toString(); + if (current.symbol != null) { + result.append(current.symbol); + current = root; } + } + + if (current != root) { + throw new IllegalArgumentException("Invalid encoded string"); + } + + return result.toString(); } + } } diff --git a/src/main/java/org/nintynine/problems/MyList.java b/src/main/java/org/nintynine/problems/MyList.java index a6576b1..ffd373f 100644 --- a/src/main/java/org/nintynine/problems/MyList.java +++ b/src/main/java/org/nintynine/problems/MyList.java @@ -6,36 +6,36 @@ import java.util.stream.Stream; interface Streamable extends Iterable { - Stream stream(); + Stream stream(); } public class MyList implements Streamable { - protected T[] items; - - @SafeVarargs - public MyList(T... elements) { - this.items = Arrays.copyOf(elements, elements.length); - } - - //P01 : Find the last box of a list - public T last() { - return Arrays.stream(items) - .reduce((_, b) -> b) - .orElseThrow(() -> new IllegalStateException("Empty list has no last element")); - } - - @Override - public String toString() { - return "(" + String.join(" ", Arrays.stream(items).map(Objects::toString).toList()) + ")"; - } - - @Override - public Stream stream() { - return Arrays.stream(items); - } - - @Override - public Iterator iterator() { - return Arrays.stream(items).iterator(); - } + protected T[] items; + + @SafeVarargs + public MyList(T... elements) { + this.items = Arrays.copyOf(elements, elements.length); + } + + // P01 : Find the last box of a list + public T last() { + return Arrays.stream(items) + .reduce((_, b) -> b) + .orElseThrow(() -> new IllegalStateException("Empty list has no last element")); + } + + @Override + public String toString() { + return "(" + String.join(" ", Arrays.stream(items).map(Objects::toString).toList()) + ")"; + } + + @Override + public Stream stream() { + return Arrays.stream(items); + } + + @Override + public Iterator iterator() { + return Arrays.stream(items).iterator(); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP02.java b/src/main/java/org/nintynine/problems/MyListP02.java index 9d4524d..444ba32 100644 --- a/src/main/java/org/nintynine/problems/MyListP02.java +++ b/src/main/java/org/nintynine/problems/MyListP02.java @@ -4,31 +4,31 @@ import java.util.NoSuchElementException; public class MyListP02 extends MyList { - @SafeVarargs - public MyListP02(T... elements) { - super(elements); - } + @SafeVarargs + public MyListP02(T... elements) { + super(elements); + } - public T lastButOne() { - return Arrays.stream(items) - .reduce(Pair.empty(), Pair::shift, (_, b) -> b) - .secondLastOrThrow(); - } + public T lastButOne() { + return Arrays.stream(items) + .reduce(Pair.empty(), Pair::shift, (_, b) -> b) + .secondLastOrThrow(); + } - private record Pair(T first, T second) { - static Pair empty() { - return new Pair<>(null, null); - } + private record Pair(T first, T second) { + static Pair empty() { + return new Pair<>(null, null); + } - static Pair shift(Pair prev, T next) { - return new Pair<>(prev.second, next); - } + static Pair shift(Pair prev, T next) { + return new Pair<>(prev.second, next); + } - T secondLastOrThrow() { - if (first == null) { - throw new NoSuchElementException("List has fewer than two elements"); - } - return first; - } + T secondLastOrThrow() { + if (first == null) { + throw new NoSuchElementException("List has fewer than two elements"); + } + return first; } + } } diff --git a/src/main/java/org/nintynine/problems/MyListP03.java b/src/main/java/org/nintynine/problems/MyListP03.java index aaaad68..38f4de0 100644 --- a/src/main/java/org/nintynine/problems/MyListP03.java +++ b/src/main/java/org/nintynine/problems/MyListP03.java @@ -3,18 +3,18 @@ import java.util.Arrays; public class MyListP03 extends MyListP02 { - @SafeVarargs - public MyListP03(T... elements) { - super(elements); - } + @SafeVarargs + public MyListP03(T... elements) { + super(elements); + } - public T elementAt(long k) { - if (k < 1) { - throw new IllegalArgumentException("Position must be greater than 0"); - } - return Arrays.stream(items) - .skip(k - 1) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Position " + k + " is out of bounds")); + public T elementAt(long k) { + if (k < 1) { + throw new IllegalArgumentException("Position must be greater than 0"); } + return Arrays.stream(items) + .skip(k - 1) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Position " + k + " is out of bounds")); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP04.java b/src/main/java/org/nintynine/problems/MyListP04.java index daab2f2..0c14af6 100644 --- a/src/main/java/org/nintynine/problems/MyListP04.java +++ b/src/main/java/org/nintynine/problems/MyListP04.java @@ -1,16 +1,14 @@ package org.nintynine.problems; - import java.util.Arrays; public class MyListP04 extends MyListP03 { - @SafeVarargs - public MyListP04(T... elements) { - super(elements); - } - - public long length() { - return Arrays.stream(items) - .count(); - } + @SafeVarargs + public MyListP04(T... elements) { + super(elements); + } + + public long length() { + return Arrays.stream(items).count(); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP05.java b/src/main/java/org/nintynine/problems/MyListP05.java index 292065b..6937532 100644 --- a/src/main/java/org/nintynine/problems/MyListP05.java +++ b/src/main/java/org/nintynine/problems/MyListP05.java @@ -4,23 +4,24 @@ import java.util.LinkedList; public class MyListP05 extends MyListP04 { - @SafeVarargs - public MyListP05(T... elements) { - super(elements); - } + @SafeVarargs + public MyListP05(T... elements) { + super(elements); + } - public MyListP05 reverse() { - return new MyListP05<>(Arrays.stream(items) - .reduce( - new LinkedList(), - (list, item) -> { - list.addFirst(item); - return list; - }, - (list1, list2) -> { - list2.addAll(list1); - return list2; - } - ).toArray(Arrays.copyOf(items, 0))); - } + public MyListP05 reverse() { + return new MyListP05<>( + Arrays.stream(items) + .reduce( + new LinkedList(), + (list, item) -> { + list.addFirst(item); + return list; + }, + (list1, list2) -> { + list2.addAll(list1); + return list2; + }) + .toArray(Arrays.copyOf(items, 0))); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP06.java b/src/main/java/org/nintynine/problems/MyListP06.java index 48d21d0..0fba06d 100644 --- a/src/main/java/org/nintynine/problems/MyListP06.java +++ b/src/main/java/org/nintynine/problems/MyListP06.java @@ -4,15 +4,14 @@ import java.util.stream.LongStream; public class MyListP06 extends MyListP05 { - @SafeVarargs - public MyListP06(T... elements) { - super(elements); - } - - public boolean isPalindrome() { - final long len = length(); - return LongStream.range(0, len / 2) - .allMatch(i -> Objects.equals(elementAt(i + 1), elementAt(len + 1 - 1 - i))); - } + @SafeVarargs + public MyListP06(T... elements) { + super(elements); + } + public boolean isPalindrome() { + final long len = length(); + return LongStream.range(0, len / 2) + .allMatch(i -> Objects.equals(elementAt(i + 1), elementAt(len + 1 - 1 - i))); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP07.java b/src/main/java/org/nintynine/problems/MyListP07.java index 1f7c07b..c2aa509 100644 --- a/src/main/java/org/nintynine/problems/MyListP07.java +++ b/src/main/java/org/nintynine/problems/MyListP07.java @@ -5,25 +5,23 @@ import java.util.stream.Stream; public class MyListP07 extends MyListP06 { - @SafeVarargs - public MyListP07(T... elements) { - super(elements); - } + @SafeVarargs + public MyListP07(T... elements) { + super(elements); + } - @SuppressWarnings("unchecked") - public MyListP07 flatten() { - T[] flattenedArray = (T[]) Arrays.stream(items) - .flatMap(this::flattenHelper) - .toArray(); - return new MyListP07<>(flattenedArray); - } + @SuppressWarnings("unchecked") + public MyListP07 flatten() { + T[] flattenedArray = (T[]) Arrays.stream(items).flatMap(this::flattenHelper).toArray(); + return new MyListP07<>(flattenedArray); + } - protected Stream flattenHelper(Object item) { - return switch (item) { - case MyListP07 myListP07 -> Arrays.stream(myListP07.items).flatMap(this::flattenHelper); - case List objects -> objects.stream().flatMap(this::flattenHelper); - case Object[] objects -> Arrays.stream(objects).flatMap(this::flattenHelper); - case null, default -> Stream.of(item); - }; - } + protected Stream flattenHelper(Object item) { + return switch (item) { + case MyListP07 myListP07 -> Arrays.stream(myListP07.items).flatMap(this::flattenHelper); + case List objects -> objects.stream().flatMap(this::flattenHelper); + case Object[] objects -> Arrays.stream(objects).flatMap(this::flattenHelper); + case null, default -> Stream.of(item); + }; + } } diff --git a/src/main/java/org/nintynine/problems/MyListP08.java b/src/main/java/org/nintynine/problems/MyListP08.java index 2b05280..9aca4f2 100644 --- a/src/main/java/org/nintynine/problems/MyListP08.java +++ b/src/main/java/org/nintynine/problems/MyListP08.java @@ -5,22 +5,23 @@ import java.util.stream.LongStream; public class MyListP08 extends MyListP07 { - @SafeVarargs - public MyListP08(T... elements) { - super(elements); - } + @SafeVarargs + public MyListP08(T... elements) { + super(elements); + } - public MyListP08 compress() { - if (length() == 0) { - return new MyListP08<>(); - } + public MyListP08 compress() { + if (length() == 0) { + return new MyListP08<>(); + } - @SuppressWarnings("unchecked") - T[] compressed = LongStream.range(0, length()) - .filter(i -> i == 0 || !Objects.equals(elementAt(i + 1), elementAt(i))) - .mapToObj(k -> elementAt(k + 1)) - .toArray(size -> (T[]) Array.newInstance(items.getClass().getComponentType(), size)); + @SuppressWarnings("unchecked") + T[] compressed = + LongStream.range(0, length()) + .filter(i -> i == 0 || !Objects.equals(elementAt(i + 1), elementAt(i))) + .mapToObj(k -> elementAt(k + 1)) + .toArray(size -> (T[]) Array.newInstance(items.getClass().getComponentType(), size)); - return new MyListP08<>(compressed); - } + return new MyListP08<>(compressed); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP09.java b/src/main/java/org/nintynine/problems/MyListP09.java index dda8bd2..2850f7e 100644 --- a/src/main/java/org/nintynine/problems/MyListP09.java +++ b/src/main/java/org/nintynine/problems/MyListP09.java @@ -1,6 +1,5 @@ package org.nintynine.problems; - import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; @@ -8,60 +7,68 @@ import java.util.Objects; /** - * A generic list class that extends MyListP08 to provide functionality for packing - * consecutive duplicate elements into sublists. + * A generic list class that extends MyListP08 to provide functionality for packing consecutive + * duplicate elements into sublists. * * @param the type of elements in the list */ public class MyListP09 extends MyListP08 { - /** - * Constructs a new MyListP09 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP09(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP09 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP09(T... elements) { + super(elements); + } - /** - * Packs consecutive duplicate elements into sublists. - * Each sublist contains elements that are equal according to {@link Object#equals(Object)}. - * - *

Examples: - *

-     * [a, a, a, b, c, c] → [[a, a, a], [b], [c, c]]
-     * [a, b, a, b] → [[a], [b], [a], [b]]
-     * [] → []
-     * [a] → [[a]]
-     * 
- * - * @return a new MyListP09 instance where each element is a MyListP09 containing - * consecutive equal elements from the original list - * @throws NullPointerException if the list contains null elements - */ - @SuppressWarnings("unchecked") - public MyListP09> pack() { - if (length() == 0) { - return new MyListP09<>(); - } + /** + * Packs consecutive duplicate elements into sublists. Each sublist contains elements that are + * equal according to {@link Object#equals(Object)}. + * + *

Examples: + * + *

+   * [a, a, a, b, c, c] → [[a, a, a], [b], [c, c]]
+   * [a, b, a, b] → [[a], [b], [a], [b]]
+   * [] → []
+   * [a] → [[a]]
+   * 
+ * + * @return a new MyListP09 instance where each element is a MyListP09 containing consecutive equal + * elements from the original list + * @throws NullPointerException if the list contains null elements + */ + @SuppressWarnings("unchecked") + public MyListP09> pack() { + if (length() == 0) { + return new MyListP09<>(); + } - List> packed = Arrays.stream(items) - .sequential() - .collect(ArrayList::new, - (lists, item) -> { - if (lists.isEmpty() || !Objects.equals(item, lists.getLast().getFirst())) { - lists.add(new ArrayList<>(List.of(item))); - } else { - lists.getLast().add(item); - } - }, - ArrayList::addAll); + List> packed = + Arrays.stream(items) + .sequential() + .collect( + ArrayList::new, + (lists, item) -> { + if (lists.isEmpty() || !Objects.equals(item, lists.getLast().getFirst())) { + lists.add(new ArrayList<>(List.of(item))); + } else { + lists.getLast().add(item); + } + }, + ArrayList::addAll); - //noinspection rawtypes - return new MyListP09<>(packed.stream() - .map(group -> new MyListP09<>(group.toArray((T[]) Array.newInstance(items.getClass().getComponentType(), 0)))) - .toArray(MyListP09[]::new)); - } + //noinspection rawtypes + return new MyListP09<>( + packed.stream() + .map( + group -> + new MyListP09<>( + group.toArray( + (T[]) Array.newInstance(items.getClass().getComponentType(), 0)))) + .toArray(MyListP09[]::new)); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP10.java b/src/main/java/org/nintynine/problems/MyListP10.java index e5c0617..1a6f813 100644 --- a/src/main/java/org/nintynine/problems/MyListP10.java +++ b/src/main/java/org/nintynine/problems/MyListP10.java @@ -3,85 +3,88 @@ import java.util.Objects; /** - * A generic list class that provides run-length encoding functionality for consecutive duplicate elements. - * Uses MyListP09's packing functionality to implement run-length encoding compression. + * A generic list class that provides run-length encoding functionality for consecutive duplicate + * elements. Uses MyListP09's packing functionality to implement run-length encoding compression. * * @param the type of elements in the list */ public class MyListP10 extends MyListP09 { - /** - * Constructs a new MyListP10 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP10(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP10 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP10(T... elements) { + super(elements); + } - /** - * Performs run-length encoding on the list. Consecutive duplicates of elements - * are encoded as EncodedElement instances containing the count and the element. - * - *

Examples: - *

-     * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), (1 b), (2 c), (2 a), (1 d), (4 e)]
-     * [a, b, c] → [(1 a), (1 b), (1 c)]
-     * [] → []
-     * [a] → [(1 a)]
-     * 
- * - * @return a new MyListP10 containing EncodedElement instances representing the run-length encoding - * @throws NullPointerException if the list contains null elements - */ - public MyListP10> encode() { - MyListP09> packed = pack(); + /** + * Performs run-length encoding on the list. Consecutive duplicates of elements are encoded as + * EncodedElement instances containing the count and the element. + * + *

Examples: + * + *

+   * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), (1 b), (2 c), (2 a), (1 d), (4 e)]
+   * [a, b, c] → [(1 a), (1 b), (1 c)]
+   * [] → []
+   * [a] → [(1 a)]
+   * 
+ * + * @return a new MyListP10 containing EncodedElement instances representing the run-length + * encoding + * @throws NullPointerException if the list contains null elements + */ + public MyListP10> encode() { + MyListP09> packed = pack(); - @SuppressWarnings("unchecked") - EncodedElement[] encoded = packed.stream() - .map(sublist -> new EncodedElement<>(sublist.length(), sublist.elementAt(1))) - .toArray(EncodedElement[]::new); + @SuppressWarnings("unchecked") + EncodedElement[] encoded = + packed.stream() + .map(sublist -> new EncodedElement<>(sublist.length(), sublist.elementAt(1))) + .toArray(EncodedElement[]::new); - return new MyListP10<>(encoded); - } + return new MyListP10<>(encoded); + } + + /** + * Represents a run-length encoded element. + * + * @param the type of the element + */ + public static class EncodedElement { + final long count; + final T element; /** - * Represents a run-length encoded element. + * Creates a new EncodedElement with the specified count and element. * - * @param the type of the element + * @param count the number of consecutive occurrences + * @param element the element that was repeated */ - public static class EncodedElement { - final long count; - final T element; - - /** - * Creates a new EncodedElement with the specified count and element. - * - * @param count the number of consecutive occurrences - * @param element the element that was repeated - */ - public EncodedElement(long count, T element) { - this.count = count; - this.element = element; - } + public EncodedElement(long count, T element) { + this.count = count; + this.element = element; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EncodedElement that = (EncodedElement) o; - return count == that.count && Objects.equals(element, that.element); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EncodedElement that = (EncodedElement) o; + return count == that.count && Objects.equals(element, that.element); + } - @Override - public int hashCode() { - return Objects.hash(count, element); - } + @Override + public int hashCode() { + return Objects.hash(count, element); + } - @Override - public String toString() { - return "(" + count + " " + element + ")"; - } + @Override + public String toString() { + return "(" + count + " " + element + ")"; } + } } diff --git a/src/main/java/org/nintynine/problems/MyListP11.java b/src/main/java/org/nintynine/problems/MyListP11.java index 721be7f..0b2d991 100644 --- a/src/main/java/org/nintynine/problems/MyListP11.java +++ b/src/main/java/org/nintynine/problems/MyListP11.java @@ -1,53 +1,55 @@ package org.nintynine.problems; /** - * A generic list class that provides modified run-length encoding functionality. - * Single elements are kept as is, while only repeated elements are encoded as (N E) pairs. + * A generic list class that provides modified run-length encoding functionality. Single elements + * are kept as is, while only repeated elements are encoded as (N E) pairs. * * @param the type of elements in the list */ public class MyListP11 extends MyListP10 { - /** - * Constructs a new MyListP11 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP11(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP11 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP11(T... elements) { + super(elements); + } - /** - * Performs modified run-length encoding on the list. - * Single elements are kept as is, while consecutive duplicates - * are encoded as EncodedElement instances. - * - *

Examples: - *

-     * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), b, (2 c), (2 a), d, (4 e)]
-     * [a, b, c] → [a, b, c]
-     * [] → []
-     * [a] → [a]
-     * [a, a] → [(2 a)]
-     * 
- * - * @return a new MyListP11 containing a mix of original elements and EncodedElement instances - * @throws NullPointerException if the list contains null elements - */ - public MyListP11 encodeModified() { - MyListP09> packed = pack(); + /** + * Performs modified run-length encoding on the list. Single elements are kept as is, while + * consecutive duplicates are encoded as EncodedElement instances. + * + *

Examples: + * + *

+   * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), b, (2 c), (2 a), d, (4 e)]
+   * [a, b, c] → [a, b, c]
+   * [] → []
+   * [a] → [a]
+   * [a, a] → [(2 a)]
+   * 
+ * + * @return a new MyListP11 containing a mix of original elements and EncodedElement instances + * @throws NullPointerException if the list contains null elements + */ + public MyListP11 encodeModified() { + MyListP09> packed = pack(); - Object[] encoded = packed.stream() - .map(sublist -> { - if (sublist.length() == 1) { - return sublist.elementAt(1); - } else { - return new EncodedElement<>(sublist.length(), sublist.elementAt(1)); - } + Object[] encoded = + packed.stream() + .map( + sublist -> { + if (sublist.length() == 1) { + return sublist.elementAt(1); + } else { + return new EncodedElement<>(sublist.length(), sublist.elementAt(1)); + } }) - .toArray(); + .toArray(); - return new MyListP11<>(encoded); - } + return new MyListP11<>(encoded); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP12.java b/src/main/java/org/nintynine/problems/MyListP12.java index 034b310..755f1f3 100644 --- a/src/main/java/org/nintynine/problems/MyListP12.java +++ b/src/main/java/org/nintynine/problems/MyListP12.java @@ -5,57 +5,62 @@ import java.util.List; /** - * A generic list class that provides functionality to decode run-length encoded lists. - * Can decode both standard (P10) and modified (P11) run-length encodings. + * A generic list class that provides functionality to decode run-length encoded lists. Can decode + * both standard (P10) and modified (P11) run-length encodings. * * @param the type of elements in the list */ public class MyListP12 extends MyListP11 { - /** - * Constructs a new MyListP12 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP12(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP12 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP12(T... elements) { + super(elements); + } - /** - * Decodes a run-length encoded list, supporting both standard (P10) and modified (P11) encodings. - * For modified encoding, single elements are represented directly, while repeated elements - * are encoded as EncodedElement instances. - * - *

Examples: - *

-     * [(4 a), b, (2 c), (2 a), d, (4 e)] → [a, a, a, a, b, c, c, a, a, d, e, e, e, e]
-     * [a, b, c] → [a, b, c]
-     * [(2 a), (2 b)] → [a, a, b, b]
-     * [] → []
-     * [a] → [a]
-     * 
- * - * @param the type of elements in the decoded list - * @return a new MyListP12 containing the decoded sequence - * @throws IllegalArgumentException if the encoded list contains invalid elements - */ - @SuppressWarnings("unchecked") - public MyListP12 decode() { - List decoded = new ArrayList<>(); + /** + * Decodes a run-length encoded list, supporting both standard (P10) and modified (P11) encodings. + * For modified encoding, single elements are represented directly, while repeated elements are + * encoded as EncodedElement instances. + * + *

Examples: + * + *

+   * [(4 a), b, (2 c), (2 a), d, (4 e)] → [a, a, a, a, b, c, c, a, a, d, e, e, e, e]
+   * [a, b, c] → [a, b, c]
+   * [(2 a), (2 b)] → [a, a, b, b]
+   * [] → []
+   * [a] → [a]
+   * 
+ * + * @param the type of elements in the decoded list + * @return a new MyListP12 containing the decoded sequence + * @throws IllegalArgumentException if the encoded list contains invalid elements + */ + @SuppressWarnings("unchecked") + public MyListP12 decode() { + List decoded = new ArrayList<>(); - for (T item : items) { - if (item instanceof MyListP10.EncodedElement encoded) { - U element = (U) encoded.element; - for (long i = 0; i < encoded.count; i++) { - decoded.add(element); - } - } else { - decoded.add((U) item); - } + for (T item : items) { + if (item instanceof MyListP10.EncodedElement encoded) { + U element = (U) encoded.element; + for (long i = 0; i < encoded.count; i++) { + decoded.add(element); } - - return new MyListP12<>(decoded.toArray(size -> (U[]) Array.newInstance( - decoded.isEmpty() ? Object.class : decoded.getFirst().getClass(), size))); + } else { + decoded.add((U) item); + } } + + return new MyListP12<>( + decoded.toArray( + size -> + (U[]) + Array.newInstance( + decoded.isEmpty() ? Object.class : decoded.getFirst().getClass(), size))); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP13.java b/src/main/java/org/nintynine/problems/MyListP13.java index d3bd309..647ba1a 100644 --- a/src/main/java/org/nintynine/problems/MyListP13.java +++ b/src/main/java/org/nintynine/problems/MyListP13.java @@ -6,103 +6,105 @@ import java.util.Objects; /** - * A generic list class that provides direct run-length encoding functionality. - * Encodes consecutive duplicates without creating intermediate sublists. + * A generic list class that provides direct run-length encoding functionality. Encodes consecutive + * duplicates without creating intermediate sublists. * * @param the type of elements in the list */ public class MyListP13 extends MyListP12 { - /** - * Constructs a new org.nintynine.problems.MyListP13 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP13(T... elements) { - super(elements); - } - - /** - * Performs direct run-length encoding on the list. - * Consecutive duplicates are encoded as EncodedElement instances, - * while single elements are kept as is. - * Unlike P11, this implementation doesn't create intermediate sublists. - * - *

Examples: - *

-     * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), b, (2 c), (2 a), d, (4 e)]
-     * [a, b, c] → [a, b, c]
-     * [] → []
-     * [a] → [a]
-     * [a, a] → [(2 a)]
-     * 
- * - * @return a new org.nintynine.problems.MyListP13 containing a mix of original elements and EncodedElement instances - * @throws NullPointerException if the list contains null elements - */ - public MyListP13 encodeDirect() { - if (length() == 0) { - return new MyListP13<>(); - } + /** + * Constructs a new org.nintynine.problems.MyListP13 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP13(T... elements) { + super(elements); + } - List result = new ArrayList<>(); - T currentElement = elementAt(1); - long count = 1; + /** + * Performs direct run-length encoding on the list. Consecutive duplicates are encoded as + * EncodedElement instances, while single elements are kept as is. Unlike P11, this implementation + * doesn't create intermediate sublists. + * + *

Examples: + * + *

+   * [a, a, a, a, b, c, c, a, a, d, e, e, e, e] → [(4 a), b, (2 c), (2 a), d, (4 e)]
+   * [a, b, c] → [a, b, c]
+   * [] → []
+   * [a] → [a]
+   * [a, a] → [(2 a)]
+   * 
+ * + * @return a new org.nintynine.problems.MyListP13 containing a mix of original elements and + * EncodedElement instances + * @throws NullPointerException if the list contains null elements + */ + public MyListP13 encodeDirect() { + if (length() == 0) { + return new MyListP13<>(); + } - for (int i = 1; i < length(); i++) { - T element = elementAt(i + 1); - if (Objects.equals(currentElement, element)) { - count++; - } else { - addEncodedElement(result, count, currentElement); - currentElement = element; - count = 1; - } - } + List result = new ArrayList<>(); + T currentElement = elementAt(1); + long count = 1; - // Handle the last group + for (int i = 1; i < length(); i++) { + T element = elementAt(i + 1); + if (Objects.equals(currentElement, element)) { + count++; + } else { addEncodedElement(result, count, currentElement); - - return new MyListP13<>(result.toArray()); + currentElement = element; + count = 1; + } } - /** - * Helper method to add either an encoded element or a single element to the result list. - * - * @param result the list to add the element to - * @param count the count of consecutive occurrences - * @param element the element to add - */ - private void addEncodedElement(List result, long count, T element) { - if (count == 1) { - result.add(element); - } else { - result.add(new MyListP10.EncodedElement<>(count, element)); - } + // Handle the last group + addEncodedElement(result, count, currentElement); + + return new MyListP13<>(result.toArray()); + } + + /** + * Helper method to add either an encoded element or a single element to the result list. + * + * @param result the list to add the element to + * @param count the count of consecutive occurrences + * @param element the element to add + */ + private void addEncodedElement(List result, long count, T element) { + if (count == 1) { + result.add(element); + } else { + result.add(new MyListP10.EncodedElement<>(count, element)); } + } - /** - * Override of decode method to return MyListP13 instead of MyListP12 - */ - @Override - @SuppressWarnings({"unchecked", "DuplicatedCode"}) - public MyListP13 decode() { - List decoded = new ArrayList<>(); + /** Override of decode method to return MyListP13 instead of MyListP12 */ + @Override + @SuppressWarnings({"unchecked", "DuplicatedCode"}) + public MyListP13 decode() { + List decoded = new ArrayList<>(); - for (T item : items) { - if (item instanceof MyListP10.EncodedElement encoded) { - U element = (U) encoded.element; - for (long i = 0; i < encoded.count; i++) { - decoded.add(element); - } - } else { - decoded.add((U) item); - } + for (T item : items) { + if (item instanceof MyListP10.EncodedElement encoded) { + U element = (U) encoded.element; + for (long i = 0; i < encoded.count; i++) { + decoded.add(element); } - - return new MyListP13<>(decoded.toArray(size -> (U[]) Array.newInstance( - decoded.isEmpty() ? Object.class : decoded.getFirst().getClass(), size))); + } else { + decoded.add((U) item); + } } + return new MyListP13<>( + decoded.toArray( + size -> + (U[]) + Array.newInstance( + decoded.isEmpty() ? Object.class : decoded.getFirst().getClass(), size))); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP14.java b/src/main/java/org/nintynine/problems/MyListP14.java index 55e9618..6cd4b52 100644 --- a/src/main/java/org/nintynine/problems/MyListP14.java +++ b/src/main/java/org/nintynine/problems/MyListP14.java @@ -10,44 +10,41 @@ */ public class MyListP14 extends MyListP13 { - /** - * Constructs a new org.nintynine.problems.MyListP14 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP14(T... elements) { - super(elements); - } - - /** - * Duplicates each element in the list. - * Each element appears exactly twice in the resulting list. - * - *

Examples: - *

-     * [a, b, c, d] → [a, a, b, b, c, c, d, d]
-     * [a, a] → [a, a, a, a]
-     * [] → []
-     * [a] → [a, a]
-     * 
- * - * @return a new org.nintynine.problems.MyListP14 with duplicated elements - */ - public MyListP14 duplicate() { - if (length() == 0) { - return new MyListP14<>(); - } + /** + * Constructs a new org.nintynine.problems.MyListP14 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP14(T... elements) { + super(elements); + } - @SuppressWarnings("unchecked") - T[] duplicated = stream() - .flatMap(item -> Stream.of(item, item)) - .toArray(size -> (T[]) Array.newInstance( - items[0].getClass(), - size - )); - - return new MyListP14<>(duplicated); + /** + * Duplicates each element in the list. Each element appears exactly twice in the resulting list. + * + *

Examples: + * + *

+   * [a, b, c, d] → [a, a, b, b, c, c, d, d]
+   * [a, a] → [a, a, a, a]
+   * [] → []
+   * [a] → [a, a]
+   * 
+ * + * @return a new org.nintynine.problems.MyListP14 with duplicated elements + */ + public MyListP14 duplicate() { + if (length() == 0) { + return new MyListP14<>(); } + @SuppressWarnings("unchecked") + T[] duplicated = + stream() + .flatMap(item -> Stream.of(item, item)) + .toArray(size -> (T[]) Array.newInstance(items[0].getClass(), size)); + + return new MyListP14<>(duplicated); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP15.java b/src/main/java/org/nintynine/problems/MyListP15.java index 43e2027..c305740 100644 --- a/src/main/java/org/nintynine/problems/MyListP15.java +++ b/src/main/java/org/nintynine/problems/MyListP15.java @@ -11,49 +11,48 @@ */ public class MyListP15 extends MyListP14 { - /** - * Constructs a new MyListP15 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP15(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP15 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP15(T... elements) { + super(elements); + } - /** - * Replicates each element in the list a specified number of times. - * - *

Examples: - *

-     * [a, b, c] replicate 3 → [a, a, a, b, b, b, c, c, c]
-     * [a, b] replicate 2 → [a, a, b, b]
-     * [] replicate 5 → []
-     * [a] replicate 1 → [a]
-     * [a, b] replicate 0 → []
-     * 
- * - * @param times the number of times to replicate each element - * @return a new MyListP15 with replicated elements - * @throws IllegalArgumentException if times is negative - */ - public MyListP15 replicate(int times) { - if (times < 0) { - throw new IllegalArgumentException("Number of replications cannot be negative"); - } + /** + * Replicates each element in the list a specified number of times. + * + *

Examples: + * + *

+   * [a, b, c] replicate 3 → [a, a, a, b, b, b, c, c, c]
+   * [a, b] replicate 2 → [a, a, b, b]
+   * [] replicate 5 → []
+   * [a] replicate 1 → [a]
+   * [a, b] replicate 0 → []
+   * 
+ * + * @param times the number of times to replicate each element + * @return a new MyListP15 with replicated elements + * @throws IllegalArgumentException if times is negative + */ + public MyListP15 replicate(int times) { + if (times < 0) { + throw new IllegalArgumentException("Number of replications cannot be negative"); + } - if (times == 0 || length() == 0) { - return new MyListP15<>(); - } + if (times == 0 || length() == 0) { + return new MyListP15<>(); + } - @SuppressWarnings("unchecked") - T[] replicated = Arrays.stream(items) - .flatMap(item -> Stream.generate(() -> item).limit(times)) - .toArray(size -> (T[]) Array.newInstance( - items[0].getClass(), - size - )); + @SuppressWarnings("unchecked") + T[] replicated = + Arrays.stream(items) + .flatMap(item -> Stream.generate(() -> item).limit(times)) + .toArray(size -> (T[]) Array.newInstance(items[0].getClass(), size)); - return new MyListP15<>(replicated); - } + return new MyListP15<>(replicated); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP16.java b/src/main/java/org/nintynine/problems/MyListP16.java index c6526b2..76eecf7 100644 --- a/src/main/java/org/nintynine/problems/MyListP16.java +++ b/src/main/java/org/nintynine/problems/MyListP16.java @@ -10,51 +10,49 @@ */ public class MyListP16 extends MyListP15 { - /** - * Constructs a new MyListP16 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP16(T... elements) { - super(elements); + /** + * Constructs a new MyListP16 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP16(T... elements) { + super(elements); + } + + /** + * Drops every N'th element from the list. + * + *

Examples: + * + *

+   * [a, b, c, d, e, f] drop 3 → [a, b, d, e]
+   * [a, b, c] drop 1 → []
+   * [a, b, c] drop 4 → [a, b, c]
+   * [] drop 2 → []
+   * [a] drop 2 → [a]
+   * 
+ * + * @param n the position of elements to drop (every n'th element) + * @return a new MyListP16 with elements removed + * @throws IllegalArgumentException if n is less than 1 + */ + public MyListP16 drop(int n) { + if (n < 1) { + throw new IllegalArgumentException("N must be greater than 0"); } - /** - * Drops every N'th element from the list. - * - *

Examples: - *

-     * [a, b, c, d, e, f] drop 3 → [a, b, d, e]
-     * [a, b, c] drop 1 → []
-     * [a, b, c] drop 4 → [a, b, c]
-     * [] drop 2 → []
-     * [a] drop 2 → [a]
-     * 
- * - * @param n the position of elements to drop (every n'th element) - * @return a new MyListP16 with elements removed - * @throws IllegalArgumentException if n is less than 1 - */ - public MyListP16 drop(int n) { - if (n < 1) { - throw new IllegalArgumentException("N must be greater than 0"); - } - - if (length() == 0) { - return new MyListP16<>(); - } - - @SuppressWarnings("unchecked") - T[] filtered = LongStream.range(0, length()) - .filter(i -> (i + 1) % n != 0) - .mapToObj(i -> items[Math.toIntExact(i)]) - .toArray(size -> (T[]) Array.newInstance( - items[0].getClass(), - size - )); - - return new MyListP16<>(filtered); + if (length() == 0) { + return new MyListP16<>(); } + @SuppressWarnings("unchecked") + T[] filtered = + LongStream.range(0, length()) + .filter(i -> (i + 1) % n != 0) + .mapToObj(i -> items[Math.toIntExact(i)]) + .toArray(size -> (T[]) Array.newInstance(items[0].getClass(), size)); + + return new MyListP16<>(filtered); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP17.java b/src/main/java/org/nintynine/problems/MyListP17.java index 1c1ea0b..a223606 100644 --- a/src/main/java/org/nintynine/problems/MyListP17.java +++ b/src/main/java/org/nintynine/problems/MyListP17.java @@ -9,67 +9,64 @@ */ public class MyListP17 extends MyListP16 { - /** - * Constructs a new MyListP17 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP17(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP17 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP17(T... elements) { + super(elements); + } - /** - * Splits the list into two parts at the specified position. - * - *

Examples: - *

-     * [a, b, c, d, e] split 3 → ([a, b, c], [d, e])
-     * [a, b] split 0 → ([], [a, b])
-     * [a, b] split 2 → ([a, b], [])
-     * [] split 0 → ([], [])
-     * 
- * - * @param position the position at which to split the list - * @return a pair of MyListP17 instances containing the split parts - * @throws IllegalArgumentException if position is negative or greater than list length - */ - public Pair, MyListP17> split(int position) { - if (position < 0 || position > length()) { - throw new IllegalArgumentException( - "Position must be between 0 and list length (inclusive)" - ); - } + /** + * Splits the list into two parts at the specified position. + * + *

Examples: + * + *

+   * [a, b, c, d, e] split 3 → ([a, b, c], [d, e])
+   * [a, b] split 0 → ([], [a, b])
+   * [a, b] split 2 → ([a, b], [])
+   * [] split 0 → ([], [])
+   * 
+ * + * @param position the position at which to split the list + * @return a pair of MyListP17 instances containing the split parts + * @throws IllegalArgumentException if position is negative or greater than list length + */ + public Pair, MyListP17> split(int position) { + if (position < 0 || position > length()) { + throw new IllegalArgumentException("Position must be between 0 and list length (inclusive)"); + } - // Create arrays for both parts - @SuppressWarnings("unchecked") - T[] firstPart = (T[]) new Object[position]; - @SuppressWarnings("unchecked") - T[] secondPart = (T[]) new Object[Math.toIntExact(length() - position)]; + // Create arrays for both parts + @SuppressWarnings("unchecked") + T[] firstPart = (T[]) new Object[position]; + @SuppressWarnings("unchecked") + T[] secondPart = (T[]) new Object[Math.toIntExact(length() - position)]; - // Copy elements to first part - System.arraycopy(items, 0, firstPart, 0, position); + // Copy elements to first part + System.arraycopy(items, 0, firstPart, 0, position); - // Copy elements to second part - IntStream.iterate(position, i -> i < length(), i -> i + 1).forEachOrdered(i -> secondPart[i - position] = items[i]); + // Copy elements to second part + IntStream.iterate(position, i -> i < length(), i -> i + 1) + .forEachOrdered(i -> secondPart[i - position] = items[i]); - return new Pair<>( - new MyListP17<>(firstPart), - new MyListP17<>(secondPart) - ); - } + return new Pair<>(new MyListP17<>(firstPart), new MyListP17<>(secondPart)); + } - /** - * A simple pair class to hold two values. - * - * @param type of the first value - * @param type of the second value - */ - public record Pair(A first, B second) { + /** + * A simple pair class to hold two values. + * + * @param type of the first value + * @param type of the second value + */ + public record Pair(A first, B second) { - @Override - public String toString() { - return "(" + first + ", " + second + ")"; - } + @Override + public String toString() { + return "(" + first + ", " + second + ")"; } + } } diff --git a/src/main/java/org/nintynine/problems/MyListP18.java b/src/main/java/org/nintynine/problems/MyListP18.java index db0bffb..e771b38 100644 --- a/src/main/java/org/nintynine/problems/MyListP18.java +++ b/src/main/java/org/nintynine/problems/MyListP18.java @@ -9,61 +9,58 @@ */ public class MyListP18 extends MyListP17 { - /** - * Constructs a new MyListP18 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP18(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP18 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP18(T... elements) { + super(elements); + } - /** - * Extracts a slice from the list between startIndex and endIndex (inclusive, 1-based indices). - * - *

Examples: - *

-     * [a, b, c, d, e] slice(2, 4) → [b, c, d]
-     * [a, b, c] slice(1, 3) → [a, b, c]
-     * [a, b, c, d] slice(2, 2) → [b]
-     * 
- * - * @param startIndex the starting index (1-based) - * @param endIndex the ending index (1-based) - * @return a new MyListP18 containing the slice - * @throws IllegalArgumentException if indices are invalid - */ - public MyListP18 slice(int startIndex, int endIndex) { - // Convert to 0-based indices for internal use - int start = startIndex - 1; - int end = endIndex - 1; + /** + * Extracts a slice from the list between startIndex and endIndex (inclusive, 1-based indices). + * + *

Examples: + * + *

+   * [a, b, c, d, e] slice(2, 4) → [b, c, d]
+   * [a, b, c] slice(1, 3) → [a, b, c]
+   * [a, b, c, d] slice(2, 2) → [b]
+   * 
+ * + * @param startIndex the starting index (1-based) + * @param endIndex the ending index (1-based) + * @return a new MyListP18 containing the slice + * @throws IllegalArgumentException if indices are invalid + */ + public MyListP18 slice(int startIndex, int endIndex) { + // Convert to 0-based indices for internal use + int start = startIndex - 1; + int end = endIndex - 1; - // Validate indices - if (startIndex < 1) { - throw new IllegalArgumentException("Start index must be at least 1"); - } - if (endIndex > length()) { - throw new IllegalArgumentException( - "End index cannot exceed list length (" + length() + ")" - ); - } - if (startIndex > endIndex) { - throw new IllegalArgumentException( - "Start index cannot be greater than end index" - ); - } + // Validate indices + if (startIndex < 1) { + throw new IllegalArgumentException("Start index must be at least 1"); + } + if (endIndex > length()) { + throw new IllegalArgumentException("End index cannot exceed list length (" + length() + ")"); + } + if (startIndex > endIndex) { + throw new IllegalArgumentException("Start index cannot be greater than end index"); + } - // Calculate slice length - int sliceLength = end - start + 1; + // Calculate slice length + int sliceLength = end - start + 1; - // Create array for the slice - @SuppressWarnings("unchecked") - T[] slicedItems = (T[]) new Object[sliceLength]; + // Create array for the slice + @SuppressWarnings("unchecked") + T[] slicedItems = (T[]) new Object[sliceLength]; - // Copy elements to the slice - range(0, sliceLength).forEach(i -> slicedItems[i] = items[start + i]); + // Copy elements to the slice + range(0, sliceLength).forEach(i -> slicedItems[i] = items[start + i]); - return new MyListP18<>(slicedItems); - } + return new MyListP18<>(slicedItems); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP19.java b/src/main/java/org/nintynine/problems/MyListP19.java index e12425f..884db47 100644 --- a/src/main/java/org/nintynine/problems/MyListP19.java +++ b/src/main/java/org/nintynine/problems/MyListP19.java @@ -9,61 +9,64 @@ */ public class MyListP19 extends MyListP18 { - /** - * Constructs a new MyListP19 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP19(T... elements) { - super(elements); - } - - /** - * Rotates the list N places to the left. - * Negative values rotate to the right. - * - *

Examples: - *

-     * [a, b, c, d] rotate 1 → [b, c, d, a]
-     * [a, b, c, d] rotate -1 → [d, a, b, c]
-     * [a, b, c, d] rotate 4 → [a, b, c, d]
-     * [a, b, c, d] rotate 5 → [b, c, d, a]
-     * 
- * - * @param n number of places to rotate (positive for left, negative for right) - * @return a new MyListP19 containing the rotated elements - */ - public MyListP19 rotate(int n) { - if (length() <= 1) { - return new MyListP19<>(items); - } + /** + * Constructs a new MyListP19 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP19(T... elements) { + super(elements); + } - // Normalize n to be within list length - n = Math.toIntExact(n % length()); - if (n < 0) { - n += Math.toIntExact(length()); // Convert right rotation to the equivalent left rotation - } - - if (n == 0) { - return new MyListP19<>(items); - } + /** + * Rotates the list N places to the left. Negative values rotate to the right. + * + *

Examples: + * + *

+   * [a, b, c, d] rotate 1 → [b, c, d, a]
+   * [a, b, c, d] rotate -1 → [d, a, b, c]
+   * [a, b, c, d] rotate 4 → [a, b, c, d]
+   * [a, b, c, d] rotate 5 → [b, c, d, a]
+   * 
+ * + * @param n number of places to rotate (positive for left, negative for right) + * @return a new MyListP19 containing the rotated elements + */ + public MyListP19 rotate(int n) { + if (length() <= 1) { + return new MyListP19<>(items); + } - // Split the list at a rotation point - Pair, MyListP17> parts = split(n); + // Normalize n to be within list length + n = Math.toIntExact(n % length()); + if (n < 0) { + n += Math.toIntExact(length()); // Convert right rotation to the equivalent left rotation + } - // Create an array for rotated elements - @SuppressWarnings("unchecked") - T[] rotated = (T[]) new Object[Math.toIntExact(length())]; + if (n == 0) { + return new MyListP19<>(items); + } - // Copy the second part - LongStream.iterate(0, i -> i < parts.second().length(), i -> i + 1).forEachOrdered(i -> rotated[Math.toIntExact(i)] = parts.second().elementAt(i + 1)); + // Split the list at a rotation point + Pair, MyListP17> parts = split(n); - // Copy the first part - LongStream.iterate(0, i -> i < parts.first().length(), i -> i + 1).forEachOrdered(i -> rotated[Math.toIntExact(parts.second().length() + i)] = parts.first().elementAt(i + 1)); + // Create an array for rotated elements + @SuppressWarnings("unchecked") + T[] rotated = (T[]) new Object[Math.toIntExact(length())]; - return new MyListP19<>(rotated); - } + // Copy the second part + LongStream.iterate(0, i -> i < parts.second().length(), i -> i + 1) + .forEachOrdered(i -> rotated[Math.toIntExact(i)] = parts.second().elementAt(i + 1)); + // Copy the first part + LongStream.iterate(0, i -> i < parts.first().length(), i -> i + 1) + .forEachOrdered( + i -> + rotated[Math.toIntExact(parts.second().length() + i)] = + parts.first().elementAt(i + 1)); + return new MyListP19<>(rotated); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP20.java b/src/main/java/org/nintynine/problems/MyListP20.java index 98ca759..d66a155 100644 --- a/src/main/java/org/nintynine/problems/MyListP20.java +++ b/src/main/java/org/nintynine/problems/MyListP20.java @@ -9,53 +9,53 @@ */ public class MyListP20 extends MyListP19 { - /** - * Constructs a new MyListP20 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP20(T... elements) { - super(elements); + /** + * Constructs a new MyListP20 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP20(T... elements) { + super(elements); + } + + /** + * Removes the element at the specified position (1-based indexing). Returns a pair containing the + * removed element and the resulting list. + * + *

Examples: + * + *

+   * [a, b, c, d] removeAt(2) → (b, [a, c, d])
+   * [a] removeAt(1) → (a, [])
+   * 
+ * + * @param position the position of the element to remove (1-based) + * @return a pair containing the removed element and the new list + * @throws IllegalArgumentException if position is invalid + */ + public Pair> removeAt(int position) { + if (position < 1 || position > length()) { + throw new IllegalArgumentException("Position must be between 1 and " + length()); } - /** - * Removes the element at the specified position (1-based indexing). - * Returns a pair containing the removed element and the resulting list. - * - *

Examples: - *

-     * [a, b, c, d] removeAt(2) → (b, [a, c, d])
-     * [a] removeAt(1) → (a, [])
-     * 
- * - * @param position the position of the element to remove (1-based) - * @return a pair containing the removed element and the new list - * @throws IllegalArgumentException if position is invalid - */ - public Pair> removeAt(int position) { - if (position < 1 || position > length()) { - throw new IllegalArgumentException( - "Position must be between 1 and " + length() - ); - } - - // Convert to 0-based index - int index = position - 1; - - // Store element to be removed - T removedElement = items[index]; - - // Create new array without the element - @SuppressWarnings("unchecked") - T[] newItems = (T[]) new Object[Math.toIntExact(length() - 1)]; - - // Copy elements before the removal position - IntStream.range(0, index).forEach(i -> newItems[i] = items[i]); - - // Copy elements after the removal position - IntStream.iterate(index + 1, i -> i < length(), i -> i + 1).forEach(i -> newItems[i - 1] = items[i]); - - return new Pair<>(removedElement, new MyListP20<>(newItems)); - } + // Convert to 0-based index + int index = position - 1; + + // Store element to be removed + T removedElement = items[index]; + + // Create new array without the element + @SuppressWarnings("unchecked") + T[] newItems = (T[]) new Object[Math.toIntExact(length() - 1)]; + + // Copy elements before the removal position + IntStream.range(0, index).forEach(i -> newItems[i] = items[i]); + + // Copy elements after the removal position + IntStream.iterate(index + 1, i -> i < length(), i -> i + 1) + .forEach(i -> newItems[i - 1] = items[i]); + + return new Pair<>(removedElement, new MyListP20<>(newItems)); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP21.java b/src/main/java/org/nintynine/problems/MyListP21.java index 7d52cd2..935036a 100644 --- a/src/main/java/org/nintynine/problems/MyListP21.java +++ b/src/main/java/org/nintynine/problems/MyListP21.java @@ -7,56 +7,55 @@ */ public class MyListP21 extends MyListP20 { - /** - * Constructs a new MyListP21 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP21(T... elements) { - super(elements); + /** + * Constructs a new MyListP21 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP21(T... elements) { + super(elements); + } + + /** + * Inserts an element at the specified position (1-based indexing). + * + *

Examples: + * + *

+   * [a, b, c] insertAt("x", 2) → [a, x, b, c]
+   * [] insertAt("x", 1) → [x]
+   * [a] insertAt("x", 1) → [x, a]
+   * 
+ * + * @param element the element to insert + * @param position the position where to insert (1-based) + * @return a new MyListP21 with the element inserted + * @throws IllegalArgumentException if the position is invalid + */ + public MyListP21 insertAt(T element, int position) { + if (position < 1 || position > length() + 1) { + throw new IllegalArgumentException("Position must be between 1 and " + (length() + 1)); } - /** - * Inserts an element at the specified position (1-based indexing). - * - *

Examples: - *

-     * [a, b, c] insertAt("x", 2) → [a, x, b, c]
-     * [] insertAt("x", 1) → [x]
-     * [a] insertAt("x", 1) → [x, a]
-     * 
- * - * @param element the element to insert - * @param position the position where to insert (1-based) - * @return a new MyListP21 with the element inserted - * @throws IllegalArgumentException if the position is invalid - */ - public MyListP21 insertAt(T element, int position) { - if (position < 1 || position > length() + 1) { - throw new IllegalArgumentException( - "Position must be between 1 and " + (length() + 1) - ); - } - - // Convert to 0-based index - int index = position - 1; - - // Create a new array with space for a new element - @SuppressWarnings("unchecked") - T[] newItems = (T[]) new Object[Math.toIntExact(length() + 1)]; - - // Copy elements before the insertion point - System.arraycopy(items, 0, newItems, 0, index); - - // Insert new element - newItems[index] = element; - - // Copy elements after the insertion point - for (int i = index; i < length(); i++) { - newItems[i + 1] = items[i]; - } - - return new MyListP21<>(newItems); + // Convert to 0-based index + int index = position - 1; + + // Create a new array with space for a new element + @SuppressWarnings("unchecked") + T[] newItems = (T[]) new Object[Math.toIntExact(length() + 1)]; + + // Copy elements before the insertion point + System.arraycopy(items, 0, newItems, 0, index); + + // Insert new element + newItems[index] = element; + + // Copy elements after the insertion point + for (int i = index; i < length(); i++) { + newItems[i + 1] = items[i]; } + + return new MyListP21<>(newItems); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP22.java b/src/main/java/org/nintynine/problems/MyListP22.java index 84cd822..5bf6a67 100644 --- a/src/main/java/org/nintynine/problems/MyListP22.java +++ b/src/main/java/org/nintynine/problems/MyListP22.java @@ -7,47 +7,48 @@ */ public class MyListP22 extends MyListP21 { - /** - * Constructs a new MyListP22 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP22(T... elements) { - super(elements); - } - - /** - * Creates a list containing all integers within the given range (inclusive). - * If start > end, creates list in decreasing order. - * - *

Examples: - *

-     * range(4, 9) → [4, 5, 6, 7, 8, 9]
-     * range(9, 4) → [9, 8, 7, 6, 5, 4]
-     * range(3, 3) → [3]
-     * 
- * - * @param start the starting value - * @param end the ending value - * @return a new MyListP22 containing the range of integers - */ - public static MyListP22 range(int start, int end) { - int size = Math.abs(end - start) + 1; - Integer[] numbers = new Integer[size]; + /** + * Constructs a new MyListP22 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP22(T... elements) { + super(elements); + } - if (start <= end) { - // Ascending order - for (int i = 0; i < size; i++) { - numbers[i] = start + i; - } - } else { - // Descending order - for (int i = 0; i < size; i++) { - numbers[i] = start - i; - } - } + /** + * Creates a list containing all integers within the given range (inclusive). If start > end, + * creates list in decreasing order. + * + *

Examples: + * + *

+   * range(4, 9) → [4, 5, 6, 7, 8, 9]
+   * range(9, 4) → [9, 8, 7, 6, 5, 4]
+   * range(3, 3) → [3]
+   * 
+ * + * @param start the starting value + * @param end the ending value + * @return a new MyListP22 containing the range of integers + */ + public static MyListP22 range(int start, int end) { + int size = Math.abs(end - start) + 1; + Integer[] numbers = new Integer[size]; - return new MyListP22<>(numbers); + if (start <= end) { + // Ascending order + for (int i = 0; i < size; i++) { + numbers[i] = start + i; + } + } else { + // Descending order + for (int i = 0; i < size; i++) { + numbers[i] = start - i; + } } + + return new MyListP22<>(numbers); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP23.java b/src/main/java/org/nintynine/problems/MyListP23.java index b3d705f..c7f8bd3 100644 --- a/src/main/java/org/nintynine/problems/MyListP23.java +++ b/src/main/java/org/nintynine/problems/MyListP23.java @@ -9,62 +9,61 @@ */ public class MyListP23 extends MyListP22 { - private static final Random random = new Random(); + private static final Random random = new Random(); - /** - * Constructs a new MyListP23 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP23(T... elements) { - super(elements); - } - - /** - * Randomly selects N elements from the list. - * If N is greater than list size, returns all elements in random order. - * - *

Examples: - *

-     * [a, b, c, d] rndSelect(2) → might return [c, a]
-     * [a, b] rndSelect(3) → might return [b, a]
-     * [a, b, c] rndSelect(0) → []
-     * 
- * - * @param n number of elements to select - * @return a new MyListP23 containing randomly selected elements - * @throws IllegalArgumentException if n is negative - */ - public MyListP23 rndSelect(int n) { - if (n < 0) { - throw new IllegalArgumentException("Number of elements to select must be non-negative"); - } + /** + * Constructs a new MyListP23 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP23(T... elements) { + super(elements); + } - // If n is larger than list size, return all elements in random order - n = Math.toIntExact(Math.min(n, length())); + /** + * Randomly selects N elements from the list. If N is greater than list size, returns all elements + * in random order. + * + *

Examples: + * + *

+   * [a, b, c, d] rndSelect(2) → might return [c, a]
+   * [a, b] rndSelect(3) → might return [b, a]
+   * [a, b, c] rndSelect(0) → []
+   * 
+ * + * @param n number of elements to select + * @return a new MyListP23 containing randomly selected elements + * @throws IllegalArgumentException if n is negative + */ + public MyListP23 rndSelect(int n) { + if (n < 0) { + throw new IllegalArgumentException("Number of elements to select must be non-negative"); + } - // Create a working copy to avoid modifying an original list - MyListP23 workingCopy = new MyListP23<>(items); + // If n is larger than list size, return all elements in random order + n = Math.toIntExact(Math.min(n, length())); - @SuppressWarnings("unchecked") - T[] selected = (T[]) new Object[n]; + // Create a working copy to avoid modifying an original list + MyListP23 workingCopy = new MyListP23<>(items); - // Select n elements - for (int i = 0; i < n; i++) { - // Get random position (1-based for removeAt) - int position = random.nextInt(Math.toIntExact(workingCopy.length())) + 1; + @SuppressWarnings("unchecked") + T[] selected = (T[]) new Object[n]; - // Remove and store the selected element - Pair> result = workingCopy.removeAt(position); - selected[i] = result.first(); + // Select n elements + for (int i = 0; i < n; i++) { + // Get random position (1-based for removeAt) + int position = random.nextInt(Math.toIntExact(workingCopy.length())) + 1; - // Update working copy - workingCopy = new MyListP23<>(result.second().items); - } + // Remove and store the selected element + Pair> result = workingCopy.removeAt(position); + selected[i] = result.first(); - return new MyListP23<>(selected); + // Update working copy + workingCopy = new MyListP23<>(result.second().items); } - + return new MyListP23<>(selected); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP24.java b/src/main/java/org/nintynine/problems/MyListP24.java index 7619f17..f67646c 100644 --- a/src/main/java/org/nintynine/problems/MyListP24.java +++ b/src/main/java/org/nintynine/problems/MyListP24.java @@ -7,52 +7,51 @@ */ public class MyListP24 extends MyListP23 { - /** - * Constructs a new MyListP24 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP24(T... elements) { - super(elements); - } - - /** - * Generates N different random numbers from the range 1…M. - * - *

Examples: - *

-     * lottoSelect(6, 49) → might return [23, 1, 17, 33, 21, 37]
-     * lottoSelect(3, 10) → might return [7, 2, 9]
-     * lottoSelect(1, 1) → [1]
-     * 
- * - * @param n number of numbers to draw (N) - * @param m maximum number in range (M) - * @return a new MyListP24 containing N random numbers from 1…M - * @throws IllegalArgumentException if n < 0 or m < 1 or n > m - */ - public static MyListP24 lottoSelect(int n, int m) { - if (n < 0) { - throw new IllegalArgumentException("Number of selections must be non-negative"); - } - if (m < 1) { - throw new IllegalArgumentException("Maximum number must be positive"); - } - if (n > m) { - throw new IllegalArgumentException( - "Cannot select " + n + " numbers from ranged of size " + m - ); - } + /** + * Constructs a new MyListP24 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP24(T... elements) { + super(elements); + } - // Generate ranged 1…M using P22's ranged method - MyListP22 ranged = range(1, m); + /** + * Generates N different random numbers from the range 1…M. + * + *

Examples: + * + *

+   * lottoSelect(6, 49) → might return [23, 1, 17, 33, 21, 37]
+   * lottoSelect(3, 10) → might return [7, 2, 9]
+   * lottoSelect(1, 1) → [1]
+   * 
+ * + * @param n number of numbers to draw (N) + * @param m maximum number in range (M) + * @return a new MyListP24 containing N random numbers from 1…M + * @throws IllegalArgumentException if n < 0 or m < 1 or n > m + */ + public static MyListP24 lottoSelect(int n, int m) { + if (n < 0) { + throw new IllegalArgumentException("Number of selections must be non-negative"); + } + if (m < 1) { + throw new IllegalArgumentException("Maximum number must be positive"); + } + if (n > m) { + throw new IllegalArgumentException( + "Cannot select " + n + " numbers from ranged of size " + m); + } - // Convert to P23 to use random selection - MyListP23 pool = new MyListP23<>(ranged.stream().toList().toArray(new Integer[0])); + // Generate ranged 1…M using P22's ranged method + MyListP22 ranged = range(1, m); - // Select N random numbers using P23's rndSelect - return new MyListP24<>(pool.rndSelect(n).stream().toList().toArray(new Integer[0])); + // Convert to P23 to use random selection + MyListP23 pool = new MyListP23<>(ranged.stream().toList().toArray(new Integer[0])); - } + // Select N random numbers using P23's rndSelect + return new MyListP24<>(pool.rndSelect(n).stream().toList().toArray(new Integer[0])); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP25.java b/src/main/java/org/nintynine/problems/MyListP25.java index 57fbc68..03cb9f5 100644 --- a/src/main/java/org/nintynine/problems/MyListP25.java +++ b/src/main/java/org/nintynine/problems/MyListP25.java @@ -9,32 +9,35 @@ */ public class MyListP25 extends MyListP24 { - /** - * Constructs a new MyListP25 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP25(T... elements) { - super(elements); - } + /** + * Constructs a new MyListP25 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP25(T... elements) { + super(elements); + } - /** - * Generates a random permutation of the list elements. - * - *

Examples: - *

-     * [a, b, c] → might return [b, c, a]
-     * [1, 2] → might return [2, 1]
-     * [x] → [x]
-     * [] → []
-     * 
- * - * @return a new MyListP25 containing a random permutation of elements` - */ - @SuppressWarnings("unchecked") - public MyListP25 randomPermutation() { - // Using P23's rndSelect to select all elements randomly - return new MyListP25<>(rndSelect(Math.toIntExact(length())).stream().toArray(size -> (T[]) Array.newInstance(items.getClass().getComponentType(), size))); - } + /** + * Generates a random permutation of the list elements. + * + *

Examples: + * + *

+   * [a, b, c] → might return [b, c, a]
+   * [1, 2] → might return [2, 1]
+   * [x] → [x]
+   * [] → []
+   * 
+ * + * @return a new MyListP25 containing a random permutation of elements` + */ + @SuppressWarnings("unchecked") + public MyListP25 randomPermutation() { + // Using P23's rndSelect to select all elements randomly + return new MyListP25<>( + rndSelect(Math.toIntExact(length())).stream() + .toArray(size -> (T[]) Array.newInstance(items.getClass().getComponentType(), size))); + } } diff --git a/src/main/java/org/nintynine/problems/MyListP26.java b/src/main/java/org/nintynine/problems/MyListP26.java index 282a4ca..1054560 100644 --- a/src/main/java/org/nintynine/problems/MyListP26.java +++ b/src/main/java/org/nintynine/problems/MyListP26.java @@ -10,80 +10,80 @@ */ public class MyListP26 extends MyListP25 { - /** - * Constructs a new MyListP26 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP26(T... elements) { - super(elements); - } - - /** - * Calculates the number of possible combinations (n choose k). - * - * @param n total number of elements - * @param k number of elements to choose - * @return number of possible combinations - */ - public static long binomialCoefficient(int n, int k) { - if (k < 0 || k > n) return 0; - if (k == 0 || k == n) return 1; + /** + * Constructs a new MyListP26 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP26(T... elements) { + super(elements); + } - // Use symmetry to optimize calculation - if (k > n - k) { - k = n - k; - } + /** + * Calculates the number of possible combinations (n choose k). + * + * @param n total number of elements + * @param k number of elements to choose + * @return number of possible combinations + */ + public static long binomialCoefficient(int n, int k) { + if (k < 0 || k > n) return 0; + if (k == 0 || k == n) return 1; - long result = 1; - for (int i = 0; i < k; i++) { - result = result * (n - i) / (i + 1); - } - return result; + // Use symmetry to optimize calculation + if (k > n - k) { + k = n - k; } - /** - * Generates all combinations of K elements from the list. - * - *

Examples: - *

-     * [a, b, c], k=2 → [[a, b], [a, c], [b, c]]
-     * [1, 2, 3, 4], k=3 → [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
-     * [x, y], k=1 → [[x], [y]]
-     * 
- * - * @param k number of elements in each combination - * @return list of all possible combinations - * @throws IllegalArgumentException if k is negative or greater than list size - */ - public List> combinations(int k) { - if (k < 0) { - throw new IllegalArgumentException("k cannot be negative"); - } - if (k > length()) { - throw new IllegalArgumentException("k cannot be greater than list size"); - } + long result = 1; + for (int i = 0; i < k; i++) { + result = result * (n - i) / (i + 1); + } + return result; + } - List> result = new ArrayList<>(); - generateCombinations(0, k, new ArrayList<>(), result); - return result; + /** + * Generates all combinations of K elements from the list. + * + *

Examples: + * + *

+   * [a, b, c], k=2 → [[a, b], [a, c], [b, c]]
+   * [1, 2, 3, 4], k=3 → [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
+   * [x, y], k=1 → [[x], [y]]
+   * 
+ * + * @param k number of elements in each combination + * @return list of all possible combinations + * @throws IllegalArgumentException if k is negative or greater than list size + */ + public List> combinations(int k) { + if (k < 0) { + throw new IllegalArgumentException("k cannot be negative"); } + if (k > length()) { + throw new IllegalArgumentException("k cannot be greater than list size"); + } + + List> result = new ArrayList<>(); + generateCombinations(0, k, new ArrayList<>(), result); + return result; + } - @SuppressWarnings("unchecked") - private void generateCombinations(int start, int k, List current, - List> result) { - if (k == 0) { - // Create a new combination when we've selected k elements - result.add(new MyListP26<>(current.toArray((T[]) new Object[0]))); - return; - } + @SuppressWarnings("unchecked") + private void generateCombinations(int start, int k, List current, List> result) { + if (k == 0) { + // Create a new combination when we've selected k elements + result.add(new MyListP26<>(current.toArray((T[]) new Object[0]))); + return; + } - // For each remaining position, try to include the element at that position - for (int i = start; i <= length() - k; i++) { - current.add(elementAt(1 + i)); - generateCombinations(i + 1, k - 1, current, result); - current.removeLast(); - } + // For each remaining position, try to include the element at that position + for (int i = start; i <= length() - k; i++) { + current.add(elementAt(1 + i)); + generateCombinations(i + 1, k - 1, current, result); + current.removeLast(); } + } } diff --git a/src/main/java/org/nintynine/problems/MyListP27.java b/src/main/java/org/nintynine/problems/MyListP27.java index d59c6ed..9d4d10a 100644 --- a/src/main/java/org/nintynine/problems/MyListP27.java +++ b/src/main/java/org/nintynine/problems/MyListP27.java @@ -12,115 +12,111 @@ */ public class MyListP27 extends MyListP26 { - /** - * Constructs a new MyListP27 instance with the given elements. - * - * @param elements the elements to initialize the list with - */ - @SafeVarargs - public MyListP27(T... elements) { - super(elements); + /** + * Constructs a new MyListP27 instance with the given elements. + * + * @param elements the elements to initialize the list with + */ + @SafeVarargs + public MyListP27(T... elements) { + super(elements); + } + + /** + * Calculates multinomial coefficient for given group sizes. + * + * @param n total number of elements + * @param k array of group sizes + * @return multinomial coefficient + */ + public static long multinomialCoefficient(int n, int... k) { + // Validate input + int sum = Arrays.stream(k).sum(); + if (sum != n) { + throw new IllegalArgumentException("Sum of group sizes must equal total size"); } - /** - * Calculates multinomial coefficient for given group sizes. - * - * @param n total number of elements - * @param k array of group sizes - * @return multinomial coefficient - */ - public static long multinomialCoefficient(int n, int... k) { - // Validate input - int sum = Arrays.stream(k).sum(); - if (sum != n) { - throw new IllegalArgumentException( - "Sum of group sizes must equal total size" - ); - } - - long result = 1; - int denominator = 1; - - // Calculate n!/(k1!*k2!*...km!) - for (int i = 1; i <= n; i++) { - result *= i; - } - - for (int size : k) { - for (int i = 1; i <= size; i++) { - denominator *= i; - } - } - - return result / denominator; + long result = 1; + int denominator = 1; + + // Calculate n!/(k1!*k2!*...km!) + for (int i = 1; i <= n; i++) { + result *= i; + } + + for (int size : k) { + for (int i = 1; i <= size; i++) { + denominator *= i; + } } - /** - * Generates all possible ways to group 9 people into groups of 2, 3, and 4. - * - * @return list of all possible groupings - * @throws IllegalStateException if the list size is not 9 - */ - public List>> group3() { - if (length() != 9) { - throw new IllegalStateException("List must contain exactly 9 elements"); - } - return group(Arrays.asList(2, 3, 4)); + return result / denominator; + } + + /** + * Generates all possible ways to group 9 people into groups of 2, 3, and 4. + * + * @return list of all possible groupings + * @throws IllegalStateException if the list size is not 9 + */ + public List>> group3() { + if (length() != 9) { + throw new IllegalStateException("List must contain exactly 9 elements"); + } + return group(Arrays.asList(2, 3, 4)); + } + + /** + * Generates all possible ways to group elements according to specified group sizes. + * + * @param groupSizes list of required group sizes + * @return list of all possible groupings + * @throws IllegalArgumentException if group sizes don't sum to list size + */ + public List>> group(List groupSizes) { + // Validate input + int sum = groupSizes.stream().mapToInt(Integer::intValue).sum(); + if (sum != length()) { + throw new IllegalArgumentException("Sum of group sizes must equal list size"); } - /** - * Generates all possible ways to group elements according to specified group sizes. - * - * @param groupSizes list of required group sizes - * @return list of all possible groupings - * @throws IllegalArgumentException if group sizes don't sum to list size - */ - public List>> group(List groupSizes) { - // Validate input - int sum = groupSizes.stream().mapToInt(Integer::intValue).sum(); - if (sum != length()) { - throw new IllegalArgumentException( - "Sum of group sizes must equal list size" - ); - } - - List>> result = new ArrayList<>(); - generateGroups(new ArrayList<>(Set.of(items)), groupSizes, new ArrayList<>(), result); - return result; + List>> result = new ArrayList<>(); + generateGroups(new ArrayList<>(Set.of(items)), groupSizes, new ArrayList<>(), result); + return result; + } + + @SuppressWarnings("unchecked") + private void generateGroups( + List remaining, + List sizes, + List> current, + List>> result) { + // If no more sizes to process, we've found a valid grouping + if (sizes.isEmpty()) { + if (remaining.isEmpty()) { + result.add(new ArrayList<>(current)); + } + return; } - @SuppressWarnings("unchecked") - private void generateGroups(List remaining, List sizes, - List> current, - List>> result) { - // If no more sizes to process, we've found a valid grouping - if (sizes.isEmpty()) { - if (remaining.isEmpty()) { - result.add(new ArrayList<>(current)); - } - return; - } - - int currentSize = sizes.getFirst(); - List remainingSizes = sizes.subList(1, sizes.size()); - - // Generate combinations of the current size from remaining elements - MyListP27 remainingList = new MyListP27<>( - remaining.toArray((T[]) new Object[0]) - ); - List> combinations = remainingList.combinations(currentSize); - - for (MyListP26 combination : combinations) { - // Create a new remaining list excluding chosen elements - List newRemaining = new ArrayList<>(remaining); - for (int i = 0; i < combination.length(); i++) { - newRemaining.remove(combination.elementAt(1 + i)); - } - - // Add the current combination to groups and recurse - current.add(new MyListP27<>(combination.items)); - generateGroups(newRemaining, remainingSizes, current, result); - current.removeLast(); - } + int currentSize = sizes.getFirst(); + List remainingSizes = sizes.subList(1, sizes.size()); + + // Generate combinations of the current size from remaining elements + MyListP27 remainingList = new MyListP27<>(remaining.toArray((T[]) new Object[0])); + List> combinations = remainingList.combinations(currentSize); + + for (MyListP26 combination : combinations) { + // Create a new remaining list excluding chosen elements + List newRemaining = new ArrayList<>(remaining); + for (int i = 0; i < combination.length(); i++) { + newRemaining.remove(combination.elementAt(1 + i)); + } + + // Add the current combination to groups and recurse + current.add(new MyListP27<>(combination.items)); + generateGroups(newRemaining, remainingSizes, current, result); + current.removeLast(); } + } } diff --git a/src/main/java/org/nintynine/problems/MyListP28.java b/src/main/java/org/nintynine/problems/MyListP28.java index 6d9a916..3b5952a 100644 --- a/src/main/java/org/nintynine/problems/MyListP28.java +++ b/src/main/java/org/nintynine/problems/MyListP28.java @@ -12,102 +12,101 @@ */ public class MyListP28 extends MyListP27> { + @SafeVarargs + public MyListP28(T... elements) { + super(); + this.items = createItemsArray(elements); + } - @SafeVarargs - public MyListP28(T... elements) { - super(); - this.items = createItemsArray(elements); + @SuppressWarnings("unchecked") + private MyListP28(T[] elements, boolean isSublist) { + super(); + if (isSublist && elements.length == 1) { + // Base case: single element sublist + this.items = (MyListP28[]) new MyListP28[1]; + // Store the single element as a leaf node + this.items[0] = + new MyListP28<>() { + @Override + public String toString() { + return elements[0].toString(); + } + }; } + } - @SuppressWarnings("unchecked") - private MyListP28(T[] elements, boolean isSublist) { - super(); - if (isSublist && elements.length == 1) { - // Base case: single element sublist - this.items = (MyListP28[]) new MyListP28[1]; - // Store the single element as a leaf node - this.items[0] = new MyListP28<>() { - @Override - public String toString() { - return elements[0].toString(); - } - }; - } - } + /** + * Creates a list of lists from the given sublists. + * + * @param sublists array of sublists to initialize with + * @param the type of elements in the sublists + * @return new MyListP28 containing the sublists + */ + @SafeVarargs + public static MyListP28 of(MyListP28... sublists) { + MyListP28 result = new MyListP28<>(); + result.items = sublists; + return result; + } - /** - * Creates a list of lists from the given sublists. - * - * @param sublists array of sublists to initialize with - * @param the type of elements in the sublists - * @return new MyListP28 containing the sublists - */ - @SafeVarargs - public static MyListP28 of(MyListP28... sublists) { - MyListP28 result = new MyListP28<>(); - result.items = sublists; - return result; + @SuppressWarnings("unchecked") + private MyListP28[] createItemsArray(T[] elements) { + MyListP28[] result = (MyListP28[]) new MyListP28[elements.length]; + for (int i = 0; i < elements.length; i++) { + T[] singleElement = (T[]) new Object[] {elements[i]}; + result[i] = new MyListP28<>(singleElement, true); } + return result; + } - @SuppressWarnings("unchecked") - private MyListP28[] createItemsArray(T[] elements) { - MyListP28[] result = (MyListP28[]) new MyListP28[elements.length]; - for (int i = 0; i < elements.length; i++) { - T[] singleElement = (T[]) new Object[]{elements[i]}; - result[i] = new MyListP28<>(singleElement, true); - } - return result; - } + /** + * Sorts sublists by their length. + * + * @return new list with sublists sorted by length + */ + public MyListP28 lsort() { + MyListP28[] sorted = Arrays.copyOf(items, items.length); + Arrays.sort(sorted, Comparator.comparingInt(sublist -> Math.toIntExact(sublist.length()))); + return new MyListP28().withItems(sorted); + } - /** - * Sorts sublists by their length. - * - * @return new list with sublists sorted by length - */ - public MyListP28 lsort() { - MyListP28[] sorted = Arrays.copyOf(items, items.length); - Arrays.sort(sorted, Comparator.comparingInt(sublist -> Math.toIntExact(sublist.length()))); - return new MyListP28().withItems(sorted); + /** + * Sorts sublists by frequency of their lengths. Lists with rare lengths appear first. + * + * @return new list with sublists sorted by length frequency + */ + public MyListP28 lfsort() { + // Count frequency of each length + Map lengthFreq = new HashMap<>(); + for (MyListP28 sublist : items) { + lengthFreq.merge(Math.toIntExact(sublist.length()), 1, Integer::sum); } - /** - * Sorts sublists by frequency of their lengths. - * Lists with rare lengths appear first. - * - * @return new list with sublists sorted by length frequency - */ - public MyListP28 lfsort() { - // Count frequency of each length - Map lengthFreq = new HashMap<>(); - for (MyListP28 sublist : items) { - lengthFreq.merge(Math.toIntExact(sublist.length()), 1, Integer::sum); - } - - MyListP28[] sorted = Arrays.copyOf(items, items.length); - Arrays.sort(sorted, (a, b) -> { - int freqComp = lengthFreq.get(Math.toIntExact(a.length())) - .compareTo(lengthFreq.get(Math.toIntExact(b.length()))); - return Math.toIntExact(freqComp != 0 ? freqComp : a.length() - b.length()); + MyListP28[] sorted = Arrays.copyOf(items, items.length); + Arrays.sort( + sorted, + (a, b) -> { + int freqComp = + lengthFreq + .get(Math.toIntExact(a.length())) + .compareTo(lengthFreq.get(Math.toIntExact(b.length()))); + return Math.toIntExact(freqComp != 0 ? freqComp : a.length() - b.length()); }); - return new MyListP28().withItems(sorted); - } + return new MyListP28().withItems(sorted); + } - /** - * Helper method to set items directly. - */ - private MyListP28 withItems(MyListP28[] items) { - this.items = items; - return this; - } + /** Helper method to set items directly. */ + private MyListP28 withItems(MyListP28[] items) { + this.items = items; + return this; + } - @Override - public String toString() { - if (!items.getClass().getComponentType().equals(MyListP28.class)) { - return Arrays.toString(items); - } - return Arrays.toString(Arrays.stream(items) - .map(MyListP28::toString) - .toArray()); + @Override + public String toString() { + if (!items.getClass().getComponentType().equals(MyListP28.class)) { + return Arrays.toString(items); } + return Arrays.toString(Arrays.stream(items).map(MyListP28::toString).toArray()); + } } diff --git a/src/main/java/org/nintynine/problems/TruthP46.java b/src/main/java/org/nintynine/problems/TruthP46.java index 092b5ca..c514329 100644 --- a/src/main/java/org/nintynine/problems/TruthP46.java +++ b/src/main/java/org/nintynine/problems/TruthP46.java @@ -1,218 +1,197 @@ package org.nintynine.problems; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.function.BiFunction; -/** - * P46: Truth tables for logical expressions. - */ +/** P46: Truth tables for logical expressions. */ public class TruthP46 { - /** - * Generates a truth table for a given logical expression. - * - * @param expression the logical expression in prefix notation - * @return list of truth table rows - * @throws IllegalArgumentException if the expression is invalid - */ - public static List table(String expression) { - ExpressionNode root = parseExpression(expression); - List rows = new ArrayList<>(); - - // Generate all possible combinations of A and B - for (boolean a : new boolean[]{false, true}) { - for (boolean b : new boolean[]{false, true}) { - boolean result = root.evaluate(a, b); - rows.add(new TruthTableRow(a, b, result)); - } - } + /** + * Generates a truth table for a given logical expression. + * + * @param expression the logical expression in prefix notation + * @return list of truth table rows + * @throws IllegalArgumentException if the expression is invalid + */ + public static List table(String expression) { + ExpressionNode root = parseExpression(expression); + List rows = new ArrayList<>(); + + // Generate all possible combinations of A and B + for (boolean a : new boolean[] {false, true}) { + for (boolean b : new boolean[] {false, true}) { + boolean result = root.evaluate(a, b); + rows.add(new TruthTableRow(a, b, result)); + } + } - return rows; + return rows; + } + + /** + * Parses a logical expression in prefix notation. + * + * @param expression the expression to parse + * @return root node of the expression tree + * @throws IllegalArgumentException if the expression is invalid + */ + private static ExpressionNode parseExpression(String expression) { + expression = expression.trim(); + + // Handle single variables + if (expression.length() == 1) { + char var = expression.charAt(0); + if (var == 'A' || var == 'B') { + return new VariableNode(var); + } + throw new IllegalArgumentException("Invalid variable: " + var + " (must be A or B)"); } - /** - * Parses a logical expression in prefix notation. - * - * @param expression the expression to parse - * @return root node of the expression tree - * @throws IllegalArgumentException if the expression is invalid - */ - private static ExpressionNode parseExpression(String expression) { - expression = expression.trim(); - - // Handle single variables - if (expression.length() == 1) { - char var = expression.charAt(0); - if (var == 'A' || var == 'B') { - return new VariableNode(var); - } - throw new IllegalArgumentException("Invalid variable: " + var + " (must be A or B)"); - } + // Handle operations + if (expression.startsWith("(") && expression.endsWith(")")) { + // Remove outer parentheses + expression = expression.substring(1, expression.length() - 1).trim(); + + // Split into operator and operands + int firstSpace = expression.indexOf(' '); + if (firstSpace == -1) { + throw new IllegalArgumentException( + "Invalid expression format : " + + expression + + " (missing space between operator and operands)"); + } + + String operator = expression.substring(0, firstSpace); + String remainingExpr = expression.substring(firstSpace + 1).trim(); + + // Find the two operands + String[] operands = splitOperands(remainingExpr); + if (operands.length != 2) { + throw new IllegalArgumentException("Expected two operands"); + } + + LogicalOp op = + LogicalOp.fromString(operator) + .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + operator)); + + return new OperationNode(op, parseExpression(operands[0]), parseExpression(operands[1])); + } - // Handle operations - if (expression.startsWith("(") && expression.endsWith(")")) { - // Remove outer parentheses - expression = expression.substring(1, expression.length() - 1).trim(); - - // Split into operator and operands - int firstSpace = expression.indexOf(' '); - if (firstSpace == -1) { - throw new IllegalArgumentException("Invalid expression format : " + expression + " (missing space between operator and operands)"); - } - - String operator = expression.substring(0, firstSpace); - String remainingExpr = expression.substring(firstSpace + 1).trim(); - - // Find the two operands - String[] operands = splitOperands(remainingExpr); - if (operands.length != 2) { - throw new IllegalArgumentException("Expected two operands"); - } - - LogicalOp op = LogicalOp.fromString(operator) - .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + operator)); - - return new OperationNode( - op, - parseExpression(operands[0]), - parseExpression(operands[1]) - ); - } + throw new IllegalArgumentException("Invalid expression format"); + } - throw new IllegalArgumentException("Invalid expression format"); - } + /** Splits an expression into operands, handling nested parentheses. */ + private static String[] splitOperands(String expr) { + List operands = new ArrayList<>(); + int parenthesesCount = 0; + StringBuilder current = new StringBuilder(); - /** - * Splits an expression into operands, handling nested parentheses. - */ - private static String[] splitOperands(String expr) { - List operands = new ArrayList<>(); - int parenthesesCount = 0; - StringBuilder current = new StringBuilder(); - - for (char c : expr.toCharArray()) { - if (c == '(') { - parenthesesCount++; - } else if (c == ')') { - parenthesesCount--; - } - - if (c == ' ' && parenthesesCount == 0) { - if (!current.isEmpty()) { - operands.add(current.toString().trim()); - current = new StringBuilder(); - } - } else { - current.append(c); - } - } + for (char c : expr.toCharArray()) { + if (c == '(') { + parenthesesCount++; + } else if (c == ')') { + parenthesesCount--; + } + if (c == ' ' && parenthesesCount == 0) { if (!current.isEmpty()) { - operands.add(current.toString().trim()); + operands.add(current.toString().trim()); + current = new StringBuilder(); } - - return operands.toArray(new String[0]); + } else { + current.append(c); + } } - /** - * Formats a truth table as a string. - */ - public static String formatTruthTable(List table) { - StringBuilder sb = new StringBuilder(); - sb.append(" A B Result\n"); - sb.append("-------------------\n"); - table.forEach(row -> sb.append(row).append('\n')); - return sb.toString(); + if (!current.isEmpty()) { + operands.add(current.toString().trim()); } - /** - * Represents a logical operation that can be performed on boolean values. - */ - public enum LogicalOp { - AND("and", (a, b) -> a && b), - OR("or", (a, b) -> a || b), - NAND("nand", (a, b) -> !(a && b)), - NOR("nor", (a, b) -> !(a || b)), - XOR("xor", (a, b) -> a ^ b), - IMPL("impl", (a, b) -> !a || b), - EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()); - - @SuppressWarnings("PMD.UnusedPrivateField") - private final String symbol; - private final BiFunction operation; - - LogicalOp(String symbol, BiFunction operation) { - this.symbol = symbol; - this.operation = operation; - } - - public static Optional fromString(String symbol) { - return Arrays.stream(values()) - .filter(op -> op.symbol.equals(symbol)) - .findFirst(); - } + return operands.toArray(new String[0]); + } + + /** Formats a truth table as a string. */ + public static String formatTruthTable(List table) { + StringBuilder sb = new StringBuilder(); + sb.append(" A B Result\n"); + sb.append("-------------------\n"); + table.forEach(row -> sb.append(row).append('\n')); + return sb.toString(); + } + + /** Represents a logical operation that can be performed on boolean values. */ + public enum LogicalOp { + AND("and", (a, b) -> a && b), + OR("or", (a, b) -> a || b), + NAND("nand", (a, b) -> !(a && b)), + NOR("nor", (a, b) -> !(a || b)), + XOR("xor", (a, b) -> a ^ b), + IMPL("impl", (a, b) -> !a || b), + EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()); + + @SuppressWarnings("PMD.UnusedPrivateField") + private final String symbol; + + private final BiFunction operation; + + LogicalOp(String symbol, BiFunction operation) { + this.symbol = symbol; + this.operation = operation; + } - public boolean apply(boolean a, boolean b) { - return operation.apply(a, b); - } + public static Optional fromString(String symbol) { + return Arrays.stream(values()).filter(op -> op.symbol.equals(symbol)).findFirst(); } - /** - * Represents a logical expression node in the expression tree. - */ - private static abstract class ExpressionNode { - abstract boolean evaluate(boolean a, boolean b); + public boolean apply(boolean a, boolean b) { + return operation.apply(a, b); } + } - /** - * Represents a variable (A or B) in the expression. - */ - private static class VariableNode extends ExpressionNode { - private final char variable; + /** Represents a logical expression node in the expression tree. */ + private abstract static class ExpressionNode { + abstract boolean evaluate(boolean a, boolean b); + } - public VariableNode(char variable) { - this.variable = variable; - } + /** Represents a variable (A or B) in the expression. */ + private static class VariableNode extends ExpressionNode { + private final char variable; - @Override - boolean evaluate(boolean a, boolean b) { - return variable == 'A' ? a : b; - } + public VariableNode(char variable) { + this.variable = variable; } - /** - * Represents an operation node with two operands. - */ - private static class OperationNode extends ExpressionNode { - private final LogicalOp operator; - private final ExpressionNode left; - private final ExpressionNode right; - - public OperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { - this.operator = operator; - this.left = left; - this.right = right; - } + @Override + boolean evaluate(boolean a, boolean b) { + return variable == 'A' ? a : b; + } + } + + /** Represents an operation node with two operands. */ + private static class OperationNode extends ExpressionNode { + private final LogicalOp operator; + private final ExpressionNode left; + private final ExpressionNode right; + + public OperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { + this.operator = operator; + this.left = left; + this.right = right; + } - @Override - boolean evaluate(boolean a, boolean b) { - return operator.apply( - left.evaluate(a, b), - right.evaluate(a, b) - ); - } + @Override + boolean evaluate(boolean a, boolean b) { + return operator.apply(left.evaluate(a, b), right.evaluate(a, b)); } + } - /** - * Represents a truth table row. - */ - public record TruthTableRow(boolean a, boolean b, boolean result) { - @Override - public String toString() { - return String.format("%5s %5s %7s", a, b, result); - } + /** Represents a truth table row. */ + public record TruthTableRow(boolean a, boolean b, boolean result) { + @Override + public String toString() { + return String.format("%5s %5s %7s", a, b, result); } + } } diff --git a/src/main/java/org/nintynine/problems/TruthP47.java b/src/main/java/org/nintynine/problems/TruthP47.java index c31b661..fdfec57 100644 --- a/src/main/java/org/nintynine/problems/TruthP47.java +++ b/src/main/java/org/nintynine/problems/TruthP47.java @@ -7,285 +7,255 @@ import java.util.function.BiFunction; import java.util.function.UnaryOperator; -/** - * P47: Truth tables for logical expressions (infix notation). - */ +/** P47: Truth tables for logical expressions (infix notation). */ public class TruthP47 { - /** - * Generates a truth table for a given logical expression in infix notation. - * - * @param expression the logical expression - * @return list of truth table rows - * @throws IllegalArgumentException if expression is invalid - */ - public static List table(String expression) { - ExpressionNode root = parseInfixExpression(expression); - List rows = new ArrayList<>(); - - // Generate all possible combinations of A and B - for (boolean a : new boolean[]{false, true}) { - for (boolean b : new boolean[]{false, true}) { - boolean result = root.evaluate(a, b); - rows.add(new TruthTableRow(a, b, result)); - } - } - - return rows; + /** + * Generates a truth table for a given logical expression in infix notation. + * + * @param expression the logical expression + * @return list of truth table rows + * @throws IllegalArgumentException if expression is invalid + */ + public static List table(String expression) { + ExpressionNode root = parseInfixExpression(expression); + List rows = new ArrayList<>(); + + // Generate all possible combinations of A and B + for (boolean a : new boolean[] {false, true}) { + for (boolean b : new boolean[] {false, true}) { + boolean result = root.evaluate(a, b); + rows.add(new TruthTableRow(a, b, result)); + } } - /** - * Parses an infix expression and builds an expression tree. - */ - private static ExpressionNode parseInfixExpression(String expression) { - expression = expression.trim(); - - // Handle single variables - if (expression.length() == 1) { - char var = expression.charAt(0); - if (var == 'A' || var == 'B') { - return new VariableNode(var); - } - throw new IllegalArgumentException("Invalid variable: " + var); - } + return rows; + } - // Check if this is a parenthesized single variable - illegal - if (expression.startsWith("(") && expression.endsWith(")")) { - String inner = expression.substring(1, expression.length() - 1).trim(); - if (inner.length() == 1 && (inner.equals("A") || inner.equals("B"))) { - throw new IllegalArgumentException( - "Single variables should not be parenthesized: " + expression); - } - } + /** Parses an infix expression and builds an expression tree. */ + private static ExpressionNode parseInfixExpression(String expression) { + expression = expression.trim(); - // Rest of the validation and parsing... - // Require parentheses for all non-single-variable expressions - if (!expression.startsWith("(") || !expression.endsWith(")")) { - throw new IllegalArgumentException( - "Expression must be fully parenthesized: " + expression); - } + // Handle single variables + if (expression.length() == 1) { + char var = expression.charAt(0); + if (var == 'A' || var == 'B') { + return new VariableNode(var); + } + throw new IllegalArgumentException("Invalid variable: " + var); + } - // Remove outer parentheses - expression = expression.substring(1, expression.length() - 1).trim(); - - // Find the main operator - int operatorIndex = findMainOperator(expression); - if (operatorIndex == -1) { - // Might be a NOT expression or nested expression - if (expression.startsWith("not ")) { - String operand = expression.substring(4).trim(); - return new UnaryOperationNode( - LogicalOp.NOT, - parseInfixExpression(operand) - ); - } - return parseInfixExpression(expression); - } + // Check if this is a parenthesized single variable - illegal + if (expression.startsWith("(") && expression.endsWith(")")) { + String inner = expression.substring(1, expression.length() - 1).trim(); + if (inner.length() == 1 && (inner.equals("A") || inner.equals("B"))) { + throw new IllegalArgumentException( + "Single variables should not be parenthesized: " + expression); + } + } - // Split into operator and operands - String operator = findOperatorString(expression, operatorIndex); - String leftExpr = expression.substring(0, operatorIndex).trim(); - String rightExpr = expression.substring(operatorIndex + operator.length()).trim(); - - LogicalOp op = LogicalOp.fromString(operator) - .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + operator)); - - if (op.isUnary()) { - return new UnaryOperationNode( - op, - parseInfixExpression(rightExpr) - ); - } else { - return new BinaryOperationNode( - op, - parseInfixExpression(leftExpr), - parseInfixExpression(rightExpr) - ); - } + // Rest of the validation and parsing... + // Require parentheses for all non-single-variable expressions + if (!expression.startsWith("(") || !expression.endsWith(")")) { + throw new IllegalArgumentException("Expression must be fully parenthesized: " + expression); + } - // Rest of the method remains the same... + // Remove outer parentheses + expression = expression.substring(1, expression.length() - 1).trim(); + + // Find the main operator + int operatorIndex = findMainOperator(expression); + if (operatorIndex == -1) { + // Might be a NOT expression or nested expression + if (expression.startsWith("not ")) { + String operand = expression.substring(4).trim(); + return new UnaryOperationNode(LogicalOp.NOT, parseInfixExpression(operand)); + } + return parseInfixExpression(expression); } - private static int findMainOperator(String expression) { - int parenthesesCount = 0; - int lastOperatorIndex = -1; - - for (int i = 0; i < expression.length(); i++) { - char c = expression.charAt(i); - - if (c == '(') { - parenthesesCount++; - } else if (c == ')') { - parenthesesCount--; - } else if (parenthesesCount == 0) { - // Try to match any operator starting at current position - String remainingExpr = expression.substring(i); - for (LogicalOp op : LogicalOp.values()) { - if (remainingExpr.startsWith(op.symbol) && - (i == 0 || Character.isWhitespace(expression.charAt(i - 1)))) { - lastOperatorIndex = i; - break; - } - } - } - } + // Split into operator and operands + String operator = findOperatorString(expression, operatorIndex); + String leftExpr = expression.substring(0, operatorIndex).trim(); + String rightExpr = expression.substring(operatorIndex + operator.length()).trim(); + + LogicalOp op = + LogicalOp.fromString(operator) + .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + operator)); - return lastOperatorIndex; + if (op.isUnary()) { + return new UnaryOperationNode(op, parseInfixExpression(rightExpr)); + } else { + return new BinaryOperationNode( + op, parseInfixExpression(leftExpr), parseInfixExpression(rightExpr)); } - /** - * Extracts the operator string from an expression. - */ - private static String findOperatorString(String expression, int startIndex) { + // Rest of the method remains the same... + } + + private static int findMainOperator(String expression) { + int parenthesesCount = 0; + int lastOperatorIndex = -1; + + for (int i = 0; i < expression.length(); i++) { + char c = expression.charAt(i); + + if (c == '(') { + parenthesesCount++; + } else if (c == ')') { + parenthesesCount--; + } else if (parenthesesCount == 0) { + // Try to match any operator starting at current position + String remainingExpr = expression.substring(i); for (LogicalOp op : LogicalOp.values()) { - if (expression.substring(startIndex).startsWith(op.symbol)) { - return op.symbol; - } + if (remainingExpr.startsWith(op.symbol) + && (i == 0 || Character.isWhitespace(expression.charAt(i - 1)))) { + lastOperatorIndex = i; + break; + } } - throw new IllegalArgumentException("No valid operator found at position " + startIndex); + } } - /** - * Formats a truth table as a string. - */ - public static String formatTruthTable(List table) { - StringBuilder sb = new StringBuilder(); - sb.append(" A B Result\n"); - sb.append("-------------------\n"); - table.forEach(row -> sb.append(row).append('\n')); - return sb.toString(); - } - - /** - * Represents a logical operation that can be performed on boolean values. - */ - public enum LogicalOp { - AND("and", (a, b) -> a && b), - OR("or", (a, b) -> a || b), - NAND("nand", (a, b) -> !(a && b)), - NOR("nor", (a, b) -> !(a || b)), - XOR("xor", (a, b) -> a ^ b), - IMPL("impl", (a, b) -> !a || b), - EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()), - NOT("not", a -> !a, true); - - @SuppressWarnings("PMD.UnusedPrivateField") - private final String symbol; - private final BiFunction binaryOp; - private final UnaryOperator unaryOp; - private final boolean isUnary; - - LogicalOp(String symbol, BiFunction operation) { - this(symbol, operation, null, false); - } + return lastOperatorIndex; + } - LogicalOp(String symbol, UnaryOperator operation, boolean isUnary) { - this(symbol, null, operation, isUnary); - } + /** Extracts the operator string from an expression. */ + private static String findOperatorString(String expression, int startIndex) { + for (LogicalOp op : LogicalOp.values()) { + if (expression.substring(startIndex).startsWith(op.symbol)) { + return op.symbol; + } + } + throw new IllegalArgumentException("No valid operator found at position " + startIndex); + } + + /** Formats a truth table as a string. */ + public static String formatTruthTable(List table) { + StringBuilder sb = new StringBuilder(); + sb.append(" A B Result\n"); + sb.append("-------------------\n"); + table.forEach(row -> sb.append(row).append('\n')); + return sb.toString(); + } + + /** Represents a logical operation that can be performed on boolean values. */ + public enum LogicalOp { + AND("and", (a, b) -> a && b), + OR("or", (a, b) -> a || b), + NAND("nand", (a, b) -> !(a && b)), + NOR("nor", (a, b) -> !(a || b)), + XOR("xor", (a, b) -> a ^ b), + IMPL("impl", (a, b) -> !a || b), + EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()), + NOT("not", a -> !a, true); + + @SuppressWarnings("PMD.UnusedPrivateField") + private final String symbol; + + private final BiFunction binaryOp; + private final UnaryOperator unaryOp; + private final boolean isUnary; + + LogicalOp(String symbol, BiFunction operation) { + this(symbol, operation, null, false); + } - LogicalOp(String symbol, BiFunction binaryOp, - UnaryOperator unaryOp, boolean isUnary) { - this.symbol = symbol; - this.binaryOp = binaryOp; - this.unaryOp = unaryOp; - this.isUnary = isUnary; - } + LogicalOp(String symbol, UnaryOperator operation, boolean isUnary) { + this(symbol, null, operation, isUnary); + } - public static Optional fromString(String symbol) { - return Arrays.stream(values()) - .filter(op -> op.symbol.equals(symbol)) - .findFirst(); - } + LogicalOp( + String symbol, + BiFunction binaryOp, + UnaryOperator unaryOp, + boolean isUnary) { + this.symbol = symbol; + this.binaryOp = binaryOp; + this.unaryOp = unaryOp; + this.isUnary = isUnary; + } - public boolean apply(boolean a, boolean b) { - if (isUnary) { - throw new IllegalStateException("Cannot apply binary operation to unary operator"); - } - return binaryOp.apply(a, b); - } + public static Optional fromString(String symbol) { + return Arrays.stream(values()).filter(op -> op.symbol.equals(symbol)).findFirst(); + } - public boolean apply(boolean a) { - if (!isUnary) { - throw new IllegalStateException("Cannot apply unary operation to binary operator"); - } - return unaryOp.apply(a); - } + public boolean apply(boolean a, boolean b) { + if (isUnary) { + throw new IllegalStateException("Cannot apply binary operation to unary operator"); + } + return binaryOp.apply(a, b); + } - public boolean isUnary() { - return isUnary; - } + public boolean apply(boolean a) { + if (!isUnary) { + throw new IllegalStateException("Cannot apply unary operation to binary operator"); + } + return unaryOp.apply(a); } - /** - * Represents a node in the expression tree. - */ - private static abstract class ExpressionNode { - abstract boolean evaluate(boolean a, boolean b); + public boolean isUnary() { + return isUnary; } + } - /** - * Represents a variable (A or B) in the expression. - */ - private static class VariableNode extends ExpressionNode { - private final char variable; + /** Represents a node in the expression tree. */ + private abstract static class ExpressionNode { + abstract boolean evaluate(boolean a, boolean b); + } - public VariableNode(char variable) { - this.variable = variable; - } + /** Represents a variable (A or B) in the expression. */ + private static class VariableNode extends ExpressionNode { + private final char variable; - @Override - boolean evaluate(boolean a, boolean b) { - return variable == 'A' ? a : b; - } + public VariableNode(char variable) { + this.variable = variable; } - /** - * Represents a binary operation node. - */ - private static class BinaryOperationNode extends ExpressionNode { - private final LogicalOp operator; - private final ExpressionNode left; - private final ExpressionNode right; - - public BinaryOperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { - this.operator = operator; - this.left = left; - this.right = right; - } + @Override + boolean evaluate(boolean a, boolean b) { + return variable == 'A' ? a : b; + } + } + + /** Represents a binary operation node. */ + private static class BinaryOperationNode extends ExpressionNode { + private final LogicalOp operator; + private final ExpressionNode left; + private final ExpressionNode right; + + public BinaryOperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { + this.operator = operator; + this.left = left; + this.right = right; + } - @Override - boolean evaluate(boolean a, boolean b) { - return operator.apply( - left.evaluate(a, b), - right.evaluate(a, b) - ); - } + @Override + boolean evaluate(boolean a, boolean b) { + return operator.apply(left.evaluate(a, b), right.evaluate(a, b)); } + } - /** - * Represents a unary operation node (NOT). - */ - private static class UnaryOperationNode extends ExpressionNode { - private final LogicalOp operator; - private final ExpressionNode operand; + /** Represents a unary operation node (NOT). */ + private static class UnaryOperationNode extends ExpressionNode { + private final LogicalOp operator; + private final ExpressionNode operand; - public UnaryOperationNode(LogicalOp operator, ExpressionNode operand) { - this.operator = operator; - this.operand = operand; - } + public UnaryOperationNode(LogicalOp operator, ExpressionNode operand) { + this.operator = operator; + this.operand = operand; + } - @Override - boolean evaluate(boolean a, boolean b) { - return operator.apply(operand.evaluate(a, b)); - } + @Override + boolean evaluate(boolean a, boolean b) { + return operator.apply(operand.evaluate(a, b)); } + } - /** - * Represents a truth table row. - */ - public record TruthTableRow(boolean a, boolean b, boolean result) { - @Override - public String toString() { - return String.format("%5s %5s %7s", a, b, result); - } + /** Represents a truth table row. */ + public record TruthTableRow(boolean a, boolean b, boolean result) { + @Override + public String toString() { + return String.format("%5s %5s %7s", a, b, result); } + } } diff --git a/src/main/java/org/nintynine/problems/TruthP48.java b/src/main/java/org/nintynine/problems/TruthP48.java index 9c384b6..3ddf3f3 100644 --- a/src/main/java/org/nintynine/problems/TruthP48.java +++ b/src/main/java/org/nintynine/problems/TruthP48.java @@ -1,6 +1,5 @@ package org.nintynine.problems; - import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -9,248 +8,243 @@ import java.util.function.UnaryOperator; public class TruthP48 { - public static void table(List variables, String expression) { - ExpressionNode expr = parse(expression); - int columnWidth = 8; // Width for each column to accommodate "false" and "true" + public static void table(List variables, String expression) { + ExpressionNode expr = parse(expression); + int columnWidth = 8; // Width for each column to accommodate "false" and "true" - // Print header - for (String var : variables) { - System.out.printf("%-" + columnWidth + "s", var); - } - System.out.println("Result"); - - // Print separator line - System.out.println("-".repeat(variables.size() * columnWidth + 6)); - - // Generate all possible combinations - int combinations = 1 << variables.size(); - for (int i = 0; i < combinations; i++) { - Map values = new HashMap<>(); - for (int j = 0; j < variables.size(); j++) { - boolean value = (i & (1 << j)) != 0; - values.put(variables.get(j), value); - } - - // Print values with proper spacing - for (String var : variables) { - System.out.printf("%-" + columnWidth + "s", values.get(var).toString()); - } - - // Evaluate and print result - boolean result = expr.evaluate(values); - System.out.printf("%s%n", result); - } + // Print header + for (String var : variables) { + System.out.printf("%-" + columnWidth + "s", var); } + System.out.println("Result"); + + // Print separator line + System.out.println("-".repeat(variables.size() * columnWidth + 6)); + + // Generate all possible combinations + int combinations = 1 << variables.size(); + for (int i = 0; i < combinations; i++) { + Map values = new HashMap<>(); + for (int j = 0; j < variables.size(); j++) { + boolean value = (i & (1 << j)) != 0; + values.put(variables.get(j), value); + } + + // Print values with proper spacing + for (String var : variables) { + System.out.printf("%-" + columnWidth + "s", values.get(var).toString()); + } + + // Evaluate and print result + boolean result = expr.evaluate(values); + System.out.printf("%s%n", result); + } + } - private static int findMainOperator(String expression) { - int parenthesesCount = 0; - int position = 0; - StringBuilder currentToken = new StringBuilder(); - - for (int i = 0; i < expression.length(); i++) { - char c = expression.charAt(i); - - if (c == '(') { - parenthesesCount++; - continue; - } else if (c == ')') { - parenthesesCount--; - continue; - } - - if (c == ' ') { - if (parenthesesCount == 0 && !currentToken.isEmpty()) { - String token = currentToken.toString().trim(); - if (Arrays.stream(LogicalOp.values()) - .anyMatch(op -> op.symbol.equals(token))) { - return position; - } - } - position++; - currentToken = new StringBuilder(); - continue; - } - - currentToken.append(c); - if (currentToken.length() == 1) { - position = i; - } - } + private static int findMainOperator(String expression) { + int parenthesesCount = 0; + int position = 0; + StringBuilder currentToken = new StringBuilder(); - // Check the last token + for (int i = 0; i < expression.length(); i++) { + char c = expression.charAt(i); + + if (c == '(') { + parenthesesCount++; + continue; + } else if (c == ')') { + parenthesesCount--; + continue; + } + + if (c == ' ') { if (parenthesesCount == 0 && !currentToken.isEmpty()) { - String token = currentToken.toString().trim(); - if (Arrays.stream(LogicalOp.values()) - .anyMatch(op -> op.symbol.equals(token))) { - return position; - } - } + String token = currentToken.toString().trim(); + if (Arrays.stream(LogicalOp.values()).anyMatch(op -> op.symbol.equals(token))) { + return position; + } + } + position++; + currentToken = new StringBuilder(); + continue; + } + + currentToken.append(c); + if (currentToken.length() == 1) { + position = i; + } + } - return -1; + // Check the last token + if (parenthesesCount == 0 && !currentToken.isEmpty()) { + String token = currentToken.toString().trim(); + if (Arrays.stream(LogicalOp.values()).anyMatch(op -> op.symbol.equals(token))) { + return position; + } } - private static ExpressionNode parse(String expression) { - expression = expression.trim(); - - // Handle outer parentheses - while (expression.startsWith("(") && expression.endsWith(")")) { - // Verify matching parentheses - int count = 0; - boolean valid = true; - for (int i = 0; i < expression.length(); i++) { - if (expression.charAt(i) == '(') count++; - if (expression.charAt(i) == ')') { - count--; - if (count == 0 && i != expression.length() - 1) { - valid = false; - break; - } - } - } - if (!valid || count != 0) break; - expression = expression.substring(1, expression.length() - 1).trim(); - } + return -1; + } + + private static ExpressionNode parse(String expression) { + expression = expression.trim(); + + // Handle outer parentheses + while (expression.startsWith("(") && expression.endsWith(")")) { + // Verify matching parentheses + int count = 0; + boolean valid = true; + for (int i = 0; i < expression.length(); i++) { + if (expression.charAt(i) == '(') count++; + if (expression.charAt(i) == ')') { + count--; + if (count == 0 && i != expression.length() - 1) { + valid = false; + break; + } + } + } + if (!valid || count != 0) break; + expression = expression.substring(1, expression.length() - 1).trim(); + } - // Handle single token - if (expression.split("\\s+").length == 1) { - try { - // It's a variable - return new VariableNode(expression); - } catch (NumberFormatException _) { - throw new IllegalArgumentException("Invalid expression: " + expression); - } - } + // Handle single token + if (expression.split("\\s+").length == 1) { + try { + // It's a variable + return new VariableNode(expression); + } catch (NumberFormatException _) { + throw new IllegalArgumentException("Invalid expression: " + expression); + } + } - // Unary operation (not) - String[] tokens = expression.split("\\s+"); - if (tokens[0].equals("not")) { - String remainingExpr = String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)); - return new UnaryOperationNode(LogicalOp.NOT, parse(remainingExpr)); - } + // Unary operation (not) + String[] tokens = expression.split("\\s+"); + if (tokens[0].equals("not")) { + String remainingExpr = String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)); + return new UnaryOperationNode(LogicalOp.NOT, parse(remainingExpr)); + } - // Find the main operator - int mainOpIndex = findMainOperator(expression); - if (mainOpIndex == -1) { - throw new IllegalArgumentException("Invalid expression: " + expression); - } + // Find the main operator + int mainOpIndex = findMainOperator(expression); + if (mainOpIndex == -1) { + throw new IllegalArgumentException("Invalid expression: " + expression); + } - String leftExpr = expression.substring(0, mainOpIndex).trim(); - String op = expression.substring(mainOpIndex, expression.indexOf(' ', mainOpIndex)).trim(); - String rightExpr = expression.substring(expression.indexOf(' ', mainOpIndex) + 1).trim(); + String leftExpr = expression.substring(0, mainOpIndex).trim(); + String op = expression.substring(mainOpIndex, expression.indexOf(' ', mainOpIndex)).trim(); + String rightExpr = expression.substring(expression.indexOf(' ', mainOpIndex) + 1).trim(); + LogicalOp operator = + Arrays.stream(LogicalOp.values()) + .filter(o -> o.symbol.equals(op)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + op)); - LogicalOp operator = Arrays.stream(LogicalOp.values()) - .filter(o -> o.symbol.equals(op)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Unknown operator: " + op)); + return new BinaryOperationNode(operator, parse(leftExpr), parse(rightExpr)); + } - return new BinaryOperationNode(operator, - parse(leftExpr), - parse(rightExpr)); - } + private enum LogicalOp { + AND("and", (a, b) -> a && b), + OR("or", (a, b) -> a || b), + NOT("not", a -> !a), + EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()); - private enum LogicalOp { - AND("and", (a, b) -> a && b), - OR("or", (a, b) -> a || b), - NOT("not", a -> !a), - EQU("equ", (a, b) -> a.booleanValue() == b.booleanValue()); - - @SuppressWarnings("PMD.UnusedPrivateField") - final String symbol; - final BinaryOperator binaryOp; - final UnaryOperator unaryOp; - - LogicalOp(String symbol, BinaryOperator op) { - this.symbol = symbol; - this.binaryOp = op; - this.unaryOp = null; - } + @SuppressWarnings("PMD.UnusedPrivateField") + final String symbol; - LogicalOp(String symbol, UnaryOperator op) { - this.symbol = symbol; - this.binaryOp = null; - this.unaryOp = op; - } + final BinaryOperator binaryOp; + final UnaryOperator unaryOp; - boolean apply(boolean a, boolean b) { - assert binaryOp != null; - return binaryOp.apply(a, b); - } + LogicalOp(String symbol, BinaryOperator op) { + this.symbol = symbol; + this.binaryOp = op; + this.unaryOp = null; + } - boolean apply(boolean a) { - assert unaryOp != null; - return unaryOp.apply(a); - } + LogicalOp(String symbol, UnaryOperator op) { + this.symbol = symbol; + this.binaryOp = null; + this.unaryOp = op; } - private static abstract class ExpressionNode { - abstract boolean evaluate(Map variables); + boolean apply(boolean a, boolean b) { + assert binaryOp != null; + return binaryOp.apply(a, b); + } - public abstract String toString(); + boolean apply(boolean a) { + assert unaryOp != null; + return unaryOp.apply(a); } + } - private static class BinaryOperationNode extends ExpressionNode { - private final LogicalOp operator; - private final ExpressionNode left; - private final ExpressionNode right; + private abstract static class ExpressionNode { + abstract boolean evaluate(Map variables); - public BinaryOperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { - this.operator = operator; - this.left = left; - this.right = right; - } + public abstract String toString(); + } - @Override - boolean evaluate(Map variables) { - boolean leftResult = left.evaluate(variables); - boolean rightResult = right.evaluate(variables); - return operator.apply(leftResult, rightResult); - } + private static class BinaryOperationNode extends ExpressionNode { + private final LogicalOp operator; + private final ExpressionNode left; + private final ExpressionNode right; - @Override - public String toString() { - return String.format("(%s %s %s)", left, operator, right); - } + public BinaryOperationNode(LogicalOp operator, ExpressionNode left, ExpressionNode right) { + this.operator = operator; + this.left = left; + this.right = right; } - private static class UnaryOperationNode extends ExpressionNode { - private final LogicalOp operator; - private final ExpressionNode operand; + @Override + boolean evaluate(Map variables) { + boolean leftResult = left.evaluate(variables); + boolean rightResult = right.evaluate(variables); + return operator.apply(leftResult, rightResult); + } - public UnaryOperationNode(LogicalOp operator, ExpressionNode operand) { - this.operator = operator; - this.operand = operand; - } + @Override + public String toString() { + return String.format("(%s %s %s)", left, operator, right); + } + } - @Override - boolean evaluate(Map variables) { - boolean operandResult = operand.evaluate(variables); - return operator.apply(operandResult); - } + private static class UnaryOperationNode extends ExpressionNode { + private final LogicalOp operator; + private final ExpressionNode operand; - @Override - public String toString() { - return String.format("(%s %s)", operator, operand); - } + public UnaryOperationNode(LogicalOp operator, ExpressionNode operand) { + this.operator = operator; + this.operand = operand; } - private static class VariableNode extends ExpressionNode { - private final String name; + @Override + boolean evaluate(Map variables) { + boolean operandResult = operand.evaluate(variables); + return operator.apply(operandResult); + } - public VariableNode(String name) { - this.name = name; - } + @Override + public String toString() { + return String.format("(%s %s)", operator, operand); + } + } - @Override - boolean evaluate(Map variables) { - return variables.get(name); - } + private static class VariableNode extends ExpressionNode { + private final String name; - @Override - public String toString() { - return name; - } + public VariableNode(String name) { + this.name = name; } + @Override + boolean evaluate(Map variables) { + return variables.get(name); + } + @Override + public String toString() { + return name; + } + } } diff --git a/src/main/java/org/nintynine/problems/TruthP55.java b/src/main/java/org/nintynine/problems/TruthP55.java index ab68d2d..8257c1c 100644 --- a/src/main/java/org/nintynine/problems/TruthP55.java +++ b/src/main/java/org/nintynine/problems/TruthP55.java @@ -7,123 +7,121 @@ @SuppressWarnings("ClassEscapesDefinedScope") public class TruthP55 { - private TruthP55() {} - static class Node { - String value; - Node left; - Node right; - - Node(String value, Node left, Node right) { - this.value = value; - this.left = left; - this.right = right; - } + private TruthP55() {} - @Override - public String toString() { - if (left == null && right == null) { - return "(X NIL NIL)"; - } - return String.format("(X %s %s)", - left == null ? "NIL" : left.toString(), - right == null ? "NIL" : right.toString()); - } + static class Node { + String value; + Node left; + Node right; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Node node)) return false; - return Objects.equals(value, node.value) && - Objects.equals(left, node.left) && - Objects.equals(right, node.right); - } + Node(String value, Node left, Node right) { + this.value = value; + this.left = left; + this.right = right; + } - @Override - public int hashCode() { - return Objects.hash(value, left, right); - } + @Override + public String toString() { + if (left == null && right == null) { + return "(X NIL NIL)"; + } + return String.format( + "(X %s %s)", + left == null ? "NIL" : left.toString(), right == null ? "NIL" : right.toString()); } - /** - * Generates all possible completely balanced binary trees with n nodes - * @param n number of nodes - * @return list of all possible balanced trees - */ - protected static List cbalTree(int n) { - if (n < 1) { - return Collections.emptyList(); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node node)) return false; + return Objects.equals(value, node.value) + && Objects.equals(left, node.left) + && Objects.equals(right, node.right); + } - if (n == 1) { - return Collections.singletonList(new Node("X", null, null)); - } + @Override + public int hashCode() { + return Objects.hash(value, left, right); + } + } + + /** + * Generates all possible completely balanced binary trees with n nodes + * + * @param n number of nodes + * @return list of all possible balanced trees + */ + protected static List cbalTree(int n) { + if (n < 1) { + return Collections.emptyList(); + } + + if (n == 1) { + return Collections.singletonList(new Node("X", null, null)); + } - List result = new ArrayList<>(); + List result = new ArrayList<>(); - // For n=2, one leaf node can be either left or right child - if (n == 2) { - Node leaf = new Node("X", null, null); - result.add(new Node("X", leaf, null)); - result.add(new Node("X", null, leaf)); - return result; - } + // For n=2, one leaf node can be either left or right child + if (n == 2) { + Node leaf = new Node("X", null, null); + result.add(new Node("X", leaf, null)); + result.add(new Node("X", null, leaf)); + return result; + } - // For n=3, we have two possibilities: - if (n == 3) { - Node leaf = new Node("X", null, null); - // Case 1: Perfect balance (1,1) - result.add(new Node("X", leaf, leaf)); + // For n=3, we have two possibilities: + if (n == 3) { + Node leaf = new Node("X", null, null); + // Case 1: Perfect balance (1,1) + result.add(new Node("X", leaf, leaf)); - // Case 2: Two nodes on left, none on right - Node twoNodeSubtree = new Node("X", leaf, null); - result.add(new Node("X", twoNodeSubtree, null)); - return result; + // Case 2: Two nodes on left, none on right + Node twoNodeSubtree = new Node("X", leaf, null); + result.add(new Node("X", twoNodeSubtree, null)); + return result; } // For n=4, we have four possibilities if (n == 4) { - Node leaf = new Node("X", null, null); + Node leaf = new Node("X", null, null); - // Pattern 1: (X (X NIL NIL) (X NIL (X NIL NIL))) - Node rightSubtree = new Node("X", null, leaf); - result.add(new Node("X", leaf, rightSubtree)); + // Pattern 1: (X (X NIL NIL) (X NIL (X NIL NIL))) + Node rightSubtree = new Node("X", null, leaf); + result.add(new Node("X", leaf, rightSubtree)); - // Pattern 2: (X (X NIL NIL) (X (X NIL NIL) NIL)) - Node rightSubtree2 = new Node("X", leaf, null); - result.add(new Node("X", leaf, rightSubtree2)); + // Pattern 2: (X (X NIL NIL) (X (X NIL NIL) NIL)) + Node rightSubtree2 = new Node("X", leaf, null); + result.add(new Node("X", leaf, rightSubtree2)); - // Mirror images of above patterns - Node leftSubtree = new Node("X", null, leaf); - result.add(new Node("X", leftSubtree, leaf)); + // Mirror images of above patterns + Node leftSubtree = new Node("X", null, leaf); + result.add(new Node("X", leftSubtree, leaf)); - Node leftSubtree2 = new Node("X", leaf, null); - result.add(new Node("X", leftSubtree2, leaf)); + Node leftSubtree2 = new Node("X", leaf, null); + result.add(new Node("X", leftSubtree2, leaf)); - return result; + return result; } // For other numbers int rem = n - 1; - - // Try all valid distributions + // Try all valid distributions for (int left = 0; left <= rem; left++) { - int right = rem - left; - if (Math.abs(left - right) <= 1) { - List leftSubtrees = left == 0 ? - Collections.singletonList(null) : cbalTree(left); - List rightSubtrees = right == 0 ? - Collections.singletonList(null) : cbalTree(right); - - for (Node leftTree : leftSubtrees) { - for (Node rightTree : rightSubtrees) { - result.add(new Node("X", leftTree, rightTree)); - } - } + int right = rem - left; + if (Math.abs(left - right) <= 1) { + List leftSubtrees = left == 0 ? Collections.singletonList(null) : cbalTree(left); + List rightSubtrees = right == 0 ? Collections.singletonList(null) : cbalTree(right); + + for (Node leftTree : leftSubtrees) { + for (Node rightTree : rightSubtrees) { + result.add(new Node("X", leftTree, rightTree)); + } } + } } return result; -} - + } } diff --git a/src/test/java/org/nintynine/problems/BTree54Test.java b/src/test/java/org/nintynine/problems/BTree54Test.java index 21a26a2..f11912a 100644 --- a/src/test/java/org/nintynine/problems/BTree54Test.java +++ b/src/test/java/org/nintynine/problems/BTree54Test.java @@ -1,101 +1,100 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static org.junit.jupiter.api.Assertions.*; - - class BTree54Test { - @Test - @DisplayName("Test single node expressions") - void testSingleNode() { - assertTrue(BTree54.isTree("a")); - assertTrue(BTree54.isTree("x")); - assertTrue(BTree54.isTree("(a nil nil)")); - } + @Test + @DisplayName("Test single node expressions") + void testSingleNode() { + assertTrue(BTree54.isTree("a")); + assertTrue(BTree54.isTree("x")); + assertTrue(BTree54.isTree("(a nil nil)")); + } - @Test - @DisplayName("Test complex valid expressions") - void testValidComplexExpressions() { - assertTrue(BTree54.isTree("(a (b nil nil) nil)")); - assertTrue(BTree54.isTree("(a nil (b nil nil))")); - assertTrue(BTree54.isTree("(a (b nil nil) (c nil nil))")); - assertTrue(BTree54.isTree("(a (b (c nil nil) nil) nil)")); - } + @Test + @DisplayName("Test complex valid expressions") + void testValidComplexExpressions() { + assertTrue(BTree54.isTree("(a (b nil nil) nil)")); + assertTrue(BTree54.isTree("(a nil (b nil nil))")); + assertTrue(BTree54.isTree("(a (b nil nil) (c nil nil))")); + assertTrue(BTree54.isTree("(a (b (c nil nil) nil) nil)")); + } - @ParameterizedTest - @DisplayName("Test invalid expressions") - @ValueSource(strings = { - "", - "nil", - "()", - "(a)", - "(a nil)", - "(a b c)", - "(a (b nil nil)", - "a nil nil", - "(a (nil nil) nil)", - "(a (b) nil)" - }) - void testInvalidExpressions(String expression) { - assertFalse(BTree54.isTree(expression)); - } + @ParameterizedTest + @DisplayName("Test invalid expressions") + @ValueSource( + strings = { + "", + "nil", + "()", + "(a)", + "(a nil)", + "(a b c)", + "(a (b nil nil)", + "a nil nil", + "(a (nil nil) nil)", + "(a (b) nil)" + }) + void testInvalidExpressions(String expression) { + assertFalse(BTree54.isTree(expression)); + } - @Test - @DisplayName("Test tree parsing and reconstruction") - void testTreeParsing() { - String expr = "(a (b nil nil) (c nil nil))"; - BTree54.BTree54Node tree = BTree54.parseTree(expr); - assertEquals(expr, tree.toString()); - } + @Test + @DisplayName("Test tree parsing and reconstruction") + void testTreeParsing() { + String expr = "(a (b nil nil) (c nil nil))"; + BTree54.BTree54Node tree = BTree54.parseTree(expr); + assertEquals(expr, tree.toString()); + } - @Test - @DisplayName("Test null and empty inputs") - void testNullAndEmpty() { - assertFalse(BTree54.isTree(null)); - assertFalse(BTree54.isTree("")); - assertFalse(BTree54.isTree(" ")); - } + @Test + @DisplayName("Test null and empty inputs") + void testNullAndEmpty() { + assertFalse(BTree54.isTree(null)); + assertFalse(BTree54.isTree("")); + assertFalse(BTree54.isTree(" ")); + } - @Test - @DisplayName("Test node creation and equality") - void testNodeCreation() { - BTree54.BTree54Node leaf1 = new BTree54.BTree54Node("x"); - BTree54.BTree54Node leaf2 = new BTree54.BTree54Node("x"); - BTree54.BTree54Node bTree54Node1 = new BTree54.BTree54Node("a", leaf1, null); - BTree54.BTree54Node bTree54Node = new BTree54.BTree54Node("a", leaf2, null); + @Test + @DisplayName("Test node creation and equality") + void testNodeCreation() { + BTree54.BTree54Node leaf1 = new BTree54.BTree54Node("x"); + BTree54.BTree54Node leaf2 = new BTree54.BTree54Node("x"); + BTree54.BTree54Node bTree54Node1 = new BTree54.BTree54Node("a", leaf1, null); + BTree54.BTree54Node bTree54Node = new BTree54.BTree54Node("a", leaf2, null); - assertEquals(leaf1, leaf2); - assertEquals(bTree54Node1, bTree54Node); - assertNotEquals(leaf1, bTree54Node1); - } + assertEquals(leaf1, leaf2); + assertEquals(bTree54Node1, bTree54Node); + assertNotEquals(leaf1, bTree54Node1); + } - @Test - @DisplayName("Test node construction with null value") - void testNodeNullValue() { - assertThrows(NullPointerException.class, - () -> new BTree54.BTree54Node(null)); - } + @Test + @DisplayName("Test node construction with null value") + void testNodeNullValue() { + assertThrows(NullPointerException.class, () -> new BTree54.BTree54Node(null)); + } - @Test - @DisplayName("Test complex tree structure") - void testComplexTree() { - String complexExpr = "(root (left (ll nil nil) (lr nil nil)) (right nil (rr nil nil)))"; - assertTrue(BTree54.isTree(complexExpr)); + @Test + @DisplayName("Test complex tree structure") + void testComplexTree() { + String complexExpr = "(root (left (ll nil nil) (lr nil nil)) (right nil (rr nil nil)))"; + assertTrue(BTree54.isTree(complexExpr)); - BTree54.BTree54Node tree = BTree54.parseTree(complexExpr); - assertEquals(complexExpr, tree.toString()); - } + BTree54.BTree54Node tree = BTree54.parseTree(complexExpr); + assertEquals(complexExpr, tree.toString()); + } - @Test - @DisplayName("Test invalid characters in values") - void testInvalidCharacters() { - assertFalse(BTree54.isTree("(a(b nil nil) nil)")); - assertFalse(BTree54.isTree("(a) (b nil nil) nil)")); - assertFalse(BTree54.isTree("(a,b nil nil)")); - } + @Test + @DisplayName("Test invalid characters in values") + void testInvalidCharacters() { + assertFalse(BTree54.isTree("(a(b nil nil) nil)")); + assertFalse(BTree54.isTree("(a) (b nil nil) nil)")); + assertFalse(BTree54.isTree("(a,b nil nil)")); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP56Test.java b/src/test/java/org/nintynine/problems/BTreeP56Test.java index a2035a5..d171643 100644 --- a/src/test/java/org/nintynine/problems/BTreeP56Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP56Test.java @@ -1,51 +1,53 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class BTreeP56Test { - @Test - void emptyTreeIsSymmetric() { - BTreeP56 tree = new BTreeP56<>(); - assertTrue(tree.isSymmetric()); - } - - @Test - void singleNodeTreeIsSymmetric() { - BTreeP56 tree = new BTreeP56<>(); - tree.setRoot(1); - assertTrue(tree.isSymmetric()); - } - - @Test - void symmetricTreeWithTwoNodes() { - BTreeP56 tree = new BTreeP56<>(); - tree.setRoot(1); - tree.addLeft(2); - tree.addRight(3); - assertTrue(tree.isSymmetric()); - } - - @Test - void asymmetricTreeWithLeftNodeOnly() { - BTreeP56 tree = new BTreeP56<>(); - tree.setRoot(1); - tree.addLeft(2); - assertFalse(tree.isSymmetric()); - } - - @Test - void asymmetricTreeWithRightNodeOnly() { - BTreeP56 tree = new BTreeP56<>(); - tree.setRoot(1); - tree.addRight(2); - assertFalse(tree.isSymmetric()); - } - - @Test - void throwsExceptionWhenAddingToEmptyTree() { - BTreeP56 tree = new BTreeP56<>(); - assertThrows(IllegalStateException.class, () -> tree.addLeft(1)); - assertThrows(IllegalStateException.class, () -> tree.addRight(1)); - } + @Test + void emptyTreeIsSymmetric() { + BTreeP56 tree = new BTreeP56<>(); + assertTrue(tree.isSymmetric()); + } + + @Test + void singleNodeTreeIsSymmetric() { + BTreeP56 tree = new BTreeP56<>(); + tree.setRoot(1); + assertTrue(tree.isSymmetric()); + } + + @Test + void symmetricTreeWithTwoNodes() { + BTreeP56 tree = new BTreeP56<>(); + tree.setRoot(1); + tree.addLeft(2); + tree.addRight(3); + assertTrue(tree.isSymmetric()); + } + + @Test + void asymmetricTreeWithLeftNodeOnly() { + BTreeP56 tree = new BTreeP56<>(); + tree.setRoot(1); + tree.addLeft(2); + assertFalse(tree.isSymmetric()); + } + + @Test + void asymmetricTreeWithRightNodeOnly() { + BTreeP56 tree = new BTreeP56<>(); + tree.setRoot(1); + tree.addRight(2); + assertFalse(tree.isSymmetric()); + } + + @Test + void throwsExceptionWhenAddingToEmptyTree() { + BTreeP56 tree = new BTreeP56<>(); + assertThrows(IllegalStateException.class, () -> tree.addLeft(1)); + assertThrows(IllegalStateException.class, () -> tree.addRight(1)); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP57Test.java b/src/test/java/org/nintynine/problems/BTreeP57Test.java index 74da99a..08ca470 100644 --- a/src/test/java/org/nintynine/problems/BTreeP57Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP57Test.java @@ -1,69 +1,70 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class BTreeP57Test { - @Test - void constructEmptyTree() { - BTreeP57 tree = new BTreeP57<>(); - assertTrue(tree.isSymmetric()); - } + @Test + void constructEmptyTree() { + BTreeP57 tree = new BTreeP57<>(); + assertTrue(tree.isSymmetric()); + } - @Test - void constructSymmetricTree() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {5, 3, 18, 1, 4, 12, 21}; - tree.construct(values); - assertTrue(tree.isSymmetric()); - } + @Test + void constructSymmetricTree() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {5, 3, 18, 1, 4, 12, 21}; + tree.construct(values); + assertTrue(tree.isSymmetric()); + } - @Test - void constructAnotherSymmetricTree() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {3, 2, 5, 7, 1}; - tree.construct(values); - assertTrue(tree.isSymmetric()); - } + @Test + void constructAnotherSymmetricTree() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {3, 2, 5, 7, 1}; + tree.construct(values); + assertTrue(tree.isSymmetric()); + } - @Test - void constructAsymmetricTree() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {3, 2, 5, 7}; - tree.construct(values); - assertFalse(tree.isSymmetric()); - } + @Test + void constructAsymmetricTree() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {3, 2, 5, 7}; + tree.construct(values); + assertFalse(tree.isSymmetric()); + } - @Test - void verifyTreeStructure() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {3, 2, 5, 7, 1}; - tree.construct(values); - String expected = "(3 (2 (1 nil nil) nil) (5 nil (7 nil nil)))"; - assertEquals(expected, tree.getStructure()); - } + @Test + void verifyTreeStructure() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {3, 2, 5, 7, 1}; + tree.construct(values); + String expected = "(3 (2 (1 nil nil) nil) (5 nil (7 nil nil)))"; + assertEquals(expected, tree.getStructure()); + } - @Test - void insertSingleValue() { - BTreeP57 tree = new BTreeP57<>(); - tree.insert(5); - assertEquals("(5 nil nil)", tree.getStructure()); - } + @Test + void insertSingleValue() { + BTreeP57 tree = new BTreeP57<>(); + tree.insert(5); + assertEquals("(5 nil nil)", tree.getStructure()); + } - @Test - void insertDuplicateValues() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {3, 3, 3}; - tree.construct(values); - assertEquals("(3 nil nil)", tree.getStructure()); - } + @Test + void insertDuplicateValues() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {3, 3, 3}; + tree.construct(values); + assertEquals("(3 nil nil)", tree.getStructure()); + } - @Test - void constructLargerSymmetricTree() { - BTreeP57 tree = new BTreeP57<>(); - Integer[] values = {10, 5, 15, 3, 7, 13, 17, 1, 4, 6, 8, 12, 14, 16, 18}; - tree.construct(values); - assertTrue(tree.isSymmetric()); - } + @Test + void constructLargerSymmetricTree() { + BTreeP57 tree = new BTreeP57<>(); + Integer[] values = {10, 5, 15, 3, 7, 13, 17, 1, 4, 6, 8, 12, 14, 16, 18}; + tree.construct(values); + assertTrue(tree.isSymmetric()); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP58Test.java b/src/test/java/org/nintynine/problems/BTreeP58Test.java index bcbebcc..80c7fa5 100644 --- a/src/test/java/org/nintynine/problems/BTreeP58Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP58Test.java @@ -1,42 +1,43 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; + import java.util.List; +import org.junit.jupiter.api.Test; class BTreeP58Test { - @Test - void testSymCbalTreesWithOneNode() { - List trees = BTreeP58.symCbalTrees(1); - assertEquals(1, trees.size()); - assertEquals("X", trees.getFirst().toString()); - } + @Test + void testSymCbalTreesWithOneNode() { + List trees = BTreeP58.symCbalTrees(1); + assertEquals(1, trees.size()); + assertEquals("X", trees.getFirst().toString()); + } - @Test - void testSymCbalTreesWithFiveNodes() { - List trees = BTreeP58.symCbalTrees(5); - assertEquals(2, trees.size()); - assertTrue(trees.stream() - .map(Object::toString) - .allMatch(s -> s.equals("X(X(NIL,X),X(X,NIL))") || - s.equals("X(X(X,NIL),X(NIL,X))"))); - } + @Test + void testSymCbalTreesWithFiveNodes() { + List trees = BTreeP58.symCbalTrees(5); + assertEquals(2, trees.size()); + assertTrue( + trees.stream() + .map(Object::toString) + .allMatch(s -> s.equals("X(X(NIL,X),X(X,NIL))") || s.equals("X(X(X,NIL),X(NIL,X))"))); + } - @Test - void testSymCbalTreesWithEvenNodes() { - List trees = BTreeP58.symCbalTrees(6); - assertEquals(0, trees.size()); - } + @Test + void testSymCbalTreesWithEvenNodes() { + List trees = BTreeP58.symCbalTrees(6); + assertEquals(0, trees.size()); + } - @Test - void testCountSymCbalTrees() { - assertEquals(1, BTreeP58.countSymCbalTrees(1)); - assertEquals(0, BTreeP58.countSymCbalTrees(2)); - assertEquals(1, BTreeP58.countSymCbalTrees(3)); - assertEquals(0, BTreeP58.countSymCbalTrees(4)); - assertEquals(2, BTreeP58.countSymCbalTrees(5)); - assertEquals(0, BTreeP58.countSymCbalTrees(6)); - assertEquals(1, BTreeP58.countSymCbalTrees(7)); - } + @Test + void testCountSymCbalTrees() { + assertEquals(1, BTreeP58.countSymCbalTrees(1)); + assertEquals(0, BTreeP58.countSymCbalTrees(2)); + assertEquals(1, BTreeP58.countSymCbalTrees(3)); + assertEquals(0, BTreeP58.countSymCbalTrees(4)); + assertEquals(2, BTreeP58.countSymCbalTrees(5)); + assertEquals(0, BTreeP58.countSymCbalTrees(6)); + assertEquals(1, BTreeP58.countSymCbalTrees(7)); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP59Test.java b/src/test/java/org/nintynine/problems/BTreeP59Test.java index 6b88a84..7a3ea23 100644 --- a/src/test/java/org/nintynine/problems/BTreeP59Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP59Test.java @@ -1,47 +1,49 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; + import java.util.List; +import org.junit.jupiter.api.Test; class BTreeP59Test { - @Test - void testHbalTreesHeight0() { - List trees = BTreeP59.hbalTrees(0); - assertEquals(1, trees.size()); - assertNull(trees.getFirst()); - } - - @Test - void testHbalTreesHeight1() { - List trees = BTreeP59.hbalTrees(1); - assertEquals(1, trees.size()); - assertEquals("X", trees.getFirst().toString()); - } - - @Test - void testHbalTreesHeight2() { - List trees = BTreeP59.hbalTrees(2); - assertEquals(3, trees.size()); - assertTrue(trees.stream() - .map(Object::toString) - .allMatch(s -> s.equals("X(X,X)") || s.equals("X(X,NIL)") || s.equals("X(NIL,X)"))); - } - - @Test - void testHbalTreesHeight3() { - List trees = BTreeP59.hbalTrees(3); - assertFalse(trees.isEmpty()); - // All trees should be height-balanced - assertTrue(trees.stream().allMatch(BTreeP59::isHeightBalanced)); - // All trees should have height exactly 3 - assertTrue(trees.stream().allMatch(tree -> BTreeP59.height(tree) == 3)); - } - - @Test - void testHbalTreesNegativeHeight() { - List trees = BTreeP59.hbalTrees(-1); - assertTrue(trees.isEmpty()); - } + @Test + void testHbalTreesHeight0() { + List trees = BTreeP59.hbalTrees(0); + assertEquals(1, trees.size()); + assertNull(trees.getFirst()); + } + + @Test + void testHbalTreesHeight1() { + List trees = BTreeP59.hbalTrees(1); + assertEquals(1, trees.size()); + assertEquals("X", trees.getFirst().toString()); + } + + @Test + void testHbalTreesHeight2() { + List trees = BTreeP59.hbalTrees(2); + assertEquals(3, trees.size()); + assertTrue( + trees.stream() + .map(Object::toString) + .allMatch(s -> s.equals("X(X,X)") || s.equals("X(X,NIL)") || s.equals("X(NIL,X)"))); + } + + @Test + void testHbalTreesHeight3() { + List trees = BTreeP59.hbalTrees(3); + assertFalse(trees.isEmpty()); + // All trees should be height-balanced + assertTrue(trees.stream().allMatch(BTreeP59::isHeightBalanced)); + // All trees should have height exactly 3 + assertTrue(trees.stream().allMatch(tree -> BTreeP59.height(tree) == 3)); + } + + @Test + void testHbalTreesNegativeHeight() { + List trees = BTreeP59.hbalTrees(-1); + assertTrue(trees.isEmpty()); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP60Test.java b/src/test/java/org/nintynine/problems/BTreeP60Test.java index 2608524..c1fad94 100644 --- a/src/test/java/org/nintynine/problems/BTreeP60Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP60Test.java @@ -1,102 +1,102 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import java.util.List; +import org.junit.jupiter.api.Test; class BTreeP60Test { - @Test - void testMinNodes() { - assertEquals(0, BTreeP60.minNodes(0)); - assertEquals(1, BTreeP60.minNodes(1)); - assertEquals(2, BTreeP60.minNodes(2)); - assertEquals(4, BTreeP60.minNodes(3)); - assertEquals(7, BTreeP60.minNodes(4)); + @Test + void testMinNodes() { + assertEquals(0, BTreeP60.minNodes(0)); + assertEquals(1, BTreeP60.minNodes(1)); + assertEquals(2, BTreeP60.minNodes(2)); + assertEquals(4, BTreeP60.minNodes(3)); + assertEquals(7, BTreeP60.minNodes(4)); + } + + @Test + void testMaxHeight() { + assertEquals(0, BTreeP60.maxHeight(0)); + assertEquals(1, BTreeP60.maxHeight(1)); + assertEquals(2, BTreeP60.maxHeight(2)); + assertEquals(2, BTreeP60.maxHeight(3)); + assertEquals(3, BTreeP60.maxHeight(4)); + } + + @Test + void testHbalTreeNodesEmpty() { + List> trees = BTreeP60.hbalTreeNodes(0); + assertTrue(trees.isEmpty()); + } + + @Test + void testHbalTreeNodesSingleNode() { + List> trees = BTreeP60.hbalTreeNodes(1); + assertEquals(1, trees.size()); + assertEquals("x", trees.getFirst().getValue()); + assertNull(trees.getFirst().getLeft()); + assertNull(trees.getFirst().getRight()); + } + + @Test + void testHbalTreeNodesTwoNodes() { + List> trees = BTreeP60.hbalTreeNodes(2); + assertEquals(2, trees.size()); // There should be 2 possible trees with 2 nodes + } + + @Test + void testHbalTreeNodesThreeNodes() { + List> trees = BTreeP60.hbalTreeNodes(3); + assertEquals(1, trees.size()); // There should be 1 possible tree with 3 nodes + } + + @Test + void testTreeHeight() { + BTreeP60 root = new BTreeP60<>("x"); + assertEquals(1, BTreeP60.getHeight(root)); + + root.left = new BTreeP60<>("x"); + assertEquals(2, BTreeP60.getHeight(root)); + + root.right = new BTreeP60<>("x"); + assertEquals(2, BTreeP60.getHeight(root)); + } + + @Test + void testHeightBalancedProperty() { + List> trees = BTreeP60.hbalTreeNodes(4); + for (BTreeP60 tree : trees) { + assertTrue(isBalanced(tree)); } - - @Test - void testMaxHeight() { - assertEquals(0, BTreeP60.maxHeight(0)); - assertEquals(1, BTreeP60.maxHeight(1)); - assertEquals(2, BTreeP60.maxHeight(2)); - assertEquals(2, BTreeP60.maxHeight(3)); - assertEquals(3, BTreeP60.maxHeight(4)); + } + + @Test + void testFifteenNodes() { + List> trees = BTreeP60.hbalTreeNodes(15); + assertFalse(trees.isEmpty()); + // All trees should be height-balanced and have exactly 15 nodes + for (BTreeP60 tree : trees) { + assertTrue(isBalanced(tree)); + assertEquals(15, countNodes(tree)); } + } - @Test - void testHbalTreeNodesEmpty() { - List> trees = BTreeP60.hbalTreeNodes(0); - assertTrue(trees.isEmpty()); - } + // Helper methods for testing + private boolean isBalanced(BTreeP60 root) { + if (root == null) return true; - @Test - void testHbalTreeNodesSingleNode() { - List> trees = BTreeP60.hbalTreeNodes(1); - assertEquals(1, trees.size()); - assertEquals("x", trees.getFirst().getValue()); - assertNull(trees.getFirst().getLeft()); - assertNull(trees.getFirst().getRight()); - } + int leftHeight = BTreeP60.getHeight(root.getLeft()); + int rightHeight = BTreeP60.getHeight(root.getRight()); - @Test - void testHbalTreeNodesTwoNodes() { - List> trees = BTreeP60.hbalTreeNodes(2); - assertEquals(2, trees.size()); // There should be 2 possible trees with 2 nodes - } + return Math.abs(leftHeight - rightHeight) <= 1 + && isBalanced(root.getLeft()) + && isBalanced(root.getRight()); + } - @Test - void testHbalTreeNodesThreeNodes() { - List> trees = BTreeP60.hbalTreeNodes(3); - assertEquals(1, trees.size()); // There should be 1 possible tree with 3 nodes - } - - @Test - void testTreeHeight() { - BTreeP60 root = new BTreeP60<>("x"); - assertEquals(1, BTreeP60.getHeight(root)); - - root.left = new BTreeP60<>("x"); - assertEquals(2, BTreeP60.getHeight(root)); - - root.right = new BTreeP60<>("x"); - assertEquals(2, BTreeP60.getHeight(root)); - } - - @Test - void testHeightBalancedProperty() { - List> trees = BTreeP60.hbalTreeNodes(4); - for (BTreeP60 tree : trees) { - assertTrue(isBalanced(tree)); - } - } - - @Test - void testFifteenNodes() { - List> trees = BTreeP60.hbalTreeNodes(15); - assertFalse(trees.isEmpty()); - // All trees should be height-balanced and have exactly 15 nodes - for (BTreeP60 tree : trees) { - assertTrue(isBalanced(tree)); - assertEquals(15, countNodes(tree)); - } - } - - // Helper methods for testing - private boolean isBalanced(BTreeP60 root) { - if (root == null) return true; - - int leftHeight = BTreeP60.getHeight(root.getLeft()); - int rightHeight = BTreeP60.getHeight(root.getRight()); - - return Math.abs(leftHeight - rightHeight) <= 1 - && isBalanced(root.getLeft()) - && isBalanced(root.getRight()); - } - - private int countNodes(BTreeP60 root) { - if (root == null) return 0; - return 1 + countNodes(root.getLeft()) + countNodes(root.getRight()); - } + private int countNodes(BTreeP60 root) { + if (root == null) return 0; + return 1 + countNodes(root.getLeft()) + countNodes(root.getRight()); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP61Test.java b/src/test/java/org/nintynine/problems/BTreeP61Test.java index 70c57ec..f6e5032 100644 --- a/src/test/java/org/nintynine/problems/BTreeP61Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP61Test.java @@ -1,59 +1,60 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class BTreeP61Test { - - @Test - void testEmptyTree() { - assertNull(null); - assertEquals(0, BTreeP61.countLeaves(null)); - } - - @Test - void testSingleNode() { - BTreeP61 tree = new BTreeP61<>("a"); - assertEquals(1, BTreeP61.countLeaves(tree)); - } - - @Test - void testOneChild() { - BTreeP61 tree = new BTreeP61<>("a"); - tree.left = new BTreeP61<>("b"); - assertEquals(1, BTreeP61.countLeaves(tree)); - } - - @Test - void testTwoChildren() { - BTreeP61 tree = new BTreeP61<>("a"); - tree.left = new BTreeP61<>("b"); - tree.right = new BTreeP61<>("c"); - assertEquals(2, BTreeP61.countLeaves(tree)); - } - - @Test - void testComplexTree() { - BTreeP61 tree = new BTreeP61<>("a"); - tree.left = new BTreeP61<>("b"); - tree.right = new BTreeP61<>("c"); - tree.left.left = new BTreeP61<>("d"); - tree.left.right = new BTreeP61<>("e"); - tree.right.right = new BTreeP61<>("f"); - - assertEquals(3, BTreeP61.countLeaves(tree)); - } - - @Test - void testFullBinaryTree() { - BTreeP61 tree = new BTreeP61<>("a"); - tree.left = new BTreeP61<>("b"); - tree.right = new BTreeP61<>("c"); - tree.left.left = new BTreeP61<>("d"); - tree.left.right = new BTreeP61<>("e"); - tree.right.left = new BTreeP61<>("f"); - tree.right.right = new BTreeP61<>("g"); - - assertEquals(4, BTreeP61.countLeaves(tree)); - } + + @Test + void testEmptyTree() { + assertNull(null); + assertEquals(0, BTreeP61.countLeaves(null)); + } + + @Test + void testSingleNode() { + BTreeP61 tree = new BTreeP61<>("a"); + assertEquals(1, BTreeP61.countLeaves(tree)); + } + + @Test + void testOneChild() { + BTreeP61 tree = new BTreeP61<>("a"); + tree.left = new BTreeP61<>("b"); + assertEquals(1, BTreeP61.countLeaves(tree)); + } + + @Test + void testTwoChildren() { + BTreeP61 tree = new BTreeP61<>("a"); + tree.left = new BTreeP61<>("b"); + tree.right = new BTreeP61<>("c"); + assertEquals(2, BTreeP61.countLeaves(tree)); + } + + @Test + void testComplexTree() { + BTreeP61 tree = new BTreeP61<>("a"); + tree.left = new BTreeP61<>("b"); + tree.right = new BTreeP61<>("c"); + tree.left.left = new BTreeP61<>("d"); + tree.left.right = new BTreeP61<>("e"); + tree.right.right = new BTreeP61<>("f"); + + assertEquals(3, BTreeP61.countLeaves(tree)); + } + + @Test + void testFullBinaryTree() { + BTreeP61 tree = new BTreeP61<>("a"); + tree.left = new BTreeP61<>("b"); + tree.right = new BTreeP61<>("c"); + tree.left.left = new BTreeP61<>("d"); + tree.left.right = new BTreeP61<>("e"); + tree.right.left = new BTreeP61<>("f"); + tree.right.right = new BTreeP61<>("g"); + + assertEquals(4, BTreeP61.countLeaves(tree)); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP68Test.java b/src/test/java/org/nintynine/problems/BTreeP68Test.java index 13dc60b..4810fbf 100644 --- a/src/test/java/org/nintynine/problems/BTreeP68Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP68Test.java @@ -1,103 +1,102 @@ package org.nintynine.problems; -import java.util.List; +import static org.junit.jupiter.api.Assertions.*; +import java.util.List; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - class BTreeP68Test { - private BTreeP68.Node exampleTree() { - BTreeP68.Node a = new BTreeP68.Node('A'); - BTreeP68.Node b = new BTreeP68.Node('B'); - BTreeP68.Node c = new BTreeP68.Node('C'); - BTreeP68.Node d = new BTreeP68.Node('D'); - BTreeP68.Node e = new BTreeP68.Node('E'); - BTreeP68.Node f = new BTreeP68.Node('F'); - BTreeP68.Node g = new BTreeP68.Node('G'); - a.left = b; - a.right = c; - b.left = d; - b.right = e; - c.right = f; - f.left = g; - return a; - } - - @Test - void testPreorderAndInorder() { - BTreeP68.Node root = exampleTree(); - List pre = BTreeP68.preorder(root); - List in = BTreeP68.inorder(root); - assertEquals(List.of('A','B','D','E','C','F','G'), pre); - assertEquals(List.of('D','B','E','A','C','G','F'), in); - } - - @Test - void testFromPreorder() { - List seq = List.of('F','C','A','E','H','G'); - BTreeP68.Node root = BTreeP68.fromPreorder(seq); - assertEquals(seq, BTreeP68.preorder(root)); - List inorder = BTreeP68.inorder(root); - assertEquals(List.of('A','C','E','F','G','H'), inorder); // inorder sorted - } - - @Test - void testPreInTree() { - BTreeP68.Node root = exampleTree(); - List pre = BTreeP68.preorder(root); - List in = BTreeP68.inorder(root); - BTreeP68.Node rebuilt = BTreeP68.preInTree(pre, in); - assertEquals(pre, BTreeP68.preorder(rebuilt)); - assertEquals(in, BTreeP68.inorder(rebuilt)); - assertEquals(root, rebuilt); - } - - @Test - void testPreInTreeInvalid() { - assertThrows(IllegalArgumentException.class, () -> - BTreeP68.preInTree(List.of('A'), List.of('A','B'))); - } - - @Test - void testNodeEqualityAndHash() { - BTreeP68.Node n1 = new BTreeP68.Node('A'); - n1.left = new BTreeP68.Node('B'); - BTreeP68.Node n2 = new BTreeP68.Node('A'); - n2.left = new BTreeP68.Node('B'); - assertEquals(n1, n2); // same structure - assertEquals(n1, n1); // self equality - assertNotEquals(n1, "other"); - assertNotEquals(n1, null); - assertEquals(n1.hashCode(), n2.hashCode()); - - assertNotEquals(n1, new BTreeP68.Node('X')); - BTreeP68.Node n3 = new BTreeP68.Node('A'); - n3.left = new BTreeP68.Node('B'); - n3.right = new BTreeP68.Node('C'); - assertNotEquals(n1, n3); - - n2.left.value = 'C'; - assertNotEquals(n1, n2); - } - - @Test - void testNodeToString() { - BTreeP68.Node leaf = new BTreeP68.Node('X'); - assertEquals("X", leaf.toString()); - - BTreeP68.Node root = new BTreeP68.Node('A'); - root.left = new BTreeP68.Node('B'); - root.right = new BTreeP68.Node('C'); - assertEquals("A(B,C)", root.toString()); - - BTreeP68.Node half = new BTreeP68.Node('A'); - half.left = new BTreeP68.Node('B'); - assertEquals("A(B,NIL)", half.toString()); - - BTreeP68.Node halfRight = new BTreeP68.Node('A'); - halfRight.right = new BTreeP68.Node('B'); - assertEquals("A(NIL,B)", halfRight.toString()); - } + private BTreeP68.Node exampleTree() { + BTreeP68.Node a = new BTreeP68.Node('A'); + BTreeP68.Node b = new BTreeP68.Node('B'); + BTreeP68.Node c = new BTreeP68.Node('C'); + BTreeP68.Node d = new BTreeP68.Node('D'); + BTreeP68.Node e = new BTreeP68.Node('E'); + BTreeP68.Node f = new BTreeP68.Node('F'); + BTreeP68.Node g = new BTreeP68.Node('G'); + a.left = b; + a.right = c; + b.left = d; + b.right = e; + c.right = f; + f.left = g; + return a; + } + + @Test + void testPreorderAndInorder() { + BTreeP68.Node root = exampleTree(); + List pre = BTreeP68.preorder(root); + List in = BTreeP68.inorder(root); + assertEquals(List.of('A', 'B', 'D', 'E', 'C', 'F', 'G'), pre); + assertEquals(List.of('D', 'B', 'E', 'A', 'C', 'G', 'F'), in); + } + + @Test + void testFromPreorder() { + List seq = List.of('F', 'C', 'A', 'E', 'H', 'G'); + BTreeP68.Node root = BTreeP68.fromPreorder(seq); + assertEquals(seq, BTreeP68.preorder(root)); + List inorder = BTreeP68.inorder(root); + assertEquals(List.of('A', 'C', 'E', 'F', 'G', 'H'), inorder); // inorder sorted + } + + @Test + void testPreInTree() { + BTreeP68.Node root = exampleTree(); + List pre = BTreeP68.preorder(root); + List in = BTreeP68.inorder(root); + BTreeP68.Node rebuilt = BTreeP68.preInTree(pre, in); + assertEquals(pre, BTreeP68.preorder(rebuilt)); + assertEquals(in, BTreeP68.inorder(rebuilt)); + assertEquals(root, rebuilt); + } + + @Test + void testPreInTreeInvalid() { + assertThrows( + IllegalArgumentException.class, () -> BTreeP68.preInTree(List.of('A'), List.of('A', 'B'))); + } + + @Test + void testNodeEqualityAndHash() { + BTreeP68.Node n1 = new BTreeP68.Node('A'); + n1.left = new BTreeP68.Node('B'); + BTreeP68.Node n2 = new BTreeP68.Node('A'); + n2.left = new BTreeP68.Node('B'); + assertEquals(n1, n2); // same structure + assertEquals(n1, n1); // self equality + assertNotEquals(n1, "other"); + assertNotEquals(n1, null); + assertEquals(n1.hashCode(), n2.hashCode()); + + assertNotEquals(n1, new BTreeP68.Node('X')); + BTreeP68.Node n3 = new BTreeP68.Node('A'); + n3.left = new BTreeP68.Node('B'); + n3.right = new BTreeP68.Node('C'); + assertNotEquals(n1, n3); + + n2.left.value = 'C'; + assertNotEquals(n1, n2); + } + + @Test + void testNodeToString() { + BTreeP68.Node leaf = new BTreeP68.Node('X'); + assertEquals("X", leaf.toString()); + + BTreeP68.Node root = new BTreeP68.Node('A'); + root.left = new BTreeP68.Node('B'); + root.right = new BTreeP68.Node('C'); + assertEquals("A(B,C)", root.toString()); + + BTreeP68.Node half = new BTreeP68.Node('A'); + half.left = new BTreeP68.Node('B'); + assertEquals("A(B,NIL)", half.toString()); + + BTreeP68.Node halfRight = new BTreeP68.Node('A'); + halfRight.right = new BTreeP68.Node('B'); + assertEquals("A(NIL,B)", halfRight.toString()); + } } diff --git a/src/test/java/org/nintynine/problems/BTreeP69Test.java b/src/test/java/org/nintynine/problems/BTreeP69Test.java index a5cb571..1dcb76c 100644 --- a/src/test/java/org/nintynine/problems/BTreeP69Test.java +++ b/src/test/java/org/nintynine/problems/BTreeP69Test.java @@ -1,9 +1,9 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class BTreeP69Test { @Test diff --git a/src/test/java/org/nintynine/problems/MathP31Test.java b/src/test/java/org/nintynine/problems/MathP31Test.java index dac002c..941ed89 100644 --- a/src/test/java/org/nintynine/problems/MathP31Test.java +++ b/src/test/java/org/nintynine/problems/MathP31Test.java @@ -1,44 +1,50 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static org.junit.jupiter.api.Assertions.*; - class MathP31Test { - @ParameterizedTest(name = "{0} is prime") - @ValueSource(longs = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, - 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}) - void testPrimeNumbers(long number) { - assertTrue(MathP31.isPrime(number)); - } - - @ParameterizedTest(name = "{0} is not prime") - @ValueSource(longs = {1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, - 25, 26, 27, 28, 30, 32, 33, 34, 35, 36}) - void testNonPrimeNumbers(long number) { - assertFalse(MathP31.isPrime(number)); - } - - @Test - void testLargePrimeNumber() { - assertTrue(MathP31.isPrime(7919)); // 1000th prime number - } - - @Test - void testLargeNonPrimeNumber() { - assertFalse(MathP31.isPrime(7917)); // 7917 = 3 × 2639 - } - - @Test - void testNegativeNumber() { - assertThrows(IllegalArgumentException.class, () -> MathP31.isPrime(-7)); - } - - @Test - void testZero() { - assertThrows(IllegalArgumentException.class, () -> MathP31.isPrime(0)); - } + @ParameterizedTest(name = "{0} is prime") + @ValueSource( + longs = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97 + }) + void testPrimeNumbers(long number) { + assertTrue(MathP31.isPrime(number)); + } + + @ParameterizedTest(name = "{0} is not prime") + @ValueSource( + longs = { + 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, + 36 + }) + void testNonPrimeNumbers(long number) { + assertFalse(MathP31.isPrime(number)); + } + + @Test + void testLargePrimeNumber() { + assertTrue(MathP31.isPrime(7919)); // 1000th prime number + } + + @Test + void testLargeNonPrimeNumber() { + assertFalse(MathP31.isPrime(7917)); // 7917 = 3 × 2639 + } + + @Test + void testNegativeNumber() { + assertThrows(IllegalArgumentException.class, () -> MathP31.isPrime(-7)); + } + + @Test + void testZero() { + assertThrows(IllegalArgumentException.class, () -> MathP31.isPrime(0)); + } } diff --git a/src/test/java/org/nintynine/problems/MathP32Test.java b/src/test/java/org/nintynine/problems/MathP32Test.java index 04e02d6..79575d2 100644 --- a/src/test/java/org/nintynine/problems/MathP32Test.java +++ b/src/test/java/org/nintynine/problems/MathP32Test.java @@ -1,59 +1,59 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.*; - class MathP32Test { - @ParameterizedTest(name = "GCD of {0} and {1} should be {2}") - @CsvSource({ - "36, 63, 9", // Example from the problem statement - "10, 5, 5", // One number is multiple of another - "7, 13, 1", // Coprime numbers - "48, 18, 6", // Regular case - "54, 24, 6", // Another regular case - "100, 10, 10", // Multiple of 10 - "17, 17, 17", // Same numbers - "1, 1, 1", // Both numbers are 1 - "98, 56, 14" // Larger numbers - }) - void testGcd(long a, long b, long expected) { - assertEquals(expected, MathP32.gcd(a, b)); - assertEquals(expected, MathP32.gcd(b, a)); // Test commutative property - - // Test recursive implementation as well - assertEquals(expected, MathP32.gcdRecursive(a, b)); - assertEquals(expected, MathP32.gcdRecursive(b, a)); - } - - @Test - void testLargeNumbers() { - assertEquals(3, MathP32.gcd(123456, 654321)); - assertEquals(3, MathP32.gcdRecursive(123456, 654321)); - } - - @Test - void testNegativeNumbers() { - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(-36, 63)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(36, -63)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(-36, -63)); - - assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(-36, 63)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(36, -63)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(-36, -63)); - } - - @Test - void testZero() { - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(0, 63)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(36, 0)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(0, 0)); - - assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(0, 63)); - assertEquals(36, MathP32.gcdRecursive(36, 0)); - assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(0, 0)); - } + @ParameterizedTest(name = "GCD of {0} and {1} should be {2}") + @CsvSource({ + "36, 63, 9", // Example from the problem statement + "10, 5, 5", // One number is multiple of another + "7, 13, 1", // Coprime numbers + "48, 18, 6", // Regular case + "54, 24, 6", // Another regular case + "100, 10, 10", // Multiple of 10 + "17, 17, 17", // Same numbers + "1, 1, 1", // Both numbers are 1 + "98, 56, 14" // Larger numbers + }) + void testGcd(long a, long b, long expected) { + assertEquals(expected, MathP32.gcd(a, b)); + assertEquals(expected, MathP32.gcd(b, a)); // Test commutative property + + // Test recursive implementation as well + assertEquals(expected, MathP32.gcdRecursive(a, b)); + assertEquals(expected, MathP32.gcdRecursive(b, a)); + } + + @Test + void testLargeNumbers() { + assertEquals(3, MathP32.gcd(123456, 654321)); + assertEquals(3, MathP32.gcdRecursive(123456, 654321)); + } + + @Test + void testNegativeNumbers() { + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(-36, 63)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(36, -63)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(-36, -63)); + + assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(-36, 63)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(36, -63)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(-36, -63)); + } + + @Test + void testZero() { + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(0, 63)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(36, 0)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcd(0, 0)); + + assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(0, 63)); + assertEquals(36, MathP32.gcdRecursive(36, 0)); + assertThrows(IllegalArgumentException.class, () -> MathP32.gcdRecursive(0, 0)); + } } diff --git a/src/test/java/org/nintynine/problems/MathP33Test.java b/src/test/java/org/nintynine/problems/MathP33Test.java index 22e403b..dcab4b0 100644 --- a/src/test/java/org/nintynine/problems/MathP33Test.java +++ b/src/test/java/org/nintynine/problems/MathP33Test.java @@ -1,102 +1,102 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.*; - class MathP33Test { - @ParameterizedTest(name = "{0} and {1} should be coprime") - @DisplayName("Test known coprime numbers") - @CsvSource({ - "35, 64", // Example from the problem statement - "21, 22", // Consecutive numbers - "15, 28", // Regular coprime numbers - "7, 13", // Two prime numbers - "1, 17", // One is 1 (coprime with any number) - "17, 1", // Reverse order of above - "1, 1", // Special case - both are 1 - "49, 50", // Square number with its consecutive - "27, 35", // Two composite numbers that are coprime - "8, 15", // Powers of different primes - "125, 128" // Higher powers of different primes - }) - void testCoprimeNumbers(long a, long b) { - assertTrue(MathP33.areCoprime(a, b)); - assertTrue(MathP33.areCoprime(b, a)); // Test commutative property - } + @ParameterizedTest(name = "{0} and {1} should be coprime") + @DisplayName("Test known coprime numbers") + @CsvSource({ + "35, 64", // Example from the problem statement + "21, 22", // Consecutive numbers + "15, 28", // Regular coprime numbers + "7, 13", // Two prime numbers + "1, 17", // One is 1 (coprime with any number) + "17, 1", // Reverse order of above + "1, 1", // Special case - both are 1 + "49, 50", // Square number with its consecutive + "27, 35", // Two composite numbers that are coprime + "8, 15", // Powers of different primes + "125, 128" // Higher powers of different primes + }) + void testCoprimeNumbers(long a, long b) { + assertTrue(MathP33.areCoprime(a, b)); + assertTrue(MathP33.areCoprime(b, a)); // Test commutative property + } - @ParameterizedTest(name = "{0} and {1} should not be coprime") - @DisplayName("Test known non-coprime numbers") - @CsvSource({ - "25, 35", // Share factor 5 - "14, 28", // One is multiple of other - "15, 45", // Share multiple factors - "13, 13", // Same number (except 1) - "16, 64", // Share power of 2 - "21, 63", // Share factor 3 - "100, 150", // Share multiple factors (2 and 5) - "36, 48", // Share multiple factors (2 and 3) - "49, 147", // Share factor 7 - "121, 363" // Share factor 11 - }) - void testNonCoprimeNumbers(long a, long b) { - assertFalse(MathP33.areCoprime(a, b)); - assertFalse(MathP33.areCoprime(b, a)); // Test commutative property - } + @ParameterizedTest(name = "{0} and {1} should not be coprime") + @DisplayName("Test known non-coprime numbers") + @CsvSource({ + "25, 35", // Share factor 5 + "14, 28", // One is multiple of other + "15, 45", // Share multiple factors + "13, 13", // Same number (except 1) + "16, 64", // Share power of 2 + "21, 63", // Share factor 3 + "100, 150", // Share multiple factors (2 and 5) + "36, 48", // Share multiple factors (2 and 3) + "49, 147", // Share factor 7 + "121, 363" // Share factor 11 + }) + void testNonCoprimeNumbers(long a, long b) { + assertFalse(MathP33.areCoprime(a, b)); + assertFalse(MathP33.areCoprime(b, a)); // Test commutative property + } - @Test - @DisplayName("Test large coprime numbers") - void testLargeCoprimeNumbers() { - assertFalse(MathP33.areCoprime(123456789, 987654321)); - assertTrue(MathP33.areCoprime(104729, 104723)); // Two large consecutive primes - } + @Test + @DisplayName("Test large coprime numbers") + void testLargeCoprimeNumbers() { + assertFalse(MathP33.areCoprime(123456789, 987654321)); + assertTrue(MathP33.areCoprime(104729, 104723)); // Two large consecutive primes + } - @Test - @DisplayName("Test large non-coprime numbers") - void testLargeNonCoprimeNumbers() { - assertFalse(MathP33.areCoprime(123456, 654321)); // Share common factors - assertFalse(MathP33.areCoprime(1000000, 2000000)); // Share large power of 10 - } + @Test + @DisplayName("Test large non-coprime numbers") + void testLargeNonCoprimeNumbers() { + assertFalse(MathP33.areCoprime(123456, 654321)); // Share common factors + assertFalse(MathP33.areCoprime(1000000, 2000000)); // Share large power of 10 + } - @Test - @DisplayName("Test negative numbers throw exception") - void testNegativeNumbers() { - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(-35, 64)); - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(35, -64)); - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(-35, -64)); - } + @Test + @DisplayName("Test negative numbers throw exception") + void testNegativeNumbers() { + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(-35, 64)); + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(35, -64)); + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(-35, -64)); + } - @Test - @DisplayName("Test zero throws exception") - void testZero() { - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(0, 64)); - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(35, 0)); - assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(0, 0)); - } + @Test + @DisplayName("Test zero throws exception") + void testZero() { + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(0, 64)); + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(35, 0)); + assertThrows(IllegalArgumentException.class, () -> MathP33.areCoprime(0, 0)); + } - @Test - @DisplayName("Test special mathematical properties") - void testSpecialProperties() { - // Property 1: Consecutive numbers are always coprime - assertTrue(MathP33.areCoprime(100, 101)); - assertTrue(MathP33.areCoprime(999, 1000)); + @Test + @DisplayName("Test special mathematical properties") + void testSpecialProperties() { + // Property 1: Consecutive numbers are always coprime + assertTrue(MathP33.areCoprime(100, 101)); + assertTrue(MathP33.areCoprime(999, 1000)); - // Property 2: Any number is coprime with 1 - assertTrue(MathP33.areCoprime(1, 999999)); - assertTrue(MathP33.areCoprime(999999, 1)); + // Property 2: Any number is coprime with 1 + assertTrue(MathP33.areCoprime(1, 999999)); + assertTrue(MathP33.areCoprime(999999, 1)); - // Property 3: Two different prime numbers are always coprime - assertTrue(MathP33.areCoprime(17, 19)); - assertTrue(MathP33.areCoprime(101, 103)); + // Property 3: Two different prime numbers are always coprime + assertTrue(MathP33.areCoprime(17, 19)); + assertTrue(MathP33.areCoprime(101, 103)); - // Property 4: If a number is coprime to each of two numbers, it's not necessarily - // coprime to their product - assertTrue(MathP33.areCoprime(10, 21)); - assertFalse(MathP33.areCoprime(10, 28)); - assertFalse(MathP33.areCoprime(10, 21 * 28)); - } + // Property 4: If a number is coprime to each of two numbers, it's not necessarily + // coprime to their product + assertTrue(MathP33.areCoprime(10, 21)); + assertFalse(MathP33.areCoprime(10, 28)); + assertFalse(MathP33.areCoprime(10, 21 * 28)); + } } diff --git a/src/test/java/org/nintynine/problems/MathP34Test.java b/src/test/java/org/nintynine/problems/MathP34Test.java index 3ffea21..48da310 100644 --- a/src/test/java/org/nintynine/problems/MathP34Test.java +++ b/src/test/java/org/nintynine/problems/MathP34Test.java @@ -1,90 +1,93 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.*; - class MathP34Test { - @ParameterizedTest(name = "φ({0}) = {1}") - @DisplayName("Test known totient values") - @CsvSource({ - "1, 1", // Special case - "10, 4", // Example from problem statement (coprime: 1,3,7,9) - "2, 1", // Smallest prime - "3, 2", // Prime - "4, 2", // Power of 2 - "7, 6", // Prime - "8, 4", // Power of 2 - "9, 6", // Perfect square - "12, 4", // Composite - "15, 8", // Product of two primes - "16, 8", // Power of 2 - "20, 8", // Composite - "25, 20", // Perfect square of prime - "30, 8" // Highly composite - }) - void testTotientPhi(long input, long expected) { - assertEquals(expected, MathP34.totientPhi(input)); - } + @ParameterizedTest(name = "φ({0}) = {1}") + @DisplayName("Test known totient values") + @CsvSource({ + "1, 1", // Special case + "10, 4", // Example from problem statement (coprime: 1,3,7,9) + "2, 1", // Smallest prime + "3, 2", // Prime + "4, 2", // Power of 2 + "7, 6", // Prime + "8, 4", // Power of 2 + "9, 6", // Perfect square + "12, 4", // Composite + "15, 8", // Product of two primes + "16, 8", // Power of 2 + "20, 8", // Composite + "25, 20", // Perfect square of prime + "30, 8" // Highly composite + }) + void testTotientPhi(long input, long expected) { + assertEquals(expected, MathP34.totientPhi(input)); + } - @Test - @DisplayName("Test prime number totient properties") - void testPrimeNumberTotient() { - // For any prime number p, φ(p) = p-1 - long[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; - for (long prime : primes) { - assertEquals(prime - 1, MathP34.totientPhi(prime), - "For prime number " + prime + ", φ(p) should be p-1"); - } + @Test + @DisplayName("Test prime number totient properties") + void testPrimeNumberTotient() { + // For any prime number p, φ(p) = p-1 + long[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; + for (long prime : primes) { + assertEquals( + prime - 1, + MathP34.totientPhi(prime), + "For prime number " + prime + ", φ(p) should be p-1"); } + } - @Test - @DisplayName("Test totient properties for composite numbers") - void testCompositeNumberProperties() { - // Test multiplicative property for coprime numbers - // If a and b are coprime, then φ(a*b) = φ(a) * φ(b) - assertEquals(MathP34.totientPhi(15), - MathP34.totientPhi(3) * MathP34.totientPhi(5), - "φ(15) should equal φ(3) * φ(5)"); + @Test + @DisplayName("Test totient properties for composite numbers") + void testCompositeNumberProperties() { + // Test multiplicative property for coprime numbers + // If a and b are coprime, then φ(a*b) = φ(a) * φ(b) + assertEquals( + MathP34.totientPhi(15), + MathP34.totientPhi(3) * MathP34.totientPhi(5), + "φ(15) should equal φ(3) * φ(5)"); - // Test for perfect squares - assertEquals(6, MathP34.totientPhi(9)); // 9 = 3² - assertEquals(8, MathP34.totientPhi(16)); // 16 = 2⁴ - } + // Test for perfect squares + assertEquals(6, MathP34.totientPhi(9)); // 9 = 3² + assertEquals(8, MathP34.totientPhi(16)); // 16 = 2⁴ + } - @Test - @DisplayName("Test prime and totient check") - void testPrimeAndTotient() { - // Test prime number - var result1 = MathP34.checkPrimeAndTotient(17); - assertTrue(result1.isPrime()); - assertEquals(16, result1.totientValue()); + @Test + @DisplayName("Test prime and totient check") + void testPrimeAndTotient() { + // Test prime number + var result1 = MathP34.checkPrimeAndTotient(17); + assertTrue(result1.isPrime()); + assertEquals(16, result1.totientValue()); - // Test composite number - var result2 = MathP34.checkPrimeAndTotient(24); - assertFalse(result2.isPrime()); - assertEquals(8, result2.totientValue()); - } + // Test composite number + var result2 = MathP34.checkPrimeAndTotient(24); + assertFalse(result2.isPrime()); + assertEquals(8, result2.totientValue()); + } - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(0)); - assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(-1)); - assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(-100)); - } + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(0)); + assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(-1)); + assertThrows(IllegalArgumentException.class, () -> MathP34.totientPhi(-100)); + } - @Test - @DisplayName("Test larger numbers") - void testLargerNumbers() { - // Test a larger prime number - assertEquals(96, MathP34.totientPhi(97)); // 97 is prime, so φ(97) = 96 + @Test + @DisplayName("Test larger numbers") + void testLargerNumbers() { + // Test a larger prime number + assertEquals(96, MathP34.totientPhi(97)); // 97 is prime, so φ(97) = 96 - // Test a larger composite number - assertEquals(40, MathP34.totientPhi(100)); // 100 = 2² * 5² - } + // Test a larger composite number + assertEquals(40, MathP34.totientPhi(100)); // 100 = 2² * 5² + } } diff --git a/src/test/java/org/nintynine/problems/MathP35Test.java b/src/test/java/org/nintynine/problems/MathP35Test.java index 0c84b89..8a51236 100644 --- a/src/test/java/org/nintynine/problems/MathP35Test.java +++ b/src/test/java/org/nintynine/problems/MathP35Test.java @@ -1,110 +1,101 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.List; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; - class MathP35Test { - private static Stream provideTestCases() { - return Stream.of( - Arguments.of(1L, List.of()), // Special case: 1 - Arguments.of(2L, List.of(2L)), // Prime number - Arguments.of(3L, List.of(3L)), // Prime number - Arguments.of(4L, List.of(2L, 2L)), // Power of prime - Arguments.of(6L, List.of(2L, 3L)), // Product of primes - Arguments.of(8L, List.of(2L, 2L, 2L)), // Power of 2 - Arguments.of(9L, List.of(3L, 3L)), // Perfect square - Arguments.of(10L, List.of(2L, 5L)), // Product of primes - Arguments.of(12L, List.of(2L, 2L, 3L)), // Multiple factors - Arguments.of(315L, List.of(3L, 3L, 5L, 7L)), // Example from problem - Arguments.of(330L, List.of(2L, 3L, 5L, 11L)), // Multiple different primes - Arguments.of(1001L, List.of(7L, 11L, 13L)), // Large number - Arguments.of(1024L, List.of(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L)) // Power of 2 + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(1L, List.of()), // Special case: 1 + Arguments.of(2L, List.of(2L)), // Prime number + Arguments.of(3L, List.of(3L)), // Prime number + Arguments.of(4L, List.of(2L, 2L)), // Power of prime + Arguments.of(6L, List.of(2L, 3L)), // Product of primes + Arguments.of(8L, List.of(2L, 2L, 2L)), // Power of 2 + Arguments.of(9L, List.of(3L, 3L)), // Perfect square + Arguments.of(10L, List.of(2L, 5L)), // Product of primes + Arguments.of(12L, List.of(2L, 2L, 3L)), // Multiple factors + Arguments.of(315L, List.of(3L, 3L, 5L, 7L)), // Example from problem + Arguments.of(330L, List.of(2L, 3L, 5L, 11L)), // Multiple different primes + Arguments.of(1001L, List.of(7L, 11L, 13L)), // Large number + Arguments.of(1024L, List.of(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L)) // Power of 2 ); + } + + @ParameterizedTest(name = "Prime factors of {0} should be {1}") + @MethodSource("provideTestCases") + void testPrimeFactors(long input, List expected) { + assertEquals(expected, MathP35.primeFactors(input)); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(0)); + assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(-1)); + assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(-315)); + } + + @Test + @DisplayName("Test large numbers") + void testLargeNumbers() { + // Test a large number: 123456 = 2^4 * 3 * 643 + assertEquals(List.of(2L, 2L, 2L, 2L, 2L, 2L, 3L, 643L), MathP35.primeFactors(123456L)); + + // Test a large prime number + assertEquals(List.of(104729L), MathP35.primeFactors(104729L)); + } + + @Test + @DisplayName("Verify prime factorization product") + void verifyFactorizationProduct() { + // Test that multiplying all factors gives back the original number + long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; + + for (long n : testNumbers) { + List factors = MathP35.primeFactors(n); + long product = factors.stream().reduce(1L, (a, b) -> a * b); + assertEquals(n, product, "Product of prime factors should equal original number for " + n); } + } - @ParameterizedTest(name = "Prime factors of {0} should be {1}") - @MethodSource("provideTestCases") - void testPrimeFactors(long input, List expected) { - assertEquals(expected, MathP35.primeFactors(input)); - } - - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(0)); - assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(-1)); - assertThrows(IllegalArgumentException.class, () -> MathP35.primeFactors(-315)); - } - - @Test - @DisplayName("Test large numbers") - void testLargeNumbers() { - // Test a large number: 123456 = 2^4 * 3 * 643 - assertEquals( - List.of(2L, 2L, 2L, 2L, 2L, 2L, 3L, 643L), - MathP35.primeFactors(123456L) - ); - - // Test a large prime number - assertEquals( - List.of(104729L), - MathP35.primeFactors(104729L) - ); - } - - @Test - @DisplayName("Verify prime factorization product") - void verifyFactorizationProduct() { - // Test that multiplying all factors gives back the original number - long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - - for (long n : testNumbers) { - List factors = MathP35.primeFactors(n); - long product = factors.stream().reduce(1L, (a, b) -> a * b); - assertEquals(n, product, - "Product of prime factors should equal original number for " + n); - } - } - - @Test - @DisplayName("Verify factors are prime") - void verifyFactorsArePrime() { - long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; + @Test + @DisplayName("Verify factors are prime") + void verifyFactorsArePrime() { + long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - for (long n : testNumbers) { - List factors = MathP35.primeFactors(n); - assertTrue(factors.stream().allMatch(MathP31::isPrime), - "All factors should be prime for " + n); - } + for (long n : testNumbers) { + List factors = MathP35.primeFactors(n); + assertTrue( + factors.stream().allMatch(MathP31::isPrime), "All factors should be prime for " + n); } + } - @Test - @DisplayName("Verify factors are in ascending order") - void verifyFactorsAreOrdered() { - long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; + @Test + @DisplayName("Verify factors are in ascending order") + void verifyFactorsAreOrdered() { + long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - for (long n : testNumbers) { - List factors = MathP35.primeFactors(n); - assertTrue(isAscending(factors), - "Factors should be in ascending order for " + n); - } + for (long n : testNumbers) { + List factors = MathP35.primeFactors(n); + assertTrue(isAscending(factors), "Factors should be in ascending order for " + n); } + } - private boolean isAscending(List numbers) { - for (int i = 1; i < numbers.size(); i++) { - if (numbers.get(i) < numbers.get(i - 1)) { - return false; - } - } - return true; + private boolean isAscending(List numbers) { + for (int i = 1; i < numbers.size(); i++) { + if (numbers.get(i) < numbers.get(i - 1)) { + return false; + } } + return true; + } } diff --git a/src/test/java/org/nintynine/problems/MathP36Test.java b/src/test/java/org/nintynine/problems/MathP36Test.java index 313d0df..5a3966d 100644 --- a/src/test/java/org/nintynine/problems/MathP36Test.java +++ b/src/test/java/org/nintynine/problems/MathP36Test.java @@ -1,119 +1,115 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.List; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; - class MathP36Test { - private static Stream provideTestCases() { - return Stream.of( - Arguments.of(1L, List.of()), - Arguments.of(2L, List.of( - new MathP36.PrimeFactor(2, 1))), - Arguments.of(4L, List.of( - new MathP36.PrimeFactor(2, 2))), - Arguments.of(8L, List.of( - new MathP36.PrimeFactor(2, 3))), - Arguments.of(9L, List.of( - new MathP36.PrimeFactor(3, 2))), - Arguments.of(12L, List.of( - new MathP36.PrimeFactor(2, 2), - new MathP36.PrimeFactor(3, 1))), - Arguments.of(315L, List.of( - new MathP36.PrimeFactor(3, 2), - new MathP36.PrimeFactor(5, 1), - new MathP36.PrimeFactor(7, 1))), - Arguments.of(1024L, List.of( - new MathP36.PrimeFactor(2, 10))), - Arguments.of(123456L, List.of( - new MathP36.PrimeFactor(2, 6), - new MathP36.PrimeFactor(3, 1), - new MathP36.PrimeFactor(643, 1))) - ); - } - - @ParameterizedTest(name = "Prime factorization of {0}") - @MethodSource("provideTestCases") - void testPrimeFactorsMult(long input, List expected) { - assertEquals(expected, MathP36.primeFactorsMult(input)); + private static Stream provideTestCases() { + return Stream.of( + Arguments.of(1L, List.of()), + Arguments.of(2L, List.of(new MathP36.PrimeFactor(2, 1))), + Arguments.of(4L, List.of(new MathP36.PrimeFactor(2, 2))), + Arguments.of(8L, List.of(new MathP36.PrimeFactor(2, 3))), + Arguments.of(9L, List.of(new MathP36.PrimeFactor(3, 2))), + Arguments.of(12L, List.of(new MathP36.PrimeFactor(2, 2), new MathP36.PrimeFactor(3, 1))), + Arguments.of( + 315L, + List.of( + new MathP36.PrimeFactor(3, 2), + new MathP36.PrimeFactor(5, 1), + new MathP36.PrimeFactor(7, 1))), + Arguments.of(1024L, List.of(new MathP36.PrimeFactor(2, 10))), + Arguments.of( + 123456L, + List.of( + new MathP36.PrimeFactor(2, 6), + new MathP36.PrimeFactor(3, 1), + new MathP36.PrimeFactor(643, 1)))); + } + + @ParameterizedTest(name = "Prime factorization of {0}") + @MethodSource("provideTestCases") + void testPrimeFactorsMult(long input, List expected) { + assertEquals(expected, MathP36.primeFactorsMult(input)); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(0)); + assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(-1)); + assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(-315)); + } + + @Test + @DisplayName("Test reconstruction of original number") + void testReconstruction() { + long[] testNumbers = {1L, 2L, 4L, 8L, 9L, 12L, 315L, 1024L, 123456L}; + + for (long n : testNumbers) { + List factors = MathP36.primeFactorsMult(n); + assertEquals( + n, MathP36.reconstruct(factors), "Reconstruction should match original number for " + n); } - - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(0)); - assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(-1)); - assertThrows(IllegalArgumentException.class, () -> MathP36.primeFactorsMult(-315)); - } - - @Test - @DisplayName("Test reconstruction of original number") - void testReconstruction() { - long[] testNumbers = {1L, 2L, 4L, 8L, 9L, 12L, 315L, 1024L, 123456L}; - - for (long n : testNumbers) { - List factors = MathP36.primeFactorsMult(n); - assertEquals(n, MathP36.reconstruct(factors), - "Reconstruction should match original number for " + n); - } - } - - @Test - @DisplayName("Test reconstruction with large numbers") - void testReconstructionLarge() { - long n = 1_000_000_000_000L; - List factors = MathP36.primeFactorsMult(n); - assertEquals(n, MathP36.reconstruct(factors), - "Reconstruction should match original number for large input"); + } + + @Test + @DisplayName("Test reconstruction with large numbers") + void testReconstructionLarge() { + long n = 1_000_000_000_000L; + List factors = MathP36.primeFactorsMult(n); + assertEquals( + n, + MathP36.reconstruct(factors), + "Reconstruction should match original number for large input"); + } + + @Test + @DisplayName("Verify factors are prime") + void verifyFactorsArePrime() { + long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; + + for (long n : testNumbers) { + List factors = MathP36.primeFactorsMult(n); + assertTrue( + factors.stream().allMatch(f -> MathP31.isPrime(f.factor())), + "All factors should be prime for " + n); } + } - @Test - @DisplayName("Verify factors are prime") - void verifyFactorsArePrime() { - long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - - for (long n : testNumbers) { - List factors = MathP36.primeFactorsMult(n); - assertTrue(factors.stream() - .allMatch(f -> MathP31.isPrime(f.factor())), - "All factors should be prime for " + n); - } - } - - @Test - @DisplayName("Verify factors are in ascending order") - void verifyFactorsAreOrdered() { - long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - - for (long n : testNumbers) { - List factors = MathP36.primeFactorsMult(n); - assertTrue(isAscending(factors), - "Factors should be in ascending order for " + n); - } - } + @Test + @DisplayName("Verify factors are in ascending order") + void verifyFactorsAreOrdered() { + long[] testNumbers = {12L, 315L, 1001L, 1024L, 123456L}; - private boolean isAscending(List factors) { - for (int i = 1; i < factors.size(); i++) { - if (factors.get(i).factor() <= factors.get(i-1).factor()) { - return false; - } - } - return true; + for (long n : testNumbers) { + List factors = MathP36.primeFactorsMult(n); + assertTrue(isAscending(factors), "Factors should be in ascending order for " + n); } + } - @Test - @DisplayName("Test toString representation") - void testToString() { - List factors = MathP36.primeFactorsMult(12); - assertEquals("(2 2)", factors.get(0).toString()); - assertEquals("(3 1)", factors.get(1).toString()); + private boolean isAscending(List factors) { + for (int i = 1; i < factors.size(); i++) { + if (factors.get(i).factor() <= factors.get(i - 1).factor()) { + return false; + } } + return true; + } + + @Test + @DisplayName("Test toString representation") + void testToString() { + List factors = MathP36.primeFactorsMult(12); + assertEquals("(2 2)", factors.get(0).toString()); + assertEquals("(3 1)", factors.get(1).toString()); + } } diff --git a/src/test/java/org/nintynine/problems/MathP37Test.java b/src/test/java/org/nintynine/problems/MathP37Test.java index ebc0ced..18804bb 100644 --- a/src/test/java/org/nintynine/problems/MathP37Test.java +++ b/src/test/java/org/nintynine/problems/MathP37Test.java @@ -1,119 +1,123 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.*; - class MathP37Test { - @ParameterizedTest(name = "φ({0}) = {1}") - @DisplayName("Test known totient values") - @CsvSource({ - "1, 1", // Special case - "2, 1", // Prime - "3, 2", // Prime - "4, 2", // Power of 2 - "6, 2", // Product of primes - "8, 4", // Power of 2 - "9, 6", // Perfect square - "10, 4", // Product of primes - "12, 4", // Multiple factors - "15, 8", // Product of primes - "16, 8", // Power of 2 - "20, 8", // Multiple factors - "25, 20", // Power of prime - "30, 8", // Multiple factors - "315, 144", // Example from P34 - "1024, 512" // Large power of 2 - }) - void testTotientPhi(long input, long expected) { - assertEquals(expected, MathP37.totientPhi(input)); - } + @ParameterizedTest(name = "φ({0}) = {1}") + @DisplayName("Test known totient values") + @CsvSource({ + "1, 1", // Special case + "2, 1", // Prime + "3, 2", // Prime + "4, 2", // Power of 2 + "6, 2", // Product of primes + "8, 4", // Power of 2 + "9, 6", // Perfect square + "10, 4", // Product of primes + "12, 4", // Multiple factors + "15, 8", // Product of primes + "16, 8", // Power of 2 + "20, 8", // Multiple factors + "25, 20", // Power of prime + "30, 8", // Multiple factors + "315, 144", // Example from P34 + "1024, 512" // Large power of 2 + }) + void testTotientPhi(long input, long expected) { + assertEquals(expected, MathP37.totientPhi(input)); + } - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(0)); - assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(-1)); - assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(-315)); - } + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(0)); + assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(-1)); + assertThrows(IllegalArgumentException.class, () -> MathP37.totientPhi(-315)); + } - @Test - @DisplayName("Test prime number properties") - void testPrimeNumberProperties() { - // For any prime p, φ(p) = p-1 - long[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; - for (long p : primes) { - assertEquals(p - 1, MathP37.totientPhi(p), - "For prime number " + p + ", φ(p) should be p-1"); - } + @Test + @DisplayName("Test prime number properties") + void testPrimeNumberProperties() { + // For any prime p, φ(p) = p-1 + long[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; + for (long p : primes) { + assertEquals(p - 1, MathP37.totientPhi(p), "For prime number " + p + ", φ(p) should be p-1"); } + } - @Test - @DisplayName("Test power of prime properties") - void testPowerOfPrimeProperties() { - // For p^n where p is prime, φ(p^n) = p^(n-1) * (p-1) - assertEquals(1, MathP37.totientPhi(2)); // 2^1 - assertEquals(2, MathP37.totientPhi(4)); // 2^2 - assertEquals(4, MathP37.totientPhi(8)); // 2^3 - assertEquals(8, MathP37.totientPhi(16)); // 2^4 - assertEquals(6, MathP37.totientPhi(9)); // 3^2 - assertEquals(18, MathP37.totientPhi(27)); // 3^3 - assertEquals(20, MathP37.totientPhi(25)); // 5^2 - } + @Test + @DisplayName("Test power of prime properties") + void testPowerOfPrimeProperties() { + // For p^n where p is prime, φ(p^n) = p^(n-1) * (p-1) + assertEquals(1, MathP37.totientPhi(2)); // 2^1 + assertEquals(2, MathP37.totientPhi(4)); // 2^2 + assertEquals(4, MathP37.totientPhi(8)); // 2^3 + assertEquals(8, MathP37.totientPhi(16)); // 2^4 + assertEquals(6, MathP37.totientPhi(9)); // 3^2 + assertEquals(18, MathP37.totientPhi(27)); // 3^3 + assertEquals(20, MathP37.totientPhi(25)); // 5^2 + } - @Test - @DisplayName("Test multiplicative property") - void testMultiplicativeProperty() { - // If a and b are coprime, then φ(a*b) = φ(a) * φ(b) - assertEquals(MathP37.totientPhi(15), - MathP37.totientPhi(3) * MathP37.totientPhi(5), - "φ(15) should equal φ(3) * φ(5)"); - - assertEquals(MathP37.totientPhi(21), - MathP37.totientPhi(3) * MathP37.totientPhi(7), - "φ(21) should equal φ(3) * φ(7)"); - } + @Test + @DisplayName("Test multiplicative property") + void testMultiplicativeProperty() { + // If a and b are coprime, then φ(a*b) = φ(a) * φ(b) + assertEquals( + MathP37.totientPhi(15), + MathP37.totientPhi(3) * MathP37.totientPhi(5), + "φ(15) should equal φ(3) * φ(5)"); - @Test - @DisplayName("Compare performance with primitive method") - void testPerformanceComparison() { - long[] testNumbers = {315L, 1024L, 12345L, 123456L}; - int iterations = 5; // Number of measurements to average - - for (long n : testNumbers) { - long totalPrimitive = 0; - long totalImproved = 0; - - // Take multiple measurements - for (int i = 0; i < iterations; i++) { - long[] times = MathP37.comparePerformance(n); - totalPrimitive += times[0]; - totalImproved += times[1]; - } - - // Calculate averages - double avgPrimitive = totalPrimitive / (double) iterations; - double avgImproved = totalImproved / (double) iterations; - - // Allow the improved method to be up to 5x slower to account for system variability - double toleranceFactor = 10.0; - - System.out.printf("Number %d: Avg Primitive: %.2fns, Avg Improved: %.2fns%n", - n, avgPrimitive, avgImproved); - - assertTrue(avgImproved <= avgPrimitive * toleranceFactor, - String.format("Improved method too slow: %.2fns vs %.2fns (tolerance: %.1fx)", avgImproved, avgPrimitive, toleranceFactor)); - } - } + assertEquals( + MathP37.totientPhi(21), + MathP37.totientPhi(3) * MathP37.totientPhi(7), + "φ(21) should equal φ(3) * φ(7)"); + } + + @Test + @DisplayName("Compare performance with primitive method") + void testPerformanceComparison() { + long[] testNumbers = {315L, 1024L, 12345L, 123456L}; + int iterations = 5; // Number of measurements to average + + for (long n : testNumbers) { + long totalPrimitive = 0; + long totalImproved = 0; + + // Take multiple measurements + for (int i = 0; i < iterations; i++) { + long[] times = MathP37.comparePerformance(n); + totalPrimitive += times[0]; + totalImproved += times[1]; + } - @Test - @DisplayName("Test larger numbers") - void testLargerNumbers() { - assertEquals(512, MathP37.totientPhi(1024)); // 2^10 - assertEquals(41088, MathP37.totientPhi(123456)); // Larger composite + // Calculate averages + double avgPrimitive = totalPrimitive / (double) iterations; + double avgImproved = totalImproved / (double) iterations; + + // Allow the improved method to be up to 5x slower to account for system variability + double toleranceFactor = 10.0; + + System.out.printf( + "Number %d: Avg Primitive: %.2fns, Avg Improved: %.2fns%n", n, avgPrimitive, avgImproved); + + assertTrue( + avgImproved <= avgPrimitive * toleranceFactor, + String.format( + "Improved method too slow: %.2fns vs %.2fns (tolerance: %.1fx)", + avgImproved, avgPrimitive, toleranceFactor)); } + } + + @Test + @DisplayName("Test larger numbers") + void testLargerNumbers() { + assertEquals(512, MathP37.totientPhi(1024)); // 2^10 + assertEquals(41088, MathP37.totientPhi(123456)); // Larger composite + } } diff --git a/src/test/java/org/nintynine/problems/MathP38Test.java b/src/test/java/org/nintynine/problems/MathP38Test.java index 84a781e..cfa4d01 100644 --- a/src/test/java/org/nintynine/problems/MathP38Test.java +++ b/src/test/java/org/nintynine/problems/MathP38Test.java @@ -1,69 +1,75 @@ package org.nintynine.problems; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; class MathP38Test { - @Test - @DisplayName("Compare methods for φ(10090)") - void testCompare10090() { - List results = MathP38.compare(10090); - - // Verify both methods give same result - assertEquals(results.get(0).result(), results.get(1).result(), - "Both methods should give the same result"); - - // Print detailed comparison - System.out.println("Performance comparison for φ(10090):"); - results.forEach(System.out::println); - - // Improved method should have fewer operations - assertTrue(results.get(1).arithmeticOps() < results.get(0).arithmeticOps(), - "Improved method should use fewer arithmetic operations"); - assertTrue(results.get(1).comparisonOps() < results.get(0).comparisonOps(), - "Improved method should use fewer comparisons"); - } - - @Test - @DisplayName("Compare methods for various numbers") - void testCompareVariousNumbers() { - long[] numbers = {100, 1000, 10090, 12345}; - - for (long n : numbers) { - List results = MathP38.compare(n); - - System.out.printf("%nPerformance comparison for φ(%d):%n", n); - results.forEach(System.out::println); - - // Verify results match - assertEquals(results.get(0).result(), results.get(1).result(), - "Results should match for n = " + n); - - // Verify improved method is more efficient - assertTrue(results.get(1).timeNanos() < results.get(0).timeNanos(), - "Improved method should be faster for n = " + n); - } - } - - @Test - @DisplayName("Test operation counting accuracy") - void testOperationCounting() { - // Test with small numbers where we can verify operation counts - List results = MathP38.compare(12); - - // Primitive method should have significant operations - assertTrue(results.get(0).arithmeticOps() > 20, - "Primitive method should have counted arithmetic operations"); - assertTrue(results.get(0).comparisonOps() > 10, - "Primitive method should have counted comparisons"); - - // Improved method should have fewer operations - assertTrue(results.get(1).arithmeticOps() < results.get(0).arithmeticOps(), - "Improved method should use fewer arithmetic operations"); + @Test + @DisplayName("Compare methods for φ(10090)") + void testCompare10090() { + List results = MathP38.compare(10090); + + // Verify both methods give same result + assertEquals( + results.get(0).result(), + results.get(1).result(), + "Both methods should give the same result"); + + // Print detailed comparison + System.out.println("Performance comparison for φ(10090):"); + results.forEach(System.out::println); + + // Improved method should have fewer operations + assertTrue( + results.get(1).arithmeticOps() < results.get(0).arithmeticOps(), + "Improved method should use fewer arithmetic operations"); + assertTrue( + results.get(1).comparisonOps() < results.get(0).comparisonOps(), + "Improved method should use fewer comparisons"); + } + + @Test + @DisplayName("Compare methods for various numbers") + void testCompareVariousNumbers() { + long[] numbers = {100, 1000, 10090, 12345}; + + for (long n : numbers) { + List results = MathP38.compare(n); + + System.out.printf("%nPerformance comparison for φ(%d):%n", n); + results.forEach(System.out::println); + + // Verify results match + assertEquals( + results.get(0).result(), results.get(1).result(), "Results should match for n = " + n); + + // Verify improved method is more efficient + assertTrue( + results.get(1).timeNanos() < results.get(0).timeNanos(), + "Improved method should be faster for n = " + n); } + } + + @Test + @DisplayName("Test operation counting accuracy") + void testOperationCounting() { + // Test with small numbers where we can verify operation counts + List results = MathP38.compare(12); + + // Primitive method should have significant operations + assertTrue( + results.get(0).arithmeticOps() > 20, + "Primitive method should have counted arithmetic operations"); + assertTrue( + results.get(0).comparisonOps() > 10, "Primitive method should have counted comparisons"); + + // Improved method should have fewer operations + assertTrue( + results.get(1).arithmeticOps() < results.get(0).arithmeticOps(), + "Improved method should use fewer arithmetic operations"); + } } diff --git a/src/test/java/org/nintynine/problems/MathP39Test.java b/src/test/java/org/nintynine/problems/MathP39Test.java index 9e77c31..4a51bc3 100644 --- a/src/test/java/org/nintynine/problems/MathP39Test.java +++ b/src/test/java/org/nintynine/problems/MathP39Test.java @@ -1,143 +1,136 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - class MathP39Test { - @Test - @DisplayName("Test small ranges") - void testSmallRanges() { - // Test [1,10] - List primes = MathP39.primesInRange(1, 10); - assertEquals(List.of(2L, 3L, 5L, 7L), primes); - - // Test [10,20] - primes = MathP39.primesInRange(10, 20); - assertEquals(List.of(11L, 13L, 17L, 19L), primes); - - // Test [95,100] - primes = MathP39.primesInRange(95, 100); - assertEquals(List.of(97L), primes); - } - - @Test - @DisplayName("Test range starting with prime") - void testRangeStartingWithPrime() { - List primes = MathP39.primesInRange(17, 30); - assertEquals(List.of(17L, 19L, 23L, 29L), primes); - } - - @Test - @DisplayName("Test range ending with prime") - void testRangeEndingWithPrime() { - List primes = MathP39.primesInRange(20, 23); - assertEquals(List.of(23L), primes); - } - - @Test - @DisplayName("Test invalid ranges") - void testInvalidRanges() { - assertThrows(IllegalArgumentException.class, - () -> MathP39.primesInRange(10, 5)); - assertThrows(IllegalArgumentException.class, - () -> MathP39.primesInRange(-5, 10)); - } - - @Test - @DisplayName("Test edge cases") - void testEdgeCases() { - // Empty range - assertTrue(MathP39.primesInRange(0, 1).isEmpty()); - - // Single number range - assertEquals(List.of(2L), MathP39.primesInRange(2, 2)); - - // Range with no primes - assertTrue(MathP39.primesInRange(24, 28).isEmpty()); - } - - @ParameterizedTest(name = "Range [{0}, {1}] should contain {2} primes") - @CsvSource({ - "1, 10, 4", - "1, 100, 25", - "100, 200, 21", - "1000, 1100, 16", - "9900, 10000, 9", - "9900, 100000, 8372" - }) - void testPrimeCount(long start, long end, long expectedCount) { - assertEquals(expectedCount, MathP39.countPrimesInRange(start, end)); - assertEquals(expectedCount, MathP39.primesInRange(start, end).size()); - } - - @Test - @DisplayName("Test larger ranges") - void testLargerRanges() { - // Test performance and correctness for larger ranges - long start = System.nanoTime(); - List primes = MathP39.primesInRange(10000, 101000000); - long end = System.nanoTime(); - - // Verify some known primes in this range - assertTrue(primes.contains(10007L)); - assertTrue(primes.contains(10009L)); - assertTrue(primes.contains(10037L)); - - // Print performance info - System.out.printf("Generated primes in range [10000,10100] in %.3f ms%n", - (end - start) / 1_000_000.0); - } - - @Test - @DisplayName("Test prime number properties") - void testPrimeProperties() { - List primes = MathP39.primesInRange(2, 100); - - // All numbers should be prime - for (long prime : primes) { - assertTrue(MathP31.isPrime(prime), - prime + " should be prime"); - } - - // Should include known twin primes - List twinPrimes = List.of(3L, 5L, 7L, 11L, 13L, 17L, 19L, 29L, 31L); - assertTrue(primes.containsAll(twinPrimes)); - - // Should not include known composites - List composites = List.of(4L, 6L, 8L, 9L, 10L, 12L, 14L, 15L, 16L); - composites.forEach(n -> assertFalse(primes.contains(n), - n + " should not be in the list")); + @Test + @DisplayName("Test small ranges") + void testSmallRanges() { + // Test [1,10] + List primes = MathP39.primesInRange(1, 10); + assertEquals(List.of(2L, 3L, 5L, 7L), primes); + + // Test [10,20] + primes = MathP39.primesInRange(10, 20); + assertEquals(List.of(11L, 13L, 17L, 19L), primes); + + // Test [95,100] + primes = MathP39.primesInRange(95, 100); + assertEquals(List.of(97L), primes); + } + + @Test + @DisplayName("Test range starting with prime") + void testRangeStartingWithPrime() { + List primes = MathP39.primesInRange(17, 30); + assertEquals(List.of(17L, 19L, 23L, 29L), primes); + } + + @Test + @DisplayName("Test range ending with prime") + void testRangeEndingWithPrime() { + List primes = MathP39.primesInRange(20, 23); + assertEquals(List.of(23L), primes); + } + + @Test + @DisplayName("Test invalid ranges") + void testInvalidRanges() { + assertThrows(IllegalArgumentException.class, () -> MathP39.primesInRange(10, 5)); + assertThrows(IllegalArgumentException.class, () -> MathP39.primesInRange(-5, 10)); + } + + @Test + @DisplayName("Test edge cases") + void testEdgeCases() { + // Empty range + assertTrue(MathP39.primesInRange(0, 1).isEmpty()); + + // Single number range + assertEquals(List.of(2L), MathP39.primesInRange(2, 2)); + + // Range with no primes + assertTrue(MathP39.primesInRange(24, 28).isEmpty()); + } + + @ParameterizedTest(name = "Range [{0}, {1}] should contain {2} primes") + @CsvSource({ + "1, 10, 4", + "1, 100, 25", + "100, 200, 21", + "1000, 1100, 16", + "9900, 10000, 9", + "9900, 100000, 8372" + }) + void testPrimeCount(long start, long end, long expectedCount) { + assertEquals(expectedCount, MathP39.countPrimesInRange(start, end)); + assertEquals(expectedCount, MathP39.primesInRange(start, end).size()); + } + + @Test + @DisplayName("Test larger ranges") + void testLargerRanges() { + // Test performance and correctness for larger ranges + long start = System.nanoTime(); + List primes = MathP39.primesInRange(10000, 101000000); + long end = System.nanoTime(); + + // Verify some known primes in this range + assertTrue(primes.contains(10007L)); + assertTrue(primes.contains(10009L)); + assertTrue(primes.contains(10037L)); + + // Print performance info + System.out.printf( + "Generated primes in range [10000,10100] in %.3f ms%n", (end - start) / 1_000_000.0); + } + + @Test + @DisplayName("Test prime number properties") + void testPrimeProperties() { + List primes = MathP39.primesInRange(2, 100); + + // All numbers should be prime + for (long prime : primes) { + assertTrue(MathP31.isPrime(prime), prime + " should be prime"); } - @Test - @DisplayName("Test segmented sieve consistency") - void testSegmentedSieveConsistency() { - // Test different segment boundaries - long[][] ranges = { - {1000, 1100}, - {9900, 10100}, - {99900, 100100} - }; - - for (long[] range : ranges) { - List primes = MathP39.primesInRange(range[0], range[1]); - - // Verify all numbers are prime - for (long prime : primes) { - assertTrue(MathP31.isPrime(prime), - prime + " should be prime"); - } - - // Verify count matches direct counting - assertEquals(primes.size(), - MathP39.countPrimesInRange(range[0], range[1])); - } + // Should include known twin primes + List twinPrimes = List.of(3L, 5L, 7L, 11L, 13L, 17L, 19L, 29L, 31L); + assertTrue(primes.containsAll(twinPrimes)); + + // Should not include known composites + List composites = List.of(4L, 6L, 8L, 9L, 10L, 12L, 14L, 15L, 16L); + composites.forEach(n -> assertFalse(primes.contains(n), n + " should not be in the list")); + } + + @Test + @DisplayName("Test segmented sieve consistency") + void testSegmentedSieveConsistency() { + // Test different segment boundaries + long[][] ranges = { + {1000, 1100}, + {9900, 10100}, + {99900, 100100} + }; + + for (long[] range : ranges) { + List primes = MathP39.primesInRange(range[0], range[1]); + + // Verify all numbers are prime + for (long prime : primes) { + assertTrue(MathP31.isPrime(prime), prime + " should be prime"); + } + + // Verify count matches direct counting + assertEquals(primes.size(), MathP39.countPrimesInRange(range[0], range[1])); } + } } diff --git a/src/test/java/org/nintynine/problems/MathP40Test.java b/src/test/java/org/nintynine/problems/MathP40Test.java index 866f736..c3e680e 100644 --- a/src/test/java/org/nintynine/problems/MathP40Test.java +++ b/src/test/java/org/nintynine/problems/MathP40Test.java @@ -1,144 +1,138 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; - class MathP40Test { - @Test - @DisplayName("Test example case: 28 = 5 + 23") - void testExample() { - Optional result = MathP40.goldbach(28); - assertTrue(result.isPresent()); - assertEquals(5, result.get().prime1()); - assertEquals(23, result.get().prime2()); - } - - @Test - @DisplayName("Test small even numbers") - void testSmallEvenNumbers() { - // 4 = 2 + 2 - Optional result = MathP40.goldbach(4); - assertTrue(result.isPresent()); - assertEquals(2, result.get().prime1()); - assertEquals(2, result.get().prime2()); - - // 6 = 3 + 3 - result = MathP40.goldbach(6); - assertTrue(result.isPresent()); - assertEquals(3, result.get().prime1()); - assertEquals(3, result.get().prime2()); - - // 8 = 3 + 5 - result = MathP40.goldbach(8); - assertTrue(result.isPresent()); - assertEquals(3, result.get().prime1()); - assertEquals(5, result.get().prime2()); - } - - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - // Test numbers <= 2 - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(2)); - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(1)); - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(0)); - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(-4)); - - // Test odd numbers - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(7)); - assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(15)); - } - - @Test - @DisplayName("Test finding all Goldbach pairs") - void testGoldbachAll() { - // Test 10 = 3 + 7 = 5 + 5 - MathP40.GoldbachPair[] pairs = MathP40.goldbachAll(10); - assertEquals(2, pairs.length); - assertEquals(3, pairs[0].prime1()); - assertEquals(7, pairs[0].prime2()); - assertEquals(5, pairs[1].prime1()); - assertEquals(5, pairs[1].prime2()); - - // Test 20 = 3 + 17 = 7 + 13 - pairs = MathP40.goldbachAll(20); - assertEquals(2, pairs.length); - assertEquals(3, pairs[0].prime1()); - assertEquals(17, pairs[0].prime2()); - assertEquals(7, pairs[1].prime1()); - assertEquals(13, pairs[1].prime2()); - } - - @ParameterizedTest - @DisplayName("Verify Goldbach's conjecture up to various limits") - @ValueSource(ints = {100, 500, 1000}) - void testVerifyGoldbachUpTo(int limit) { - assertTrue(MathP40.verifyGoldbachUpTo(limit), - "Goldbach's conjecture should hold up to " + limit); - } - - @Test - @DisplayName("Test GoldbachPair properties") - void testGoldbachPairProperties() { - Optional result = MathP40.goldbach(28); - assertTrue(result.isPresent()); - MathP40.GoldbachPair pair = result.get(); - - // Test sum is correct - assertEquals(28, pair.prime1() + pair.prime2()); - - // Test both numbers are prime - assertTrue(MathP31.isPrime(pair.prime1())); - assertTrue(MathP31.isPrime(pair.prime2())); - - // Test toString format - assertEquals("(5 23)", pair.toString()); - - // Test isValid - assertTrue(pair.isValid()); + @Test + @DisplayName("Test example case: 28 = 5 + 23") + void testExample() { + Optional result = MathP40.goldbach(28); + assertTrue(result.isPresent()); + assertEquals(5, result.get().prime1()); + assertEquals(23, result.get().prime2()); + } + + @Test + @DisplayName("Test small even numbers") + void testSmallEvenNumbers() { + // 4 = 2 + 2 + Optional result = MathP40.goldbach(4); + assertTrue(result.isPresent()); + assertEquals(2, result.get().prime1()); + assertEquals(2, result.get().prime2()); + + // 6 = 3 + 3 + result = MathP40.goldbach(6); + assertTrue(result.isPresent()); + assertEquals(3, result.get().prime1()); + assertEquals(3, result.get().prime2()); + + // 8 = 3 + 5 + result = MathP40.goldbach(8); + assertTrue(result.isPresent()); + assertEquals(3, result.get().prime1()); + assertEquals(5, result.get().prime2()); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + // Test numbers <= 2 + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(2)); + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(1)); + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(0)); + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(-4)); + + // Test odd numbers + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(7)); + assertThrows(IllegalArgumentException.class, () -> MathP40.goldbach(15)); + } + + @Test + @DisplayName("Test finding all Goldbach pairs") + void testGoldbachAll() { + // Test 10 = 3 + 7 = 5 + 5 + MathP40.GoldbachPair[] pairs = MathP40.goldbachAll(10); + assertEquals(2, pairs.length); + assertEquals(3, pairs[0].prime1()); + assertEquals(7, pairs[0].prime2()); + assertEquals(5, pairs[1].prime1()); + assertEquals(5, pairs[1].prime2()); + + // Test 20 = 3 + 17 = 7 + 13 + pairs = MathP40.goldbachAll(20); + assertEquals(2, pairs.length); + assertEquals(3, pairs[0].prime1()); + assertEquals(17, pairs[0].prime2()); + assertEquals(7, pairs[1].prime1()); + assertEquals(13, pairs[1].prime2()); + } + + @ParameterizedTest + @DisplayName("Verify Goldbach's conjecture up to various limits") + @ValueSource(ints = {100, 500, 1000}) + void testVerifyGoldbachUpTo(int limit) { + assertTrue( + MathP40.verifyGoldbachUpTo(limit), "Goldbach's conjecture should hold up to " + limit); + } + + @Test + @DisplayName("Test GoldbachPair properties") + void testGoldbachPairProperties() { + Optional result = MathP40.goldbach(28); + assertTrue(result.isPresent()); + MathP40.GoldbachPair pair = result.get(); + + // Test sum is correct + assertEquals(28, pair.prime1() + pair.prime2()); + + // Test both numbers are prime + assertTrue(MathP31.isPrime(pair.prime1())); + assertTrue(MathP31.isPrime(pair.prime2())); + + // Test toString format + assertEquals("(5 23)", pair.toString()); + + // Test isValid + assertTrue(pair.isValid()); + } + + @Test + @DisplayName("Test larger even numbers") + void testLargerEvenNumbers() { + long[] numbers = {100, 200, 500, 1000}; + + for (long n : numbers) { + Optional result = MathP40.goldbach(n); + assertTrue(result.isPresent(), "Should find Goldbach pair for " + n); + + MathP40.GoldbachPair pair = result.get(); + assertEquals(n, pair.prime1() + pair.prime2(), "Sum should equal original number"); + assertTrue(pair.isValid(), "Should be valid Goldbach pair"); } + } - @Test - @DisplayName("Test larger even numbers") - void testLargerEvenNumbers() { - long[] numbers = {100, 200, 500, 1000}; - - for (long n : numbers) { - Optional result = MathP40.goldbach(n); - assertTrue(result.isPresent(), - "Should find Goldbach pair for " + n); - - MathP40.GoldbachPair pair = result.get(); - assertEquals(n, pair.prime1() + pair.prime2(), - "Sum should equal original number"); - assertTrue(pair.isValid(), - "Should be valid Goldbach pair"); - } - } - - @Test - @DisplayName("Test performance") - void testPerformance() { - long startTime = System.nanoTime(); + @Test + @DisplayName("Test performance") + void testPerformance() { + long startTime = System.nanoTime(); - // Verify conjecture up to 10000 - assertTrue(MathP40.verifyGoldbachUpTo(10000)); + // Verify conjecture up to 10000 + assertTrue(MathP40.verifyGoldbachUpTo(10000)); - long endTime = System.nanoTime(); - double seconds = (endTime - startTime) / 1_000_000_000.0; + long endTime = System.nanoTime(); + double seconds = (endTime - startTime) / 1_000_000_000.0; - System.out.printf("Verified Goldbach's conjecture up to 10000 in %.3f seconds%n", - seconds); + System.out.printf("Verified Goldbach's conjecture up to 10000 in %.3f seconds%n", seconds); - // Should complete in reasonable time - assertTrue(seconds < 1.0, - "Verification should complete in less than 1 second"); - } + // Should complete in reasonable time + assertTrue(seconds < 1.0, "Verification should complete in less than 1 second"); + } } diff --git a/src/test/java/org/nintynine/problems/MathP41Test.java b/src/test/java/org/nintynine/problems/MathP41Test.java index b0ad88b..343e5ca 100644 --- a/src/test/java/org/nintynine/problems/MathP41Test.java +++ b/src/test/java/org/nintynine/problems/MathP41Test.java @@ -1,104 +1,99 @@ package org.nintynine.problems; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; class MathP41Test { - @Test - @DisplayName("Test example range 9 to 20") - void testExampleRange() { - List result = MathP41.goldbachList(9, 20); - - // Verify specific compositions - assertEquals(6, result.size()); - assertEquals("10 = 3 + 7", result.get(0).toString()); - assertEquals("12 = 5 + 7", result.get(1).toString()); - assertEquals("14 = 3 + 11", result.get(2).toString()); - assertEquals("16 = 3 + 13", result.get(3).toString()); - assertEquals("18 = 5 + 13", result.get(4).toString()); - assertEquals("20 = 3 + 17", result.get(5).toString()); - } - - @Test - @DisplayName("Test compositions with minimum prime 50") - void testLargePrimeCompositions() { - List result = - MathP41.goldbachList(1, 2000, 50); - - // Print results - System.out.println("Goldbach compositions with primes > 50:"); - System.out.println(MathP41.formatGoldbachList(result)); - - // Verify all compositions have primes > 50 - result.forEach(entry -> { - assertTrue(entry.pair().prime1() > 50, - "First prime should be > 50"); - assertTrue(entry.pair().prime2() > 50, - "Second prime should be > 50"); + @Test + @DisplayName("Test example range 9 to 20") + void testExampleRange() { + List result = MathP41.goldbachList(9, 20); + + // Verify specific compositions + assertEquals(6, result.size()); + assertEquals("10 = 3 + 7", result.get(0).toString()); + assertEquals("12 = 5 + 7", result.get(1).toString()); + assertEquals("14 = 3 + 11", result.get(2).toString()); + assertEquals("16 = 3 + 13", result.get(3).toString()); + assertEquals("18 = 5 + 13", result.get(4).toString()); + assertEquals("20 = 3 + 17", result.get(5).toString()); + } + + @Test + @DisplayName("Test compositions with minimum prime 50") + void testLargePrimeCompositions() { + List result = MathP41.goldbachList(1, 2000, 50); + + // Print results + System.out.println("Goldbach compositions with primes > 50:"); + System.out.println(MathP41.formatGoldbachList(result)); + + // Verify all compositions have primes > 50 + result.forEach( + entry -> { + assertTrue(entry.pair().prime1() > 50, "First prime should be > 50"); + assertTrue(entry.pair().prime2() > 50, "Second prime should be > 50"); }); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MathP41.goldbachList(20, 10)); + assertThrows(IllegalArgumentException.class, () -> MathP41.goldbachList(-5, 10)); + assertThrows(IllegalArgumentException.class, () -> MathP41.goldbachList(10, 20, -1)); + } + + @Test + @DisplayName("Test count of rare compositions") + void testRareCompositions() { + long count = MathP41.countGoldbachCompositions(2, 3000, 50); + System.out.printf( + "Found %d Goldbach compositions with both primes > 50 " + "in range 2..3000%n", count); + + // There should be relatively few such compositions + assertFalse(count < 100, "Should be relatively few compositions with both primes > 50"); + } + + @Test + @DisplayName("Test empty ranges") + void testEmptyRanges() { + // Range below 4 should be empty (no even numbers that are sums of primes) + assertTrue(MathP41.goldbachList(1, 3).isEmpty()); + + // Range with minimum prime too high for the numbers + assertTrue(MathP41.goldbachList(10, 20, 15).isEmpty()); + } + + @Test + @DisplayName("Test continuous range verification") + void testContinuousRange() { + List result = MathP41.goldbachList(4, 30); + + // Verify each even number has a composition + for (long i = 4; i <= 30; i += 2) { + final long n = i; + assertTrue( + result.stream().anyMatch(entry -> entry.number() == n), + "Should find composition for " + n); } - - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, - () -> MathP41.goldbachList(20, 10)); - assertThrows(IllegalArgumentException.class, - () -> MathP41.goldbachList(-5, 10)); - assertThrows(IllegalArgumentException.class, - () -> MathP41.goldbachList(10, 20, -1)); - } - - @Test - @DisplayName("Test count of rare compositions") - void testRareCompositions() { - long count = MathP41.countGoldbachCompositions(2, 3000, 50); - System.out.printf("Found %d Goldbach compositions with both primes > 50 " + - "in range 2..3000%n", count); - - // There should be relatively few such compositions - assertFalse(count < 100, - "Should be relatively few compositions with both primes > 50"); - } - - @Test - @DisplayName("Test empty ranges") - void testEmptyRanges() { - // Range below 4 should be empty (no even numbers that are sums of primes) - assertTrue(MathP41.goldbachList(1, 3).isEmpty()); - - // Range with minimum prime too high for the numbers - assertTrue(MathP41.goldbachList(10, 20, 15).isEmpty()); - } - - @Test - @DisplayName("Test continuous range verification") - void testContinuousRange() { - List result = MathP41.goldbachList(4, 30); - - // Verify each even number has a composition - for (long i = 4; i <= 30; i += 2) { - final long n = i; - assertTrue(result.stream() - .anyMatch(entry -> entry.number() == n), - "Should find composition for " + n); - } - } - - @Test - @DisplayName("Test formatting") - void testFormatting() { - List result = MathP41.goldbachList(10, 14); - String formatted = MathP41.formatGoldbachList(result); - - assertEquals(""" - 10 = 3 + 7 - 12 = 5 + 7 - 14 = 3 + 11""", formatted); - } + } + + @Test + @DisplayName("Test formatting") + void testFormatting() { + List result = MathP41.goldbachList(10, 14); + String formatted = MathP41.formatGoldbachList(result); + + assertEquals( + """ + 10 = 3 + 7 + 12 = 5 + 7 + 14 = 3 + 11""", + formatted); + } } diff --git a/src/test/java/org/nintynine/problems/MathP43Test.java b/src/test/java/org/nintynine/problems/MathP43Test.java index d0aaeca..b26ae92 100644 --- a/src/test/java/org/nintynine/problems/MathP43Test.java +++ b/src/test/java/org/nintynine/problems/MathP43Test.java @@ -1,105 +1,102 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - class MathP43Test { - @BeforeEach - void setUp() { - MathP43.clearCache(); - } - - @Test - @DisplayName("Test 1-bit Gray code") - void testOneBitGrayCode() { - List result = MathP43.gray(1); - assertEquals(List.of("0", "1"), result); - } - - @Test - @DisplayName("Test 2-bit Gray code") - void testTwoBitGrayCode() { - List result = MathP43.gray(2); - assertEquals(List.of("00", "01", "11", "10"), result); - } - - @Test - @DisplayName("Test 3-bit Gray code") - void testThreeBitGrayCode() { - List result = MathP43.gray(3); - assertEquals(List.of( - "000", "001", "011", "010", - "110", "111", "101", "100" - ), result); - } - - @Test - @DisplayName("Test invalid input") - void testInvalidInput() { - assertThrows(IllegalArgumentException.class, - () -> MathP43.gray(0)); - assertThrows(IllegalArgumentException.class, - () -> MathP43.gray(-1)); - } - - @Test - @DisplayName("Test Gray code properties") - void testGrayCodeProperties() { - List codes = MathP43.gray(4); - - // Size should be 2^n - assertEquals(16, codes.size()); - - // Adjacent codes should differ by exactly one bit - for (int i = 0; i < codes.size() - 1; i++) { - assertEquals(1, hammingDistance(codes.get(i), codes.get(i + 1)), - "Adjacent codes should differ by exactly one bit"); - } - - // The first and last codes should differ by one bit - assertEquals(1, hammingDistance(codes.getFirst(), codes.getLast()), - "First and last codes should differ by exactly one bit"); - } - - @Test - @DisplayName("Test caching mechanism") - void testCaching() { - assertEquals(0, MathP43.getCacheSize()); - - MathP43.gray(3); - assertEquals(3, MathP43.getCacheSize()); // Should cache n=1,2,3 - - MathP43.gray(3); // Should use cache - assertEquals(3, MathP43.getCacheSize()); - - MathP43.gray(4); - assertEquals(4, MathP43.getCacheSize()); - } - - @ParameterizedTest(name = "Test Gray code size for {0} bits") - @ValueSource(ints = {1, 2, 3, 4, 5}) - void testGrayCodeSize(int n) { - List codes = MathP43.gray(n); - assertEquals(1 << n, codes.size(), - "Gray code size should be 2^n"); + @BeforeEach + void setUp() { + MathP43.clearCache(); + } + + @Test + @DisplayName("Test 1-bit Gray code") + void testOneBitGrayCode() { + List result = MathP43.gray(1); + assertEquals(List.of("0", "1"), result); + } + + @Test + @DisplayName("Test 2-bit Gray code") + void testTwoBitGrayCode() { + List result = MathP43.gray(2); + assertEquals(List.of("00", "01", "11", "10"), result); + } + + @Test + @DisplayName("Test 3-bit Gray code") + void testThreeBitGrayCode() { + List result = MathP43.gray(3); + assertEquals(List.of("000", "001", "011", "010", "110", "111", "101", "100"), result); + } + + @Test + @DisplayName("Test invalid input") + void testInvalidInput() { + assertThrows(IllegalArgumentException.class, () -> MathP43.gray(0)); + assertThrows(IllegalArgumentException.class, () -> MathP43.gray(-1)); + } + + @Test + @DisplayName("Test Gray code properties") + void testGrayCodeProperties() { + List codes = MathP43.gray(4); + + // Size should be 2^n + assertEquals(16, codes.size()); + + // Adjacent codes should differ by exactly one bit + for (int i = 0; i < codes.size() - 1; i++) { + assertEquals( + 1, + hammingDistance(codes.get(i), codes.get(i + 1)), + "Adjacent codes should differ by exactly one bit"); } - // Helper method to calculate Hamming distance between two binary strings - private int hammingDistance(String s1, String s2) { - int distance = 0; - for (int i = 0; i < s1.length(); i++) { - if (s1.charAt(i) != s2.charAt(i)) { - distance++; - } - } - return distance; + // The first and last codes should differ by one bit + assertEquals( + 1, + hammingDistance(codes.getFirst(), codes.getLast()), + "First and last codes should differ by exactly one bit"); + } + + @Test + @DisplayName("Test caching mechanism") + void testCaching() { + assertEquals(0, MathP43.getCacheSize()); + + MathP43.gray(3); + assertEquals(3, MathP43.getCacheSize()); // Should cache n=1,2,3 + + MathP43.gray(3); // Should use cache + assertEquals(3, MathP43.getCacheSize()); + + MathP43.gray(4); + assertEquals(4, MathP43.getCacheSize()); + } + + @ParameterizedTest(name = "Test Gray code size for {0} bits") + @ValueSource(ints = {1, 2, 3, 4, 5}) + void testGrayCodeSize(int n) { + List codes = MathP43.gray(n); + assertEquals(1 << n, codes.size(), "Gray code size should be 2^n"); + } + + // Helper method to calculate Hamming distance between two binary strings + private int hammingDistance(String s1, String s2) { + int distance = 0; + for (int i = 0; i < s1.length(); i++) { + if (s1.charAt(i) != s2.charAt(i)) { + distance++; + } } + return distance; + } } diff --git a/src/test/java/org/nintynine/problems/MathP50Test.java b/src/test/java/org/nintynine/problems/MathP50Test.java index 9fc621e..fa58322 100644 --- a/src/test/java/org/nintynine/problems/MathP50Test.java +++ b/src/test/java/org/nintynine/problems/MathP50Test.java @@ -1,159 +1,145 @@ package org.nintynine.problems; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; class MathP50Test { - @Test - @DisplayName("Test example from problem description") - void testExampleCase() { - List frequencies = List.of( - new MathP50.FrequencyEntry("a", 45), - new MathP50.FrequencyEntry("b", 13), - new MathP50.FrequencyEntry("c", 12), - new MathP50.FrequencyEntry("d", 16), - new MathP50.FrequencyEntry("e", 9), - new MathP50.FrequencyEntry("f", 5) - ); - - List codes = MathP50.huffman(frequencies); - - // Verify properties of the generated codes - assertValidHuffmanCodes(codes, frequencies); + @Test + @DisplayName("Test example from problem description") + void testExampleCase() { + List frequencies = + List.of( + new MathP50.FrequencyEntry("a", 45), + new MathP50.FrequencyEntry("b", 13), + new MathP50.FrequencyEntry("c", 12), + new MathP50.FrequencyEntry("d", 16), + new MathP50.FrequencyEntry("e", 9), + new MathP50.FrequencyEntry("f", 5)); + + List codes = MathP50.huffman(frequencies); + + // Verify properties of the generated codes + assertValidHuffmanCodes(codes, frequencies); + } + + @Test + @DisplayName("Test single symbol case") + void testSingleSymbol() { + List frequencies = List.of(new MathP50.FrequencyEntry("a", 1)); + + List codes = MathP50.huffman(frequencies); + assertEquals(1, codes.size()); + assertEquals("0", codes.getFirst().code()); + } + + @Test + @DisplayName("Test two symbols case") + void testTwoSymbols() { + List frequencies = + List.of(new MathP50.FrequencyEntry("a", 1), new MathP50.FrequencyEntry("b", 1)); + + List codes = MathP50.huffman(frequencies); + assertEquals(2, codes.size()); + assertNotEquals(codes.get(0).code(), codes.get(1).code()); + } + + @Test + @DisplayName("Test invalid inputs") + void testInvalidInputs() { + List emptyFreq = List.of(); + assertThrows(IllegalArgumentException.class, () -> MathP50.huffman(emptyFreq)); + + assertThrows(IllegalArgumentException.class, () -> MathP50.huffman(null)); + + assertThrows(IllegalArgumentException.class, () -> new MathP50.FrequencyEntry("a", -1)); + + assertThrows(NullPointerException.class, () -> new MathP50.FrequencyEntry(null, 1)); + } + + @Test + @DisplayName("Test encoding and decoding") + void testEncodingDecoding() { + List frequencies = + List.of( + new MathP50.FrequencyEntry("a", 45), + new MathP50.FrequencyEntry("b", 13), + new MathP50.FrequencyEntry("c", 12)); + + List codes = MathP50.huffman(frequencies); + MathP50.HuffmanDecoder decoder = MathP50.createDecoder(codes); + + // Create a mapping for encoding + Map encodeMap = new HashMap<>(); + codes.forEach(code -> encodeMap.put(code.symbol(), code.code())); + + // Test message + String message = "abcabc"; + StringBuilder encoded = new StringBuilder(); + for (char c : message.toCharArray()) { + encoded.append(encodeMap.get(String.valueOf(c))); } - @Test - @DisplayName("Test single symbol case") - void testSingleSymbol() { - List frequencies = List.of( - new MathP50.FrequencyEntry("a", 1) - ); + assertEquals(message, decoder.decode(encoded.toString())); + } - List codes = MathP50.huffman(frequencies); - assertEquals(1, codes.size()); - assertEquals("0", codes.getFirst().code()); - } - - @Test - @DisplayName("Test two symbols case") - void testTwoSymbols() { - List frequencies = List.of( - new MathP50.FrequencyEntry("a", 1), - new MathP50.FrequencyEntry("b", 1) - ); - - List codes = MathP50.huffman(frequencies); - assertEquals(2, codes.size()); - assertNotEquals(codes.get(0).code(), codes.get(1).code()); - } + @Test + @DisplayName("Test decoder with invalid input") + void testDecoderInvalidInput() { + List codes = + List.of(new MathP50.HuffmanCode("a", "0"), new MathP50.HuffmanCode("b", "1")); - @Test - @DisplayName("Test invalid inputs") - void testInvalidInputs() { - List emptyFreq = List.of(); - assertThrows(IllegalArgumentException.class, - () -> MathP50.huffman(emptyFreq)); + MathP50.HuffmanDecoder decoder = MathP50.createDecoder(codes); - assertThrows(IllegalArgumentException.class, - () -> MathP50.huffman(null)); + assertThrows(IllegalArgumentException.class, () -> decoder.decode("2")); + assertThrows(IllegalArgumentException.class, () -> decoder.decode("01x")); + assertThrows( + IllegalArgumentException.class, () -> decoder.decode("ena")); // Invalid code sequence + } - assertThrows(IllegalArgumentException.class, - () -> new MathP50.FrequencyEntry("a", -1)); + private void assertValidHuffmanCodes( + List codes, List frequencies) { + // Check that we have a code for each symbol + assertEquals(frequencies.size(), codes.size()); - assertThrows(NullPointerException.class, - () -> new MathP50.FrequencyEntry(null, 1)); + // Check that codes are unique + Set uniqueCodes = new HashSet<>(); + for (MathP50.HuffmanCode code : codes) { + assertTrue(uniqueCodes.add(code.code()), "Codes must be unique"); } - @Test - @DisplayName("Test encoding and decoding") - void testEncodingDecoding() { - List frequencies = List.of( - new MathP50.FrequencyEntry("a", 45), - new MathP50.FrequencyEntry("b", 13), - new MathP50.FrequencyEntry("c", 12) - ); - - List codes = MathP50.huffman(frequencies); - MathP50.HuffmanDecoder decoder = MathP50.createDecoder(codes); - - // Create a mapping for encoding - Map encodeMap = new HashMap<>(); - codes.forEach(code -> encodeMap.put(code.symbol(), code.code())); - - // Test message - String message = "abcabc"; - StringBuilder encoded = new StringBuilder(); - for (char c : message.toCharArray()) { - encoded.append(encodeMap.get(String.valueOf(c))); + // Check prefix property + for (MathP50.HuffmanCode code1 : codes) { + for (MathP50.HuffmanCode code2 : codes) { + if (code1 != code2) { + assertFalse( + code1.code().startsWith(code2.code()), "No code should be a prefix of another code"); } - - assertEquals(message, decoder.decode(encoded.toString())); - } - - @Test - @DisplayName("Test decoder with invalid input") - void testDecoderInvalidInput() { - List codes = List.of( - new MathP50.HuffmanCode("a", "0"), - new MathP50.HuffmanCode("b", "1") - ); - - MathP50.HuffmanDecoder decoder = MathP50.createDecoder(codes); - - assertThrows(IllegalArgumentException.class, - () -> decoder.decode("2")); - assertThrows(IllegalArgumentException.class, - () -> decoder.decode("01x")); - assertThrows(IllegalArgumentException.class, - () -> decoder.decode("ena")); // Invalid code sequence + } } - private void assertValidHuffmanCodes( - List codes, - List frequencies) { - // Check that we have a code for each symbol - assertEquals(frequencies.size(), codes.size()); - - // Check that codes are unique - Set uniqueCodes = new HashSet<>(); - for (MathP50.HuffmanCode code : codes) { - assertTrue(uniqueCodes.add(code.code()), - "Codes must be unique"); - } - - // Check prefix property - for (MathP50.HuffmanCode code1 : codes) { - for (MathP50.HuffmanCode code2 : codes) { - if (code1 != code2) { - assertFalse(code1.code().startsWith(code2.code()), - "No code should be a prefix of another code"); - } - } + // Verify that more frequent symbols have shorter codes + for (MathP50.FrequencyEntry f1 : frequencies) { + for (MathP50.FrequencyEntry f2 : frequencies) { + if (f1.frequency() > f2.frequency()) { + String code1 = getCodeForSymbol(codes, f1.symbol()); + String code2 = getCodeForSymbol(codes, f2.symbol()); + assertTrue( + code1.length() <= code2.length(), + "More frequent symbols should have shorter or equal length codes"); } - - // Verify that more frequent symbols have shorter codes - for (MathP50.FrequencyEntry f1 : frequencies) { - for (MathP50.FrequencyEntry f2 : frequencies) { - if (f1.frequency() > f2.frequency()) { - String code1 = getCodeForSymbol(codes, f1.symbol()); - String code2 = getCodeForSymbol(codes, f2.symbol()); - assertTrue(code1.length() <= code2.length(), - "More frequent symbols should have shorter or equal length codes"); - } - } - } - } - - private String getCodeForSymbol(List codes, String symbol) { - return codes.stream() - .filter(c -> c.symbol().equals(symbol)) - .findFirst() - .map(MathP50.HuffmanCode::code) - .orElseThrow(); + } } + } + + private String getCodeForSymbol(List codes, String symbol) { + return codes.stream() + .filter(c -> c.symbol().equals(symbol)) + .findFirst() + .map(MathP50.HuffmanCode::code) + .orElseThrow(); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP01Test.java b/src/test/java/org/nintynine/problems/MyListP01Test.java index e21fd3a..8ef42dc 100644 --- a/src/test/java/org/nintynine/problems/MyListP01Test.java +++ b/src/test/java/org/nintynine/problems/MyListP01Test.java @@ -1,81 +1,77 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class MyListP01Test { - @Test - void testLastWithIntegers() { - MyList list = new MyList<>(1, 2, 3, 4, 5); - assertEquals(5, list.last()); - - MyList singleElement = new MyList<>(42); - assertEquals(42, singleElement.last()); - } + @Test + void testLastWithIntegers() { + MyList list = new MyList<>(1, 2, 3, 4, 5); + assertEquals(5, list.last()); - @Test - void testLastWithStrings() { - MyList list = new MyList<>("apple", "banana", "cherry"); - assertEquals("cherry", list.last()); - - MyList singleElement = new MyList<>("solo"); - assertEquals("solo", singleElement.last()); - } + MyList singleElement = new MyList<>(42); + assertEquals(42, singleElement.last()); + } - @Test - void testLastWithCustomObjects() { - TestObject obj1 = new TestObject("first"); - TestObject obj2 = new TestObject("second"); - TestObject obj3 = new TestObject("third"); - - MyList list = new MyList<>(obj1, obj2, obj3); - assertEquals(obj3, list.last()); - } + @Test + void testLastWithStrings() { + MyList list = new MyList<>("apple", "banana", "cherry"); + assertEquals("cherry", list.last()); - @Test - void testLastWithNull() { - MyList list = new MyList<>("first", null, "last"); - assertEquals("last",list.last()); - MyList listEndingWithNull = new MyList<>("first", "second", null); - assertThrows( - NullPointerException.class, - listEndingWithNull::last); - } + MyList singleElement = new MyList<>("solo"); + assertEquals("solo", singleElement.last()); + } - @Test - void testEmptyListThrowsException() { - MyList emptyList = new MyList<>(); - IllegalStateException exception = assertThrows( - IllegalStateException.class, - emptyList::last - ); - assertEquals("Empty list has no last element", exception.getMessage()); - } + @Test + void testLastWithCustomObjects() { + TestObject obj1 = new TestObject("first"); + TestObject obj2 = new TestObject("second"); + TestObject obj3 = new TestObject("third"); - @Test - void testToString() { - MyList numbers = new MyList<>(1, 2, 3); - assertEquals("(1 2 3)", numbers.toString()); - - MyList strings = new MyList<>("a", "b", "c"); - assertEquals("(a b c)", strings.toString()); - - MyList empty = new MyList<>(); - assertEquals("()", empty.toString()); - } + MyList list = new MyList<>(obj1, obj2, obj3); + assertEquals(obj3, list.last()); + } + + @Test + void testLastWithNull() { + MyList list = new MyList<>("first", null, "last"); + assertEquals("last", list.last()); + MyList listEndingWithNull = new MyList<>("first", "second", null); + assertThrows(NullPointerException.class, listEndingWithNull::last); + } + + @Test + void testEmptyListThrowsException() { + MyList emptyList = new MyList<>(); + IllegalStateException exception = assertThrows(IllegalStateException.class, emptyList::last); + assertEquals("Empty list has no last element", exception.getMessage()); + } + + @Test + void testToString() { + MyList numbers = new MyList<>(1, 2, 3); + assertEquals("(1 2 3)", numbers.toString()); - // Helper class for testing with custom objects - private static class TestObject { - private final String value; + MyList strings = new MyList<>("a", "b", "c"); + assertEquals("(a b c)", strings.toString()); - TestObject(String value) { - this.value = value; - } + MyList empty = new MyList<>(); + assertEquals("()", empty.toString()); + } + + // Helper class for testing with custom objects + private static class TestObject { + private final String value; + + TestObject(String value) { + this.value = value; + } - @Override - public String toString() { - return value; - } + @Override + public String toString() { + return value; } -} \ No newline at end of file + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP02Test.java b/src/test/java/org/nintynine/problems/MyListP02Test.java index 65c993f..45ecddc 100644 --- a/src/test/java/org/nintynine/problems/MyListP02Test.java +++ b/src/test/java/org/nintynine/problems/MyListP02Test.java @@ -1,60 +1,57 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.NoSuchElementException; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class MyListP02Test { - @Test - void testLastButOneWithMultipleElements() { - MyListP02 list = new MyListP02<>(1, 2, 3, 4, 5); - assertEquals(4, list.lastButOne()); - } - - @Test - void testLastButOneWithTwoElements() { - MyListP02 list = new MyListP02<>("first", "second"); - assertEquals("first", list.lastButOne()); - } - - @Test - void testLastButOneWithEmptyList() { - MyListP02 list = new MyListP02<>(); - assertThrows(NoSuchElementException.class, list::lastButOne); - } - - @Test - void testLastButOneWithSingleElement() { - MyListP02 list = new MyListP02<>("alone"); - assertThrows(NoSuchElementException.class, list::lastButOne); - } - - @Test - void testLastButOneWithNullValues() { - MyListP02 list = new MyListP02<>("first", null, "last"); - assertThrows(NoSuchElementException.class, list::lastButOne); - } - - @Test - void testLastButOneWithCustomObjects() { - Point p1 = new Point(1, 1); - Point p2 = new Point(2, 2); - Point p3 = new Point(3, 3); - - MyListP02 list = new MyListP02<>(p1, p2, p3); - assertEquals(p2, list.lastButOne()); - } - - @Test - void testLastButOneWithBooleans() { - MyListP02 list = new MyListP02<>(true, false, true); - assertEquals(false, list.lastButOne()); - } - - private record Point(int x, int y) { - - } -} \ No newline at end of file + @Test + void testLastButOneWithMultipleElements() { + MyListP02 list = new MyListP02<>(1, 2, 3, 4, 5); + assertEquals(4, list.lastButOne()); + } + + @Test + void testLastButOneWithTwoElements() { + MyListP02 list = new MyListP02<>("first", "second"); + assertEquals("first", list.lastButOne()); + } + + @Test + void testLastButOneWithEmptyList() { + MyListP02 list = new MyListP02<>(); + assertThrows(NoSuchElementException.class, list::lastButOne); + } + + @Test + void testLastButOneWithSingleElement() { + MyListP02 list = new MyListP02<>("alone"); + assertThrows(NoSuchElementException.class, list::lastButOne); + } + + @Test + void testLastButOneWithNullValues() { + MyListP02 list = new MyListP02<>("first", null, "last"); + assertThrows(NoSuchElementException.class, list::lastButOne); + } + + @Test + void testLastButOneWithCustomObjects() { + Point p1 = new Point(1, 1); + Point p2 = new Point(2, 2); + Point p3 = new Point(3, 3); + + MyListP02 list = new MyListP02<>(p1, p2, p3); + assertEquals(p2, list.lastButOne()); + } + + @Test + void testLastButOneWithBooleans() { + MyListP02 list = new MyListP02<>(true, false, true); + assertEquals(false, list.lastButOne()); + } + + private record Point(int x, int y) {} +} diff --git a/src/test/java/org/nintynine/problems/MyListP03Test.java b/src/test/java/org/nintynine/problems/MyListP03Test.java index 5782ed8..5448881 100644 --- a/src/test/java/org/nintynine/problems/MyListP03Test.java +++ b/src/test/java/org/nintynine/problems/MyListP03Test.java @@ -1,61 +1,62 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class MyListP03Test { - @Test - void testElementAtMiddle() { - MyListP03 list = new MyListP03<>("a", "b", "c", "d", "e"); - assertEquals("c", list.elementAt(3)); - } - - @Test - void testElementAtFirst() { - MyListP03 list = new MyListP03<>("a", "b", "c"); - assertEquals("a", list.elementAt(1)); - } - - @Test - void testElementAtLast() { - MyListP03 list = new MyListP03<>("a", "b", "c"); - assertEquals("c", list.elementAt(3)); - } - - @Test - void testElementAtWithIntegers() { - MyListP03 list = new MyListP03<>(1, 2, 3, 4, 5); - assertEquals(4, list.elementAt(4)); - } - - @Test - void testElementAtWithZeroPosition() { - MyListP03 list = new MyListP03<>("a", "b", "c"); - assertThrows(IllegalArgumentException.class, () -> list.elementAt(0)); - } - - @Test - void testElementAtWithNegativePosition() { - MyListP03 list = new MyListP03<>("a", "b", "c"); - assertThrows(IllegalArgumentException.class, () -> list.elementAt(-1)); - } - - @Test - void testElementAtWithTooLargePosition() { - MyListP03 list = new MyListP03<>("a", "b", "c"); - assertThrows(IllegalArgumentException.class, () -> list.elementAt(4)); - } - - @Test - void testElementAtWithEmptyList() { - MyListP03 list = new MyListP03<>(); - assertThrows(IllegalArgumentException.class, () -> list.elementAt(1)); - } - - @Test - void testElementAtWithNullValues() { - MyListP03 list = new MyListP03<>("a", null, "c"); - assertThrows(NullPointerException.class,()->list.elementAt(2)); - } -} \ No newline at end of file + @Test + void testElementAtMiddle() { + MyListP03 list = new MyListP03<>("a", "b", "c", "d", "e"); + assertEquals("c", list.elementAt(3)); + } + + @Test + void testElementAtFirst() { + MyListP03 list = new MyListP03<>("a", "b", "c"); + assertEquals("a", list.elementAt(1)); + } + + @Test + void testElementAtLast() { + MyListP03 list = new MyListP03<>("a", "b", "c"); + assertEquals("c", list.elementAt(3)); + } + + @Test + void testElementAtWithIntegers() { + MyListP03 list = new MyListP03<>(1, 2, 3, 4, 5); + assertEquals(4, list.elementAt(4)); + } + + @Test + void testElementAtWithZeroPosition() { + MyListP03 list = new MyListP03<>("a", "b", "c"); + assertThrows(IllegalArgumentException.class, () -> list.elementAt(0)); + } + + @Test + void testElementAtWithNegativePosition() { + MyListP03 list = new MyListP03<>("a", "b", "c"); + assertThrows(IllegalArgumentException.class, () -> list.elementAt(-1)); + } + + @Test + void testElementAtWithTooLargePosition() { + MyListP03 list = new MyListP03<>("a", "b", "c"); + assertThrows(IllegalArgumentException.class, () -> list.elementAt(4)); + } + + @Test + void testElementAtWithEmptyList() { + MyListP03 list = new MyListP03<>(); + assertThrows(IllegalArgumentException.class, () -> list.elementAt(1)); + } + + @Test + void testElementAtWithNullValues() { + MyListP03 list = new MyListP03<>("a", null, "c"); + assertThrows(NullPointerException.class, () -> list.elementAt(2)); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP04Test.java b/src/test/java/org/nintynine/problems/MyListP04Test.java index 1edd00e..fd574c7 100644 --- a/src/test/java/org/nintynine/problems/MyListP04Test.java +++ b/src/test/java/org/nintynine/problems/MyListP04Test.java @@ -1,43 +1,44 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class MyListP04Test { - - @Test - void testEmptyListLength() { - MyListP04 list = new MyListP04<>(); - assertEquals(0, list.length()); - } - - @Test - void testSingleElementLength() { - MyListP04 list = new MyListP04<>(1); - assertEquals(1, list.length()); - } - - @Test - void testMultipleElementsLength() { - MyListP04 list = new MyListP04<>("a", "b", "c", "d", "e"); - assertEquals(5, list.length()); - } - - @Test - void testListWithNullValues() { - MyListP04 list = new MyListP04<>("a", null, "c", null); - assertEquals(4, list.length()); - } - - @Test - void testLengthWithDifferentTypes() { - MyListP04 intList = new MyListP04<>(1, 2, 3); - assertEquals(3, intList.length()); - - MyListP04 doubleList = new MyListP04<>(1.0, 2.0, 3.0, 4.0); - assertEquals(4, doubleList.length()); - - MyListP04 boolList = new MyListP04<>(true, false, true); - assertEquals(3, boolList.length()); - } -} \ No newline at end of file + + @Test + void testEmptyListLength() { + MyListP04 list = new MyListP04<>(); + assertEquals(0, list.length()); + } + + @Test + void testSingleElementLength() { + MyListP04 list = new MyListP04<>(1); + assertEquals(1, list.length()); + } + + @Test + void testMultipleElementsLength() { + MyListP04 list = new MyListP04<>("a", "b", "c", "d", "e"); + assertEquals(5, list.length()); + } + + @Test + void testListWithNullValues() { + MyListP04 list = new MyListP04<>("a", null, "c", null); + assertEquals(4, list.length()); + } + + @Test + void testLengthWithDifferentTypes() { + MyListP04 intList = new MyListP04<>(1, 2, 3); + assertEquals(3, intList.length()); + + MyListP04 doubleList = new MyListP04<>(1.0, 2.0, 3.0, 4.0); + assertEquals(4, doubleList.length()); + + MyListP04 boolList = new MyListP04<>(true, false, true); + assertEquals(3, boolList.length()); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP05Test.java b/src/test/java/org/nintynine/problems/MyListP05Test.java index 4e13e04..cb3c499 100644 --- a/src/test/java/org/nintynine/problems/MyListP05Test.java +++ b/src/test/java/org/nintynine/problems/MyListP05Test.java @@ -1,56 +1,57 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + class MyListP05Test { - @Test - void testReverseEmptyList() { - MyListP05 list = new MyListP05<>(); - assertArrayEquals(new String[]{}, list.reverse().items); - } - - @Test - void testReverseSingleElement() { - MyListP05 list = new MyListP05<>(1); - assertArrayEquals(new Integer[]{1}, list.reverse().items); - } - - @Test - void testReverseMultipleElements() { - MyListP05 list = new MyListP05<>("a", "b", "c", "d", "e"); - assertArrayEquals(new String[]{"e", "d", "c", "b", "a"}, list.reverse().items); - } - - @Test - void testReverseWithNullValues() { - MyListP05 list = new MyListP05<>("a", null, "c"); - assertArrayEquals(new String[]{"c", null, "a"}, list.reverse().items); - } - - @Test - void testReverseWithDifferentTypes() { - MyListP05 intList = new MyListP05<>(1, 2, 3); - assertArrayEquals(new Integer[]{3, 2, 1}, intList.reverse().items); - - MyListP05 doubleList = new MyListP05<>(1.0, 2.0, 3.0); - assertArrayEquals(new Double[]{3.0, 2.0, 1.0}, doubleList.reverse().items); - - MyListP05 boolList = new MyListP05<>(true, false, true); - assertArrayEquals(new Boolean[]{true, false, true}, boolList.reverse().items); - } - - @Test - void testReverseTwice() { - MyListP05 list = new MyListP05<>("a", "b", "c"); - assertArrayEquals(new String[]{"c", "b", "a"}, list.reverse().items); - assertArrayEquals(new String[]{"a", "b", "c"}, list.reverse().reverse().items); - } - - @Test - void testReversePalindrome() { - MyListP05 list = new MyListP05<>("a", "b", "a"); - assertArrayEquals(new String[]{"a", "b", "a"}, list.reverse().items); - } -} \ No newline at end of file + @Test + void testReverseEmptyList() { + MyListP05 list = new MyListP05<>(); + assertArrayEquals(new String[] {}, list.reverse().items); + } + + @Test + void testReverseSingleElement() { + MyListP05 list = new MyListP05<>(1); + assertArrayEquals(new Integer[] {1}, list.reverse().items); + } + + @Test + void testReverseMultipleElements() { + MyListP05 list = new MyListP05<>("a", "b", "c", "d", "e"); + assertArrayEquals(new String[] {"e", "d", "c", "b", "a"}, list.reverse().items); + } + + @Test + void testReverseWithNullValues() { + MyListP05 list = new MyListP05<>("a", null, "c"); + assertArrayEquals(new String[] {"c", null, "a"}, list.reverse().items); + } + + @Test + void testReverseWithDifferentTypes() { + MyListP05 intList = new MyListP05<>(1, 2, 3); + assertArrayEquals(new Integer[] {3, 2, 1}, intList.reverse().items); + + MyListP05 doubleList = new MyListP05<>(1.0, 2.0, 3.0); + assertArrayEquals(new Double[] {3.0, 2.0, 1.0}, doubleList.reverse().items); + + MyListP05 boolList = new MyListP05<>(true, false, true); + assertArrayEquals(new Boolean[] {true, false, true}, boolList.reverse().items); + } + + @Test + void testReverseTwice() { + MyListP05 list = new MyListP05<>("a", "b", "c"); + assertArrayEquals(new String[] {"c", "b", "a"}, list.reverse().items); + assertArrayEquals(new String[] {"a", "b", "c"}, list.reverse().reverse().items); + } + + @Test + void testReversePalindrome() { + MyListP05 list = new MyListP05<>("a", "b", "a"); + assertArrayEquals(new String[] {"a", "b", "a"}, list.reverse().items); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP06Test.java b/src/test/java/org/nintynine/problems/MyListP06Test.java index aa9ddeb..750ecf5 100644 --- a/src/test/java/org/nintynine/problems/MyListP06Test.java +++ b/src/test/java/org/nintynine/problems/MyListP06Test.java @@ -1,29 +1,29 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; class MyListP06Test { - @Test - void isPalindrome() { - MyListP06 palindrome = new MyListP06<>("x", "a", "m", "a", "x"); - assertTrue(palindrome.isPalindrome()); - - MyListP06 notPalindrome = new MyListP06<>("a", "b", "c"); - assertFalse(notPalindrome.isPalindrome()); + @Test + void isPalindrome() { + MyListP06 palindrome = new MyListP06<>("x", "a", "m", "a", "x"); + assertTrue(palindrome.isPalindrome()); - MyListP06 numPalindrome = new MyListP06<>(1, 2, 3, 2, 1); - assertTrue(numPalindrome.isPalindrome()); + MyListP06 notPalindrome = new MyListP06<>("a", "b", "c"); + assertFalse(notPalindrome.isPalindrome()); - MyListP06 singleElement = new MyListP06<>("a"); - assertTrue(singleElement.isPalindrome()); + MyListP06 numPalindrome = new MyListP06<>(1, 2, 3, 2, 1); + assertTrue(numPalindrome.isPalindrome()); - MyListP06 empty = new MyListP06<>(); - assertTrue(empty.isPalindrome()); + MyListP06 singleElement = new MyListP06<>("a"); + assertTrue(singleElement.isPalindrome()); - // Additional test for null elements - MyListP06 withNulls = new MyListP06<>(null, "a", null); - assertThrows(NullPointerException.class,withNulls::isPalindrome); - } + MyListP06 empty = new MyListP06<>(); + assertTrue(empty.isPalindrome()); -} \ No newline at end of file + // Additional test for null elements + MyListP06 withNulls = new MyListP06<>(null, "a", null); + assertThrows(NullPointerException.class, withNulls::isPalindrome); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP07Test.java b/src/test/java/org/nintynine/problems/MyListP07Test.java index 2bae665..14062d4 100644 --- a/src/test/java/org/nintynine/problems/MyListP07Test.java +++ b/src/test/java/org/nintynine/problems/MyListP07Test.java @@ -1,94 +1,89 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class MyListP07Test { - @Test - void testDeepNesting() { - // Create a deeply nested structure - MyListP07 level5 = new MyListP07<>("x"); - MyListP07 level4 = new MyListP07<>(level5, "y"); - MyListP07 level3 = new MyListP07<>(level4, "z"); - MyListP07 level2 = new MyListP07<>(level3, "a"); - MyListP07 level1 = new MyListP07<>(level2, "b"); - - MyListP07 flattened = level1.flatten(); - - // Should be [x, y, z, a, b] - assertArrayEquals( - new String[]{"x", "y", "z", "a", "b"}, - Arrays.stream(flattened.items).map(Object::toString).toArray() - ); - } - - @Test - void testMixedCollectionTypes() { - List javaList = Arrays.asList("p", "q"); - Object[] array = new Object[]{"r", "s"}; - MyListP07 myList = new MyListP07<>("t", "u"); - - MyListP07 mixed = new MyListP07<>(javaList, array, myList); - MyListP07 flattened = mixed.flatten(); - - // Should be [p, q, r, s, t, u] - assertArrayEquals( - new String[]{"p", "q", "r", "s", "t", "u"}, - Arrays.stream(flattened.items).map(Object::toString).toArray() - ); - } - - @Test - void testComplexNesting() { - List innerJavaList = Arrays.asList(1, Arrays.asList(2, 3)); - Object[] innerArray = new Object[]{4, new Object[]{5, 6}}; - MyListP07 innerMyList = new MyListP07<>(7, new MyListP07<>(8, 9)); - - MyListP07 complex = new MyListP07<>(innerJavaList, innerArray, innerMyList); - MyListP07 flattened = complex.flatten(); - - // Should be [1, 2, 3, 4, 5, 6, 7, 8, 9] - assertArrayEquals( - new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Arrays.stream(flattened.items).map(o -> (Integer) o).toArray() - ); - } - - @Test - void testWithNulls() { - List listWithNull = Arrays.asList(null, 1); - Object[] arrayWithNull = new Object[]{2, null}; - MyListP07 myListWithNull = new MyListP07<>(3, null); - - MyListP07 mixed = new MyListP07<>(listWithNull, arrayWithNull, myListWithNull); - MyListP07 flattened = mixed.flatten(); - - // Should be [null, 1, 2, null, 3, null] - assertEquals(6, flattened.length()); - assertThrows(NullPointerException.class,()->flattened.elementAt(1)); - assertEquals(1, flattened.elementAt(1+1)); - assertEquals(2, flattened.elementAt(2+1)); - assertThrows(NullPointerException.class,()->flattened.elementAt(3+1)); - assertEquals(3, flattened.elementAt(4+1)); - assertThrows(NullPointerException.class,()->flattened.elementAt(5+1)); - } - - @Test - void testEmptyStructures() { - List emptyList = Collections.emptyList(); - Object[] emptyArray = new Object[0]; - MyListP07 emptyMyList = new MyListP07<>(); - - MyListP07 mixed = new MyListP07<>(emptyList, emptyArray, emptyMyList); - MyListP07 flattened = mixed.flatten(); - - assertEquals(0, flattened.length()); - } - -} \ No newline at end of file + @Test + void testDeepNesting() { + // Create a deeply nested structure + MyListP07 level5 = new MyListP07<>("x"); + MyListP07 level4 = new MyListP07<>(level5, "y"); + MyListP07 level3 = new MyListP07<>(level4, "z"); + MyListP07 level2 = new MyListP07<>(level3, "a"); + MyListP07 level1 = new MyListP07<>(level2, "b"); + + MyListP07 flattened = level1.flatten(); + + // Should be [x, y, z, a, b] + assertArrayEquals( + new String[] {"x", "y", "z", "a", "b"}, + Arrays.stream(flattened.items).map(Object::toString).toArray()); + } + + @Test + void testMixedCollectionTypes() { + List javaList = Arrays.asList("p", "q"); + Object[] array = new Object[] {"r", "s"}; + MyListP07 myList = new MyListP07<>("t", "u"); + + MyListP07 mixed = new MyListP07<>(javaList, array, myList); + MyListP07 flattened = mixed.flatten(); + + // Should be [p, q, r, s, t, u] + assertArrayEquals( + new String[] {"p", "q", "r", "s", "t", "u"}, + Arrays.stream(flattened.items).map(Object::toString).toArray()); + } + + @Test + void testComplexNesting() { + List innerJavaList = Arrays.asList(1, Arrays.asList(2, 3)); + Object[] innerArray = new Object[] {4, new Object[] {5, 6}}; + MyListP07 innerMyList = new MyListP07<>(7, new MyListP07<>(8, 9)); + + MyListP07 complex = new MyListP07<>(innerJavaList, innerArray, innerMyList); + MyListP07 flattened = complex.flatten(); + + // Should be [1, 2, 3, 4, 5, 6, 7, 8, 9] + assertArrayEquals( + new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9}, + Arrays.stream(flattened.items).map(o -> (Integer) o).toArray()); + } + + @Test + void testWithNulls() { + List listWithNull = Arrays.asList(null, 1); + Object[] arrayWithNull = new Object[] {2, null}; + MyListP07 myListWithNull = new MyListP07<>(3, null); + + MyListP07 mixed = new MyListP07<>(listWithNull, arrayWithNull, myListWithNull); + MyListP07 flattened = mixed.flatten(); + + // Should be [null, 1, 2, null, 3, null] + assertEquals(6, flattened.length()); + assertThrows(NullPointerException.class, () -> flattened.elementAt(1)); + assertEquals(1, flattened.elementAt(1 + 1)); + assertEquals(2, flattened.elementAt(2 + 1)); + assertThrows(NullPointerException.class, () -> flattened.elementAt(3 + 1)); + assertEquals(3, flattened.elementAt(4 + 1)); + assertThrows(NullPointerException.class, () -> flattened.elementAt(5 + 1)); + } + + @Test + void testEmptyStructures() { + List emptyList = Collections.emptyList(); + Object[] emptyArray = new Object[0]; + MyListP07 emptyMyList = new MyListP07<>(); + + MyListP07 mixed = new MyListP07<>(emptyList, emptyArray, emptyMyList); + MyListP07 flattened = mixed.flatten(); + + assertEquals(0, flattened.length()); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP08Test.java b/src/test/java/org/nintynine/problems/MyListP08Test.java index 6236f30..e400a05 100644 --- a/src/test/java/org/nintynine/problems/MyListP08Test.java +++ b/src/test/java/org/nintynine/problems/MyListP08Test.java @@ -1,92 +1,73 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class MyListP08Test { - @Test - void testBasicCompression() { - MyListP08 list = new MyListP08<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new String[]{"a", "b", "c", "a", "d", "e"}, - Arrays.stream(compressed.items).toArray() - ); - } - - @Test - void testNoConsecutiveDuplicates() { - MyListP08 list = new MyListP08<>("a", "b", "c", "d"); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new String[]{"a", "b", "c", "d"}, - Arrays.stream(compressed.items).toArray() - ); - } - - @Test - void testAllDuplicates() { - MyListP08 list = new MyListP08<>("a", "a", "a", "a"); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new String[]{"a"}, - Arrays.stream(compressed.items).toArray() - ); - } - - @Test - void testEmptyList() { - MyListP08 list = new MyListP08<>(); - MyListP08 compressed = list.compress(); - - assertEquals(0, compressed.length()); - } - - @Test - void testSingleElement() { - MyListP08 list = new MyListP08<>("a"); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new String[]{"a"}, - Arrays.stream(compressed.items).toArray() - ); - } - - @Test - void testWithNulls() { - MyListP08 list = new MyListP08<>(null, null, "a", "a", null, "b", null, null); - assertThrows(NullPointerException.class, list::compress); - - - } - - @Test - void testWithNumbers() { - MyListP08 list = new MyListP08<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new Integer[]{1, 2, 3, 4}, - Arrays.stream(compressed.items).toArray() - ); - } - - @Test - void testAlternatingElements() { - MyListP08 list = new MyListP08<>("a", "b", "a", "b", "a", "b"); - MyListP08 compressed = list.compress(); - - assertArrayEquals( - new String[]{"a", "b", "a", "b", "a", "b"}, - Arrays.stream(compressed.items).toArray() - ); - } - -} \ No newline at end of file + @Test + void testBasicCompression() { + MyListP08 list = + new MyListP08<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); + MyListP08 compressed = list.compress(); + + assertArrayEquals( + new String[] {"a", "b", "c", "a", "d", "e"}, Arrays.stream(compressed.items).toArray()); + } + + @Test + void testNoConsecutiveDuplicates() { + MyListP08 list = new MyListP08<>("a", "b", "c", "d"); + MyListP08 compressed = list.compress(); + + assertArrayEquals(new String[] {"a", "b", "c", "d"}, Arrays.stream(compressed.items).toArray()); + } + + @Test + void testAllDuplicates() { + MyListP08 list = new MyListP08<>("a", "a", "a", "a"); + MyListP08 compressed = list.compress(); + + assertArrayEquals(new String[] {"a"}, Arrays.stream(compressed.items).toArray()); + } + + @Test + void testEmptyList() { + MyListP08 list = new MyListP08<>(); + MyListP08 compressed = list.compress(); + + assertEquals(0, compressed.length()); + } + + @Test + void testSingleElement() { + MyListP08 list = new MyListP08<>("a"); + MyListP08 compressed = list.compress(); + + assertArrayEquals(new String[] {"a"}, Arrays.stream(compressed.items).toArray()); + } + + @Test + void testWithNulls() { + MyListP08 list = new MyListP08<>(null, null, "a", "a", null, "b", null, null); + assertThrows(NullPointerException.class, list::compress); + } + + @Test + void testWithNumbers() { + MyListP08 list = new MyListP08<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); + MyListP08 compressed = list.compress(); + + assertArrayEquals(new Integer[] {1, 2, 3, 4}, Arrays.stream(compressed.items).toArray()); + } + + @Test + void testAlternatingElements() { + MyListP08 list = new MyListP08<>("a", "b", "a", "b", "a", "b"); + MyListP08 compressed = list.compress(); + + assertArrayEquals( + new String[] {"a", "b", "a", "b", "a", "b"}, Arrays.stream(compressed.items).toArray()); + } +} diff --git a/src/test/java/org/nintynine/problems/MyListP09Test.java b/src/test/java/org/nintynine/problems/MyListP09Test.java index cedcefe..a6aad1d 100644 --- a/src/test/java/org/nintynine/problems/MyListP09Test.java +++ b/src/test/java/org/nintynine/problems/MyListP09Test.java @@ -1,128 +1,121 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + /** - * Test class for MyListP09's consecutive duplicate packing functionality. - * Verifies the pack() method behavior under various scenarios. + * Test class for MyListP09's consecutive duplicate packing functionality. Verifies the pack() + * method behavior under various scenarios. */ class MyListP09Test { - - /** - * Tests the basic packing functionality with a sequence containing - * multiple consecutive duplicates. - */ - @Test - void testBasicPacking() { - MyListP09 list = new MyListP09<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); - MyListP09> packed = list.pack(); - - assertEquals(6, packed.length()); - assertArrayEquals(new String[]{"a", "a", "a", "a"}, packed.elementAt(1).items); - assertArrayEquals(new String[]{"b"}, packed.elementAt(2).items); - assertArrayEquals(new String[]{"c", "c"}, packed.elementAt(3).items); - assertArrayEquals(new String[]{"a", "a"}, packed.elementAt(4).items); - assertArrayEquals(new String[]{"d"}, packed.elementAt(5).items); - assertArrayEquals(new String[]{"e", "e", "e", "e"}, packed.elementAt(1+5).items); - } - - /** - * Tests packing behavior when the input list has no consecutive duplicates. - * Each element should be in its own sublist. - */ - @Test - void testNoConsecutiveDuplicates() { - MyListP09 list = new MyListP09<>("a", "b", "c", "d"); - MyListP09> packed = list.pack(); - - assertEquals(4, packed.length()); - assertArrayEquals(new String[]{"a"}, packed.elementAt(1).items); - assertArrayEquals(new String[]{"b"}, packed.elementAt(2).items); - assertArrayEquals(new String[]{"c"}, packed.elementAt(3).items); - assertArrayEquals(new String[]{"d"}, packed.elementAt(4).items); - } - - /** - * Tests packing when all elements in the list are identical. - * Should result in a single sublist containing all elements. - */ - @Test - void testAllDuplicates() { - MyListP09 list = new MyListP09<>("a", "a", "a", "a"); - MyListP09> packed = list.pack(); - - assertEquals(1, packed.length()); - assertArrayEquals(new String[]{"a", "a", "a", "a"}, packed.elementAt(1).items); - } - - /** - * Tests packing behavior with an empty list. - * Should return an empty list. - */ - @Test - void testEmptyList() { - MyListP09 list = new MyListP09<>(); - MyListP09> packed = list.pack(); - - assertEquals(0, packed.length()); - } - - /** - * Tests packing behavior with a single-element list. - * Should return a list containing one sublist with one element. - */ - @Test - void testSingleElement() { - MyListP09 list = new MyListP09<>("a"); - MyListP09> packed = list.pack(); - - assertEquals(1, packed.length()); - assertArrayEquals(new String[]{"a"}, packed.elementAt(1).items); - } - - /** - * Tests packing behavior with numeric values. - * Verifies that packing works correctly with Integer objects. - */ - @Test - void testWithNumbers() { - MyListP09 list = new MyListP09<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); - MyListP09> packed = list.pack(); - - assertEquals(4, packed.length()); - assertArrayEquals(new Integer[]{1, 1, 1}, packed.elementAt(1).items); - assertArrayEquals(new Integer[]{2}, packed.elementAt(1+1).items); - assertArrayEquals(new Integer[]{3, 3}, packed.elementAt(1+2).items); - assertArrayEquals(new Integer[]{4, 4, 4, 4}, packed.elementAt(1+3).items); - } - - /** - * Tests packing behavior with alternating elements. - * Each element should be in its own sublist. - */ - @Test - void testAlternatingElements() { - MyListP09 list = new MyListP09<>("a", "b", "a", "b", "a", "b"); - MyListP09> packed = list.pack(); - - assertEquals(6, packed.length()); - for (int i = 0; i < packed.length(); i++) { - assertArrayEquals( - new String[]{i % 2 == 0 ? "a" : "b"}, - packed.elementAt(1+i).items - ); - } - } - /** - * Tests that the pack method throws NullPointerException when - * the list contains null elements. - */ - @Test - void testWithNulls() { - MyListP09 list = new MyListP09<>(null, null, "a", "a", null); - assertThrows(NullPointerException.class, list::pack); + /** + * Tests the basic packing functionality with a sequence containing multiple consecutive + * duplicates. + */ + @Test + void testBasicPacking() { + MyListP09 list = + new MyListP09<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); + MyListP09> packed = list.pack(); + + assertEquals(6, packed.length()); + assertArrayEquals(new String[] {"a", "a", "a", "a"}, packed.elementAt(1).items); + assertArrayEquals(new String[] {"b"}, packed.elementAt(2).items); + assertArrayEquals(new String[] {"c", "c"}, packed.elementAt(3).items); + assertArrayEquals(new String[] {"a", "a"}, packed.elementAt(4).items); + assertArrayEquals(new String[] {"d"}, packed.elementAt(5).items); + assertArrayEquals(new String[] {"e", "e", "e", "e"}, packed.elementAt(1 + 5).items); + } + + /** + * Tests packing behavior when the input list has no consecutive duplicates. Each element should + * be in its own sublist. + */ + @Test + void testNoConsecutiveDuplicates() { + MyListP09 list = new MyListP09<>("a", "b", "c", "d"); + MyListP09> packed = list.pack(); + + assertEquals(4, packed.length()); + assertArrayEquals(new String[] {"a"}, packed.elementAt(1).items); + assertArrayEquals(new String[] {"b"}, packed.elementAt(2).items); + assertArrayEquals(new String[] {"c"}, packed.elementAt(3).items); + assertArrayEquals(new String[] {"d"}, packed.elementAt(4).items); + } + + /** + * Tests packing when all elements in the list are identical. Should result in a single sublist + * containing all elements. + */ + @Test + void testAllDuplicates() { + MyListP09 list = new MyListP09<>("a", "a", "a", "a"); + MyListP09> packed = list.pack(); + + assertEquals(1, packed.length()); + assertArrayEquals(new String[] {"a", "a", "a", "a"}, packed.elementAt(1).items); + } + + /** Tests packing behavior with an empty list. Should return an empty list. */ + @Test + void testEmptyList() { + MyListP09 list = new MyListP09<>(); + MyListP09> packed = list.pack(); + + assertEquals(0, packed.length()); + } + + /** + * Tests packing behavior with a single-element list. Should return a list containing one sublist + * with one element. + */ + @Test + void testSingleElement() { + MyListP09 list = new MyListP09<>("a"); + MyListP09> packed = list.pack(); + + assertEquals(1, packed.length()); + assertArrayEquals(new String[] {"a"}, packed.elementAt(1).items); + } + + /** + * Tests packing behavior with numeric values. Verifies that packing works correctly with Integer + * objects. + */ + @Test + void testWithNumbers() { + MyListP09 list = new MyListP09<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); + MyListP09> packed = list.pack(); + + assertEquals(4, packed.length()); + assertArrayEquals(new Integer[] {1, 1, 1}, packed.elementAt(1).items); + assertArrayEquals(new Integer[] {2}, packed.elementAt(1 + 1).items); + assertArrayEquals(new Integer[] {3, 3}, packed.elementAt(1 + 2).items); + assertArrayEquals(new Integer[] {4, 4, 4, 4}, packed.elementAt(1 + 3).items); + } + + /** + * Tests packing behavior with alternating elements. Each element should be in its own sublist. + */ + @Test + void testAlternatingElements() { + MyListP09 list = new MyListP09<>("a", "b", "a", "b", "a", "b"); + MyListP09> packed = list.pack(); + + assertEquals(6, packed.length()); + for (int i = 0; i < packed.length(); i++) { + assertArrayEquals(new String[] {i % 2 == 0 ? "a" : "b"}, packed.elementAt(1 + i).items); } + } + + /** + * Tests that the pack method throws NullPointerException when the list contains null elements. + */ + @Test + void testWithNulls() { + MyListP09 list = new MyListP09<>(null, null, "a", "a", null); + assertThrows(NullPointerException.class, list::pack); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP10Test.java b/src/test/java/org/nintynine/problems/MyListP10Test.java index 817a51a..261242e 100644 --- a/src/test/java/org/nintynine/problems/MyListP10Test.java +++ b/src/test/java/org/nintynine/problems/MyListP10Test.java @@ -1,126 +1,120 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + /** - * Test class for MyListP10's run-length encoding functionality. - * Verifies the encode() method behavior under various scenarios. + * Test class for MyListP10's run-length encoding functionality. Verifies the encode() method + * behavior under various scenarios. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP10Test { - /** - * Tests basic run-length encoding with a sequence containing - * multiple consecutive duplicates. - */ - @Test - void testBasicEncoding() { - MyListP10 list = new MyListP10<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); - MyListP10> encoded = list.encode(); - - assertEquals(6, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4, "a"), encoded.elementAt(1+0)); - assertEquals(new MyListP10.EncodedElement<>(1, "b"), encoded.elementAt(1+1)); - assertEquals(new MyListP10.EncodedElement<>(2, "c"), encoded.elementAt(1+2)); - assertEquals(new MyListP10.EncodedElement<>(2, "a"), encoded.elementAt(1+3)); - assertEquals(new MyListP10.EncodedElement<>(1, "d"), encoded.elementAt(1+4)); - assertEquals(new MyListP10.EncodedElement<>(4, "e"), encoded.elementAt(1+5)); - } - - /** - * Tests encoding behavior when the input list has no consecutive duplicates. - * Each element should be encoded with count 1. - */ - @Test - void testNoConsecutiveDuplicates() { - MyListP10 list = new MyListP10<>("a", "b", "c", "d"); - MyListP10> encoded = list.encode(); - - assertEquals(4, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(1, "a"), encoded.elementAt(1+0)); - assertEquals(new MyListP10.EncodedElement<>(1, "b"), encoded.elementAt(1+1)); - assertEquals(new MyListP10.EncodedElement<>(1, "c"), encoded.elementAt(1+2)); - assertEquals(new MyListP10.EncodedElement<>(1, "d"), encoded.elementAt(1+3)); - } - - /** - * Tests encoding when all elements in the list are identical. - * Should result in a single encoded element with the total count. - */ - @Test - void testAllDuplicates() { - MyListP10 list = new MyListP10<>("a", "a", "a", "a"); - MyListP10> encoded = list.encode(); - - assertEquals(1, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4, "a"), encoded.elementAt(1+0)); - } - - /** - * Tests encoding behavior with an empty list. - * Should return an empty list. - */ - @Test - void testEmptyList() { - MyListP10 list = new MyListP10<>(); - MyListP10> encoded = list.encode(); - - assertEquals(0, encoded.length()); - } - - /** - * Tests encoding behavior with a single-element list. - * Should return a list with one encoded element with count 1. - */ - @Test - void testSingleElement() { - MyListP10 list = new MyListP10<>("a"); - MyListP10> encoded = list.encode(); - - assertEquals(1, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(1, "a"), encoded.elementAt(1+0)); - } - - /** - * Tests encoding with numeric values. - * Verifies that encoding works correctly with Integer objects. - */ - @Test - void testWithNumbers() { - MyListP10 list = new MyListP10<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); - MyListP10> encoded = list.encode(); - System.out.println(encoded); - assertEquals(4, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(3, 1), encoded.elementAt(1+0)); - assertEquals(new MyListP10.EncodedElement<>(1, 2), encoded.elementAt(1+1)); - assertEquals(new MyListP10.EncodedElement<>(2, 3), encoded.elementAt(1+2)); - assertEquals(new MyListP10.EncodedElement<>(4, 4), encoded.elementAt(1+3)); - } - - /** - * Tests encoding behavior with alternating elements. - * Each element should be encoded with count 1. - */ - @Test - void testAlternatingElements() { - MyListP10 list = new MyListP10<>("a", "b", "a", "b", "a", "b"); - MyListP10> encoded = list.encode(); - - assertEquals(6, encoded.length()); - for (int i = 0; i < encoded.length(); i++) { - assertEquals(new MyListP10.EncodedElement<>(1, i % 2 == 0 ? "a" : "b"), encoded.elementAt(1+i)); - } - } - - /** - * Tests that the encode method throws NullPointerException when - * the list contains null elements. - */ - @Test - void testWithNulls() { - MyListP10 list = new MyListP10<>(null, null, "a", "a", null); - assertThrows(NullPointerException.class, list::encode); + /** Tests basic run-length encoding with a sequence containing multiple consecutive duplicates. */ + @Test + void testBasicEncoding() { + MyListP10 list = + new MyListP10<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); + MyListP10> encoded = list.encode(); + + assertEquals(6, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4, "a"), encoded.elementAt(1 + 0)); + assertEquals(new MyListP10.EncodedElement<>(1, "b"), encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2, "c"), encoded.elementAt(1 + 2)); + assertEquals(new MyListP10.EncodedElement<>(2, "a"), encoded.elementAt(1 + 3)); + assertEquals(new MyListP10.EncodedElement<>(1, "d"), encoded.elementAt(1 + 4)); + assertEquals(new MyListP10.EncodedElement<>(4, "e"), encoded.elementAt(1 + 5)); + } + + /** + * Tests encoding behavior when the input list has no consecutive duplicates. Each element should + * be encoded with count 1. + */ + @Test + void testNoConsecutiveDuplicates() { + MyListP10 list = new MyListP10<>("a", "b", "c", "d"); + MyListP10> encoded = list.encode(); + + assertEquals(4, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(1, "a"), encoded.elementAt(1 + 0)); + assertEquals(new MyListP10.EncodedElement<>(1, "b"), encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(1, "c"), encoded.elementAt(1 + 2)); + assertEquals(new MyListP10.EncodedElement<>(1, "d"), encoded.elementAt(1 + 3)); + } + + /** + * Tests encoding when all elements in the list are identical. Should result in a single encoded + * element with the total count. + */ + @Test + void testAllDuplicates() { + MyListP10 list = new MyListP10<>("a", "a", "a", "a"); + MyListP10> encoded = list.encode(); + + assertEquals(1, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4, "a"), encoded.elementAt(1 + 0)); + } + + /** Tests encoding behavior with an empty list. Should return an empty list. */ + @Test + void testEmptyList() { + MyListP10 list = new MyListP10<>(); + MyListP10> encoded = list.encode(); + + assertEquals(0, encoded.length()); + } + + /** + * Tests encoding behavior with a single-element list. Should return a list with one encoded + * element with count 1. + */ + @Test + void testSingleElement() { + MyListP10 list = new MyListP10<>("a"); + MyListP10> encoded = list.encode(); + + assertEquals(1, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(1, "a"), encoded.elementAt(1 + 0)); + } + + /** + * Tests encoding with numeric values. Verifies that encoding works correctly with Integer + * objects. + */ + @Test + void testWithNumbers() { + MyListP10 list = new MyListP10<>(1, 1, 1, 2, 3, 3, 4, 4, 4, 4); + MyListP10> encoded = list.encode(); + System.out.println(encoded); + assertEquals(4, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(3, 1), encoded.elementAt(1 + 0)); + assertEquals(new MyListP10.EncodedElement<>(1, 2), encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2, 3), encoded.elementAt(1 + 2)); + assertEquals(new MyListP10.EncodedElement<>(4, 4), encoded.elementAt(1 + 3)); + } + + /** + * Tests encoding behavior with alternating elements. Each element should be encoded with count 1. + */ + @Test + void testAlternatingElements() { + MyListP10 list = new MyListP10<>("a", "b", "a", "b", "a", "b"); + MyListP10> encoded = list.encode(); + + assertEquals(6, encoded.length()); + for (int i = 0; i < encoded.length(); i++) { + assertEquals( + new MyListP10.EncodedElement<>(1, i % 2 == 0 ? "a" : "b"), encoded.elementAt(1 + i)); } + } + + /** + * Tests that the encode method throws NullPointerException when the list contains null elements. + */ + @Test + void testWithNulls() { + MyListP10 list = new MyListP10<>(null, null, "a", "a", null); + assertThrows(NullPointerException.class, list::encode); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP11Test.java b/src/test/java/org/nintynine/problems/MyListP11Test.java index 98e7a6f..64ee23e 100644 --- a/src/test/java/org/nintynine/problems/MyListP11Test.java +++ b/src/test/java/org/nintynine/problems/MyListP11Test.java @@ -1,126 +1,108 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP11's modified run-length encoding functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP11's modified run-length encoding functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP11Test { - /** - * Tests basic modified run-length encoding with a sequence containing - * both single elements and duplicates. - */ - @Test - void testBasicModifiedEncoding() { - MyListP11 list = new MyListP11<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); - MyListP11 encoded = list.encodeModified(); - - assertEquals(6, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1+0)); - assertEquals("b", encoded.elementAt(1+1)); - assertEquals(new MyListP10.EncodedElement<>(2L, "c"), encoded.elementAt(1+2)); - assertEquals(new MyListP10.EncodedElement<>(2L, "a"), encoded.elementAt(1+3)); - assertEquals("d", encoded.elementAt(1+4)); - assertEquals(new MyListP10.EncodedElement<>(4L, "e"), encoded.elementAt(1+5)); - } - - /** - * Tests encoding when no elements have duplicates. - * Should return the original list unchanged. - */ - @Test - void testNoConsecutiveDuplicates() { - MyListP11 list = new MyListP11<>("a", "b", "c", "d"); - MyListP11 encoded = list.encodeModified(); - - assertEquals(4, encoded.length()); - assertEquals("a", encoded.elementAt(1+0)); - assertEquals("b", encoded.elementAt(1+1)); - assertEquals("c", encoded.elementAt(1+2)); - assertEquals("d", encoded.elementAt(1+3)); - } - - /** - * Tests encoding when all elements are identical. - * Should return a single encoded element. - */ - @Test - void testAllDuplicates() { - MyListP11 list = new MyListP11<>("a", "a", "a", "a"); - MyListP11 encoded = list.encodeModified(); - - assertEquals(1, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1+0)); - } - - /** - * Tests encoding of an empty list. - */ - @Test - void testEmptyList() { - MyListP11 list = new MyListP11<>(); - MyListP11 encoded = list.encodeModified(); - - assertEquals(0, encoded.length()); - } - - /** - * Tests encoding of a single element. - * Should return the element unchanged. - */ - @Test - void testSingleElement() { - MyListP11 list = new MyListP11<>("a"); - MyListP11 encoded = list.encodeModified(); - - assertEquals(1, encoded.length()); - assertEquals("a", encoded.elementAt(1+0)); - } - - /** - * Tests encoding with numeric values. - */ - @Test - void testWithNumbers() { - MyListP11 list = new MyListP11<>(1, 1, 1, 2, 3, 3, 4); - MyListP11 encoded = list.encodeModified(); - - assertEquals(4, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(3L, 1), encoded.elementAt(1+0)); - assertEquals(2, encoded.elementAt(1+1)); - assertEquals(new MyListP10.EncodedElement<>(2L, 3), encoded.elementAt(1+2)); - assertEquals(4, encoded.elementAt(1+3)); - } - - /** - * Tests encoding with alternating elements. - * Should return the original list unchanged. - */ - @Test - void testAlternatingElements() { - MyListP11 list = new MyListP11<>("a", "b", "a", "b", "a", "b"); - MyListP11 encoded = list.encodeModified(); - - assertEquals(6, encoded.length()); - assertEquals("a", encoded.elementAt(1+0)); - assertEquals("b", encoded.elementAt(1+1)); - assertEquals("a", encoded.elementAt(1+2)); - assertEquals("b", encoded.elementAt(1+3)); - assertEquals("a", encoded.elementAt(1+4)); - assertEquals("b", encoded.elementAt(1+5)); - } - - /** - * Tests that the encode method throws NullPointerException when - * the list contains null elements. - */ - @Test - void testWithNulls() { - MyListP11 list = new MyListP11<>(null, null, "a", "a", null); - assertThrows(NullPointerException.class, list::encodeModified); - } + /** + * Tests basic modified run-length encoding with a sequence containing both single elements and + * duplicates. + */ + @Test + void testBasicModifiedEncoding() { + MyListP11 list = + new MyListP11<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); + MyListP11 encoded = list.encodeModified(); + + assertEquals(6, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2L, "c"), encoded.elementAt(1 + 2)); + assertEquals(new MyListP10.EncodedElement<>(2L, "a"), encoded.elementAt(1 + 3)); + assertEquals("d", encoded.elementAt(1 + 4)); + assertEquals(new MyListP10.EncodedElement<>(4L, "e"), encoded.elementAt(1 + 5)); + } + + /** Tests encoding when no elements have duplicates. Should return the original list unchanged. */ + @Test + void testNoConsecutiveDuplicates() { + MyListP11 list = new MyListP11<>("a", "b", "c", "d"); + MyListP11 encoded = list.encodeModified(); + + assertEquals(4, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals("c", encoded.elementAt(1 + 2)); + assertEquals("d", encoded.elementAt(1 + 3)); + } + + /** Tests encoding when all elements are identical. Should return a single encoded element. */ + @Test + void testAllDuplicates() { + MyListP11 list = new MyListP11<>("a", "a", "a", "a"); + MyListP11 encoded = list.encodeModified(); + + assertEquals(1, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); + } + + /** Tests encoding of an empty list. */ + @Test + void testEmptyList() { + MyListP11 list = new MyListP11<>(); + MyListP11 encoded = list.encodeModified(); + + assertEquals(0, encoded.length()); + } + + /** Tests encoding of a single element. Should return the element unchanged. */ + @Test + void testSingleElement() { + MyListP11 list = new MyListP11<>("a"); + MyListP11 encoded = list.encodeModified(); + + assertEquals(1, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + } + + /** Tests encoding with numeric values. */ + @Test + void testWithNumbers() { + MyListP11 list = new MyListP11<>(1, 1, 1, 2, 3, 3, 4); + MyListP11 encoded = list.encodeModified(); + + assertEquals(4, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(3L, 1), encoded.elementAt(1 + 0)); + assertEquals(2, encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2L, 3), encoded.elementAt(1 + 2)); + assertEquals(4, encoded.elementAt(1 + 3)); + } + + /** Tests encoding with alternating elements. Should return the original list unchanged. */ + @Test + void testAlternatingElements() { + MyListP11 list = new MyListP11<>("a", "b", "a", "b", "a", "b"); + MyListP11 encoded = list.encodeModified(); + + assertEquals(6, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals("a", encoded.elementAt(1 + 2)); + assertEquals("b", encoded.elementAt(1 + 3)); + assertEquals("a", encoded.elementAt(1 + 4)); + assertEquals("b", encoded.elementAt(1 + 5)); + } + + /** + * Tests that the encode method throws NullPointerException when the list contains null elements. + */ + @Test + void testWithNulls() { + MyListP11 list = new MyListP11<>(null, null, "a", "a", null); + assertThrows(NullPointerException.class, list::encodeModified); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP12Test.java b/src/test/java/org/nintynine/problems/MyListP12Test.java index d5191de..8f23e58 100644 --- a/src/test/java/org/nintynine/problems/MyListP12Test.java +++ b/src/test/java/org/nintynine/problems/MyListP12Test.java @@ -1,169 +1,141 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -/** - * Test class for MyListP12's run-length decoding functionality. - */ +/** Test class for MyListP12's run-length decoding functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP12Test { - /** - * Tests decoding of a modified run-length encoded list with mixed - * single elements and encoded runs. - */ - @Test - void testBasicDecoding() { - MyListP12 encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(4L, "a"), - "b", - new MyListP10.EncodedElement<>(2L, "c"), - new MyListP10.EncodedElement<>(2L, "a"), - "d", - new MyListP10.EncodedElement<>(4L, "e") - ); - - MyListP12 decoded = encoded.decode(); - - String[] expected = {"a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"}; - assertEquals(expected.length, decoded.length()); - for (int i = 0; i < expected.length; i++) { - assertEquals(expected[i], decoded.elementAt(1 + i)); - } + /** + * Tests decoding of a modified run-length encoded list with mixed single elements and encoded + * runs. + */ + @Test + void testBasicDecoding() { + MyListP12 encoded = + new MyListP12<>( + new MyListP10.EncodedElement<>(4L, "a"), + "b", + new MyListP10.EncodedElement<>(2L, "c"), + new MyListP10.EncodedElement<>(2L, "a"), + "d", + new MyListP10.EncodedElement<>(4L, "e")); + + MyListP12 decoded = encoded.decode(); + + String[] expected = {"a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"}; + assertEquals(expected.length, decoded.length()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], decoded.elementAt(1 + i)); } - - /** - * Tests decoding of a list with only single elements (no encoding). - */ - @Test - void testNoEncodedElements() { - MyListP12 encoded = new MyListP12<>("a", "b", "c", "d"); - MyListP12 decoded = encoded.decode(); - - assertEquals(4, decoded.length()); - assertEquals("a", decoded.elementAt(1 + 0)); - assertEquals("b", decoded.elementAt(1 + 1)); - assertEquals("c", decoded.elementAt(1 + 2)); - assertEquals("d", decoded.elementAt(1 + 3)); + } + + /** Tests decoding of a list with only single elements (no encoding). */ + @Test + void testNoEncodedElements() { + MyListP12 encoded = new MyListP12<>("a", "b", "c", "d"); + MyListP12 decoded = encoded.decode(); + + assertEquals(4, decoded.length()); + assertEquals("a", decoded.elementAt(1 + 0)); + assertEquals("b", decoded.elementAt(1 + 1)); + assertEquals("c", decoded.elementAt(1 + 2)); + assertEquals("d", decoded.elementAt(1 + 3)); + } + + /** Tests decoding of a list with only encoded elements. */ + @Test + void testAllEncodedElements() { + MyListP12> encoded = + new MyListP12<>( + new MyListP10.EncodedElement<>(2L, "a"), + new MyListP10.EncodedElement<>(3L, "b"), + new MyListP10.EncodedElement<>(1L, "c")); + + MyListP12 decoded = encoded.decode(); + + String[] expected = {"a", "a", "b", "b", "b", "c"}; + assertEquals(expected.length, decoded.length()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], decoded.elementAt(1 + i)); } - - /** - * Tests decoding of a list with only encoded elements. - */ - @Test - void testAllEncodedElements() { - MyListP12> encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(2L, "a"), - new MyListP10.EncodedElement<>(3L, "b"), - new MyListP10.EncodedElement<>(1L, "c") - ); - - MyListP12 decoded = encoded.decode(); - - String[] expected = {"a", "a", "b", "b", "b", "c"}; - assertEquals(expected.length, decoded.length()); - for (int i = 0; i < expected.length; i++) { - assertEquals(expected[i], decoded.elementAt(1 + i)); - } + } + + /** Tests decoding of an empty list. */ + @Test + void testEmptyList() { + MyListP12 encoded = new MyListP12<>(); + MyListP12 decoded = encoded.decode(); + + assertEquals(0, decoded.length()); + } + + /** Tests decoding of a list with a single non-encoded element. */ + @Test + void testSingleElement() { + MyListP12 encoded = new MyListP12<>("a"); + MyListP12 decoded = encoded.decode(); + + assertEquals(1, decoded.length()); + assertEquals("a", decoded.elementAt(1 + 0)); + } + + /** Tests decoding of a list with a single encoded element. */ + @Test + void testSingleEncodedElement() { + MyListP12> encoded = + new MyListP12<>(new MyListP10.EncodedElement<>(3L, "a")); + + MyListP12 decoded = encoded.decode(); + + assertEquals(3, decoded.length()); + assertEquals("a", decoded.elementAt(1 + 0)); + assertEquals("a", decoded.elementAt(1 + 1)); + assertEquals("a", decoded.elementAt(1 + 2)); + } + + /** Tests decoding with numeric values. */ + @Test + void testWithNumbers() { + MyListP12 encoded = + new MyListP12<>( + new MyListP10.EncodedElement<>(2L, 1), 3, new MyListP10.EncodedElement<>(3L, 4)); + + MyListP12 decoded = encoded.decode(); + + Integer[] expected = {1, 1, 3, 4, 4, 4}; + assertEquals(expected.length, decoded.length()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], decoded.elementAt(1 + i)); } + } - /** - * Tests decoding of an empty list. - */ - @Test - void testEmptyList() { - MyListP12 encoded = new MyListP12<>(); - MyListP12 decoded = encoded.decode(); - - assertEquals(0, decoded.length()); - } + /** Tests that decoding preserves the order of elements. */ + @Test + void testPreservesOrder() { + MyListP12 encoded = + new MyListP12<>( + new MyListP10.EncodedElement<>(2L, "a"), "b", new MyListP10.EncodedElement<>(2L, "a")); - /** - * Tests decoding of a list with a single non-encoded element. - */ - @Test - void testSingleElement() { - MyListP12 encoded = new MyListP12<>("a"); - MyListP12 decoded = encoded.decode(); + MyListP12 decoded = encoded.decode(); - assertEquals(1, decoded.length()); - assertEquals("a", decoded.elementAt(1 + 0)); + String[] expected = {"a", "a", "b", "a", "a"}; + assertEquals(expected.length, decoded.length()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], decoded.elementAt(1 + i)); } + } - /** - * Tests decoding of a list with a single encoded element. - */ - @Test - void testSingleEncodedElement() { - MyListP12> encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(3L, "a") - ); - - MyListP12 decoded = encoded.decode(); - - assertEquals(3, decoded.length()); - assertEquals("a", decoded.elementAt(1 + 0)); - assertEquals("a", decoded.elementAt(1 + 1)); - assertEquals("a", decoded.elementAt(1 + 2)); - } + /** Tests decoding of elements with count zero. */ + @Test + void testZeroCount() { + MyListP12 encoded = new MyListP12<>(new MyListP10.EncodedElement<>(0L, "a"), "b"); - /** - * Tests decoding with numeric values. - */ - @Test - void testWithNumbers() { - MyListP12 encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(2L, 1), - 3, - new MyListP10.EncodedElement<>(3L, 4) - ); - - MyListP12 decoded = encoded.decode(); - - Integer[] expected = {1, 1, 3, 4, 4, 4}; - assertEquals(expected.length, decoded.length()); - for (int i = 0; i < expected.length; i++) { - assertEquals(expected[i], decoded.elementAt(1 + i)); - } - } - - /** - * Tests that decoding preserves the order of elements. - */ - @Test - void testPreservesOrder() { - MyListP12 encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(2L, "a"), - "b", - new MyListP10.EncodedElement<>(2L, "a") - ); - - MyListP12 decoded = encoded.decode(); - - String[] expected = {"a", "a", "b", "a", "a"}; - assertEquals(expected.length, decoded.length()); - for (int i = 0; i < expected.length; i++) { - assertEquals(expected[i], decoded.elementAt(1 + i)); - } - } - - /** - * Tests decoding of elements with count zero. - */ - @Test - void testZeroCount() { - MyListP12 encoded = new MyListP12<>( - new MyListP10.EncodedElement<>(0L, "a"), - "b" - ); + MyListP12 decoded = encoded.decode(); - MyListP12 decoded = encoded.decode(); - - assertEquals(1, decoded.length()); - assertEquals("b", decoded.elementAt(1 + 0)); - } + assertEquals(1, decoded.length()); + assertEquals("b", decoded.elementAt(1 + 0)); + } } - diff --git a/src/test/java/org/nintynine/problems/MyListP13Test.java b/src/test/java/org/nintynine/problems/MyListP13Test.java index f122bb7..3b54f8a 100644 --- a/src/test/java/org/nintynine/problems/MyListP13Test.java +++ b/src/test/java/org/nintynine/problems/MyListP13Test.java @@ -1,137 +1,114 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP13's direct run-length encoding functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP13's direct run-length encoding functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP13Test { - /** - * Tests basic direct encoding with a sequence containing - * both single elements and duplicates. - */ - @Test - void testBasicDirectEncoding() { - MyListP13 list = new MyListP13<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(6, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); - assertEquals("b", encoded.elementAt(1 + 1)); - assertEquals(new MyListP10.EncodedElement<>(2L, "c"), encoded.elementAt(1 + 2)); - assertEquals(new MyListP10.EncodedElement<>(2L, "a"), encoded.elementAt(1 + 3)); - assertEquals("d", encoded.elementAt(1 + 4)); - assertEquals(new MyListP10.EncodedElement<>(4L, "e"), encoded.elementAt(1 + 5)); - } - - /** - * Tests encoding when no elements have duplicates. - */ - @Test - void testNoConsecutiveDuplicates() { - MyListP13 list = new MyListP13<>("a", "b", "c", "d"); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(4, encoded.length()); - assertEquals("a", encoded.elementAt(1 + 0)); - assertEquals("b", encoded.elementAt(1 + 1)); - assertEquals("c", encoded.elementAt(1 + 2)); - assertEquals("d", encoded.elementAt(1 + 3)); - } - - /** - * Tests encoding when all elements are identical. - */ - @Test - void testAllDuplicates() { - MyListP13 list = new MyListP13<>("a", "a", "a", "a"); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(1, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); - } - - /** - * Tests encoding of an empty list. - */ - @Test - void testEmptyList() { - MyListP13 list = new MyListP13<>(); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(0, encoded.length()); - } - - /** - * Tests encoding of a single element. - */ - @Test - void testSingleElement() { - MyListP13 list = new MyListP13<>("a"); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(1, encoded.length()); - assertEquals("a", encoded.elementAt(1 + 0)); - } - - /** - * Tests encoding with numeric values. - */ - @Test - void testWithNumbers() { - MyListP13 list = new MyListP13<>(1, 1, 1, 2, 3, 3, 4); - MyListP13 encoded = list.encodeDirect(); - System.out.println(encoded); - assertEquals(4, encoded.length()); - assertEquals(new MyListP10.EncodedElement<>(3L, 1), encoded.elementAt(1 + 0)); - assertEquals(2, encoded.elementAt(1 + 1)); - assertEquals(new MyListP10.EncodedElement<>(2L, 3), encoded.elementAt(1 + 2)); - assertEquals(4, encoded.elementAt(1 + 3)); - } - - /** - * Tests encoding with alternating elements. - */ - @Test - void testAlternatingElements() { - MyListP13 list = new MyListP13<>("a", "b", "a", "b", "a", "b"); - MyListP13 encoded = list.encodeDirect(); - - assertEquals(6, encoded.length()); - assertEquals("a", encoded.elementAt(1 + 0)); - assertEquals("b", encoded.elementAt(1 + 1)); - assertEquals("a", encoded.elementAt(1 + 2)); - assertEquals("b", encoded.elementAt(1 + 3)); - assertEquals("a", encoded.elementAt(1 + 4)); - assertEquals("b", encoded.elementAt(1 + 5)); - } - - /** - * Tests that the encode method works correctly with null elements. - */ - @Test - void testWithNulls() { - MyListP13 list = new MyListP13<>(null, null, "a", "a", null); - assertThrows(NullPointerException.class, list::encodeDirect); - - - } - - /** - * Tests encoding and then decoding returns the original list. - */ - @Test - void testEncodeThenDecode() { - MyListP13 original = new MyListP13<>("a", "a", "a", "b", "c", "c", "a"); - MyListP13 encoded = original.encodeDirect(); - MyListP13 decoded = encoded.decode(); - assertEquals(original.length(), decoded.length()); - for (int i = 0; i < original.length(); i++) { - assertEquals(original.elementAt(1 + i), decoded.elementAt(1 + i)); - } + /** Tests basic direct encoding with a sequence containing both single elements and duplicates. */ + @Test + void testBasicDirectEncoding() { + MyListP13 list = + new MyListP13<>("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(6, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2L, "c"), encoded.elementAt(1 + 2)); + assertEquals(new MyListP10.EncodedElement<>(2L, "a"), encoded.elementAt(1 + 3)); + assertEquals("d", encoded.elementAt(1 + 4)); + assertEquals(new MyListP10.EncodedElement<>(4L, "e"), encoded.elementAt(1 + 5)); + } + + /** Tests encoding when no elements have duplicates. */ + @Test + void testNoConsecutiveDuplicates() { + MyListP13 list = new MyListP13<>("a", "b", "c", "d"); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(4, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals("c", encoded.elementAt(1 + 2)); + assertEquals("d", encoded.elementAt(1 + 3)); + } + + /** Tests encoding when all elements are identical. */ + @Test + void testAllDuplicates() { + MyListP13 list = new MyListP13<>("a", "a", "a", "a"); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(1, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(4L, "a"), encoded.elementAt(1 + 0)); + } + + /** Tests encoding of an empty list. */ + @Test + void testEmptyList() { + MyListP13 list = new MyListP13<>(); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(0, encoded.length()); + } + + /** Tests encoding of a single element. */ + @Test + void testSingleElement() { + MyListP13 list = new MyListP13<>("a"); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(1, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + } + + /** Tests encoding with numeric values. */ + @Test + void testWithNumbers() { + MyListP13 list = new MyListP13<>(1, 1, 1, 2, 3, 3, 4); + MyListP13 encoded = list.encodeDirect(); + System.out.println(encoded); + assertEquals(4, encoded.length()); + assertEquals(new MyListP10.EncodedElement<>(3L, 1), encoded.elementAt(1 + 0)); + assertEquals(2, encoded.elementAt(1 + 1)); + assertEquals(new MyListP10.EncodedElement<>(2L, 3), encoded.elementAt(1 + 2)); + assertEquals(4, encoded.elementAt(1 + 3)); + } + + /** Tests encoding with alternating elements. */ + @Test + void testAlternatingElements() { + MyListP13 list = new MyListP13<>("a", "b", "a", "b", "a", "b"); + MyListP13 encoded = list.encodeDirect(); + + assertEquals(6, encoded.length()); + assertEquals("a", encoded.elementAt(1 + 0)); + assertEquals("b", encoded.elementAt(1 + 1)); + assertEquals("a", encoded.elementAt(1 + 2)); + assertEquals("b", encoded.elementAt(1 + 3)); + assertEquals("a", encoded.elementAt(1 + 4)); + assertEquals("b", encoded.elementAt(1 + 5)); + } + + /** Tests that the encode method works correctly with null elements. */ + @Test + void testWithNulls() { + MyListP13 list = new MyListP13<>(null, null, "a", "a", null); + assertThrows(NullPointerException.class, list::encodeDirect); + } + + /** Tests encoding and then decoding returns the original list. */ + @Test + void testEncodeThenDecode() { + MyListP13 original = new MyListP13<>("a", "a", "a", "b", "c", "c", "a"); + MyListP13 encoded = original.encodeDirect(); + MyListP13 decoded = encoded.decode(); + assertEquals(original.length(), decoded.length()); + for (int i = 0; i < original.length(); i++) { + assertEquals(original.elementAt(1 + i), decoded.elementAt(1 + i)); } + } } - diff --git a/src/test/java/org/nintynine/problems/MyListP14Test.java b/src/test/java/org/nintynine/problems/MyListP14Test.java index 9464652..b1e0759 100644 --- a/src/test/java/org/nintynine/problems/MyListP14Test.java +++ b/src/test/java/org/nintynine/problems/MyListP14Test.java @@ -1,154 +1,136 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP14's element duplication functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP14's element duplication functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP14Test { - /** - * Tests basic duplication of a list with distinct elements. - */ - @Test - void testBasicDuplication() { - MyListP14 list = new MyListP14<>("a", "b", "c", "d"); - MyListP14 duplicated = list.duplicate(); - - assertEquals(8, duplicated.length()); - assertEquals("a", duplicated.elementAt(1+0)); - assertEquals("a", duplicated.elementAt(1+1)); - assertEquals("b", duplicated.elementAt(1+2)); - assertEquals("b", duplicated.elementAt(1+3)); - assertEquals("c", duplicated.elementAt(1+4)); - assertEquals("c", duplicated.elementAt(1+5)); - assertEquals("d", duplicated.elementAt(1+6)); - assertEquals("d", duplicated.elementAt(1+7)); - } - - /** - * Tests duplication of a list that already contains duplicates. - */ - @Test - void testDuplicatingDuplicates() { - MyListP14 list = new MyListP14<>("a", "a", "b", "b"); - MyListP14 duplicated = list.duplicate(); - - assertEquals(8, duplicated.length()); - assertEquals("a", duplicated.elementAt(1+0)); - assertEquals("a", duplicated.elementAt(1+1)); - assertEquals("a", duplicated.elementAt(1+2)); - assertEquals("a", duplicated.elementAt(1+3)); - assertEquals("b", duplicated.elementAt(1+4)); - assertEquals("b", duplicated.elementAt(1+5)); - assertEquals("b", duplicated.elementAt(1+6)); - assertEquals("b", duplicated.elementAt(1+7)); - } - - /** - * Tests duplication of an empty list. - */ - @Test - void testEmptyList() { - MyListP14 list = new MyListP14<>(); - MyListP14 duplicated = list.duplicate(); - - assertEquals(0, duplicated.length()); - } - - /** - * Tests duplication of a single element. - */ - @Test - void testSingleElement() { - MyListP14 list = new MyListP14<>("a"); - MyListP14 duplicated = list.duplicate(); - - assertEquals(2, duplicated.length()); - assertEquals("a", duplicated.elementAt(1+0)); - assertEquals("a", duplicated.elementAt(1+1)); - } - - /** - * Tests duplication with numeric values. - */ - @Test - void testWithNumbers() { - MyListP14 list = new MyListP14<>(1, 2, 3); - MyListP14 duplicated = list.duplicate(); - - assertEquals(6, duplicated.length()); - assertEquals(Integer.valueOf(1), duplicated.elementAt(1+0)); - assertEquals(Integer.valueOf(1), duplicated.elementAt(1+1)); - assertEquals(Integer.valueOf(2), duplicated.elementAt(1+2)); - assertEquals(Integer.valueOf(2), duplicated.elementAt(1+3)); - assertEquals(Integer.valueOf(3), duplicated.elementAt(1+4)); - assertEquals(Integer.valueOf(3), duplicated.elementAt(1+5)); - } - - /** - * Tests that the duplication preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("a"); - StringBuilder sb2 = new StringBuilder("b"); - MyListP14 list = new MyListP14<>(sb1, sb2); - MyListP14 duplicated = list.duplicate(); - - assertEquals(4, duplicated.length()); - assertSame(sb1, duplicated.elementAt(1+0)); - assertSame(sb1, duplicated.elementAt(1+1)); - assertSame(sb2, duplicated.elementAt(1+2)); - assertSame(sb2, duplicated.elementAt(1+3)); - } - - /** - * Tests duplication with null values. - */ - @Test - void testWithNulls() { - MyListP14 list = new MyListP14<>("a", null, "b"); - MyListP14 duplicated = list.duplicate(); - - assertEquals(6, duplicated.length()); - assertEquals("a", duplicated.elementAt(1+0)); - assertEquals("a", duplicated.elementAt(1+1)); - assertThrows(NullPointerException.class,()->duplicated.elementAt(1+2)); - assertThrows(NullPointerException.class,()->duplicated.elementAt(1+3)); - assertEquals("b", duplicated.elementAt(1+4)); - assertEquals("b", duplicated.elementAt(1+5)); - } - - /** - * Tests multiple duplications of the same list. - */ - @Test - void testMultipleDuplications() { - MyListP14 list = new MyListP14<>("a", "b"); - MyListP14 duplicated1 = list.duplicate(); - MyListP14 duplicated2 = duplicated1.duplicate(); - - assertEquals(4, duplicated1.length()); - assertEquals(8, duplicated2.length()); - - // Check first duplication - assertEquals("a", duplicated1.elementAt(1+0)); - assertEquals("a", duplicated1.elementAt(1+1)); - assertEquals("b", duplicated1.elementAt(1+2)); - assertEquals("b", duplicated1.elementAt(1+3)); - - // Check second duplication - assertEquals("a", duplicated2.elementAt(1+0)); - assertEquals("a", duplicated2.elementAt(1+1)); - assertEquals("a", duplicated2.elementAt(1+2)); - assertEquals("a", duplicated2.elementAt(1+3)); - assertEquals("b", duplicated2.elementAt(1+4)); - assertEquals("b", duplicated2.elementAt(1+5)); - assertEquals("b", duplicated2.elementAt(1+6)); - assertEquals("b", duplicated2.elementAt(1+7)); - } + /** Tests basic duplication of a list with distinct elements. */ + @Test + void testBasicDuplication() { + MyListP14 list = new MyListP14<>("a", "b", "c", "d"); + MyListP14 duplicated = list.duplicate(); + + assertEquals(8, duplicated.length()); + assertEquals("a", duplicated.elementAt(1 + 0)); + assertEquals("a", duplicated.elementAt(1 + 1)); + assertEquals("b", duplicated.elementAt(1 + 2)); + assertEquals("b", duplicated.elementAt(1 + 3)); + assertEquals("c", duplicated.elementAt(1 + 4)); + assertEquals("c", duplicated.elementAt(1 + 5)); + assertEquals("d", duplicated.elementAt(1 + 6)); + assertEquals("d", duplicated.elementAt(1 + 7)); + } + + /** Tests duplication of a list that already contains duplicates. */ + @Test + void testDuplicatingDuplicates() { + MyListP14 list = new MyListP14<>("a", "a", "b", "b"); + MyListP14 duplicated = list.duplicate(); + + assertEquals(8, duplicated.length()); + assertEquals("a", duplicated.elementAt(1 + 0)); + assertEquals("a", duplicated.elementAt(1 + 1)); + assertEquals("a", duplicated.elementAt(1 + 2)); + assertEquals("a", duplicated.elementAt(1 + 3)); + assertEquals("b", duplicated.elementAt(1 + 4)); + assertEquals("b", duplicated.elementAt(1 + 5)); + assertEquals("b", duplicated.elementAt(1 + 6)); + assertEquals("b", duplicated.elementAt(1 + 7)); + } + + /** Tests duplication of an empty list. */ + @Test + void testEmptyList() { + MyListP14 list = new MyListP14<>(); + MyListP14 duplicated = list.duplicate(); + + assertEquals(0, duplicated.length()); + } + + /** Tests duplication of a single element. */ + @Test + void testSingleElement() { + MyListP14 list = new MyListP14<>("a"); + MyListP14 duplicated = list.duplicate(); + + assertEquals(2, duplicated.length()); + assertEquals("a", duplicated.elementAt(1 + 0)); + assertEquals("a", duplicated.elementAt(1 + 1)); + } + + /** Tests duplication with numeric values. */ + @Test + void testWithNumbers() { + MyListP14 list = new MyListP14<>(1, 2, 3); + MyListP14 duplicated = list.duplicate(); + + assertEquals(6, duplicated.length()); + assertEquals(Integer.valueOf(1), duplicated.elementAt(1 + 0)); + assertEquals(Integer.valueOf(1), duplicated.elementAt(1 + 1)); + assertEquals(Integer.valueOf(2), duplicated.elementAt(1 + 2)); + assertEquals(Integer.valueOf(2), duplicated.elementAt(1 + 3)); + assertEquals(Integer.valueOf(3), duplicated.elementAt(1 + 4)); + assertEquals(Integer.valueOf(3), duplicated.elementAt(1 + 5)); + } + + /** Tests that the duplication preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("a"); + StringBuilder sb2 = new StringBuilder("b"); + MyListP14 list = new MyListP14<>(sb1, sb2); + MyListP14 duplicated = list.duplicate(); + + assertEquals(4, duplicated.length()); + assertSame(sb1, duplicated.elementAt(1 + 0)); + assertSame(sb1, duplicated.elementAt(1 + 1)); + assertSame(sb2, duplicated.elementAt(1 + 2)); + assertSame(sb2, duplicated.elementAt(1 + 3)); + } + + /** Tests duplication with null values. */ + @Test + void testWithNulls() { + MyListP14 list = new MyListP14<>("a", null, "b"); + MyListP14 duplicated = list.duplicate(); + + assertEquals(6, duplicated.length()); + assertEquals("a", duplicated.elementAt(1 + 0)); + assertEquals("a", duplicated.elementAt(1 + 1)); + assertThrows(NullPointerException.class, () -> duplicated.elementAt(1 + 2)); + assertThrows(NullPointerException.class, () -> duplicated.elementAt(1 + 3)); + assertEquals("b", duplicated.elementAt(1 + 4)); + assertEquals("b", duplicated.elementAt(1 + 5)); + } + + /** Tests multiple duplications of the same list. */ + @Test + void testMultipleDuplications() { + MyListP14 list = new MyListP14<>("a", "b"); + MyListP14 duplicated1 = list.duplicate(); + MyListP14 duplicated2 = duplicated1.duplicate(); + + assertEquals(4, duplicated1.length()); + assertEquals(8, duplicated2.length()); + + // Check first duplication + assertEquals("a", duplicated1.elementAt(1 + 0)); + assertEquals("a", duplicated1.elementAt(1 + 1)); + assertEquals("b", duplicated1.elementAt(1 + 2)); + assertEquals("b", duplicated1.elementAt(1 + 3)); + + // Check second duplication + assertEquals("a", duplicated2.elementAt(1 + 0)); + assertEquals("a", duplicated2.elementAt(1 + 1)); + assertEquals("a", duplicated2.elementAt(1 + 2)); + assertEquals("a", duplicated2.elementAt(1 + 3)); + assertEquals("b", duplicated2.elementAt(1 + 4)); + assertEquals("b", duplicated2.elementAt(1 + 5)); + assertEquals("b", duplicated2.elementAt(1 + 6)); + assertEquals("b", duplicated2.elementAt(1 + 7)); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP15Test.java b/src/test/java/org/nintynine/problems/MyListP15Test.java index 4358050..6f234e0 100644 --- a/src/test/java/org/nintynine/problems/MyListP15Test.java +++ b/src/test/java/org/nintynine/problems/MyListP15Test.java @@ -1,154 +1,132 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP15's element replication functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP15's element replication functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP15Test { - /** - * Tests basic replication with different counts. - */ - @Test - void testBasicReplication() { - MyListP15 list = new MyListP15<>("a", "b", "c"); - - MyListP15 replicated = list.replicate(3); - assertEquals(9, replicated.length()); - assertEquals("a", replicated.elementAt(1+0)); - assertEquals("a", replicated.elementAt(1+1)); - assertEquals("a", replicated.elementAt(1+2)); - assertEquals("b", replicated.elementAt(1+3)); - assertEquals("b", replicated.elementAt(1+4)); - assertEquals("b", replicated.elementAt(1+5)); - assertEquals("c", replicated.elementAt(1+6)); - assertEquals("c", replicated.elementAt(1+7)); - assertEquals("c", replicated.elementAt(1+8)); - } - - /** - * Tests replication with zero count. - */ - @Test - void testZeroReplication() { - MyListP15 list = new MyListP15<>("a", "b", "c"); - MyListP15 replicated = list.replicate(0); - assertEquals(0, replicated.length()); + /** Tests basic replication with different counts. */ + @Test + void testBasicReplication() { + MyListP15 list = new MyListP15<>("a", "b", "c"); + + MyListP15 replicated = list.replicate(3); + assertEquals(9, replicated.length()); + assertEquals("a", replicated.elementAt(1 + 0)); + assertEquals("a", replicated.elementAt(1 + 1)); + assertEquals("a", replicated.elementAt(1 + 2)); + assertEquals("b", replicated.elementAt(1 + 3)); + assertEquals("b", replicated.elementAt(1 + 4)); + assertEquals("b", replicated.elementAt(1 + 5)); + assertEquals("c", replicated.elementAt(1 + 6)); + assertEquals("c", replicated.elementAt(1 + 7)); + assertEquals("c", replicated.elementAt(1 + 8)); + } + + /** Tests replication with zero count. */ + @Test + void testZeroReplication() { + MyListP15 list = new MyListP15<>("a", "b", "c"); + MyListP15 replicated = list.replicate(0); + assertEquals(0, replicated.length()); + } + + /** Tests replication with negative count. */ + @Test + void testNegativeReplication() { + MyListP15 list = new MyListP15<>("a", "b", "c"); + assertThrows(IllegalArgumentException.class, () -> list.replicate(-1)); + } + + /** Tests replication of an empty list. */ + @Test + void testEmptyList() { + MyListP15 list = new MyListP15<>(); + MyListP15 replicated = list.replicate(3); + assertEquals(0, replicated.length()); + } + + /** Tests replication of a single element. */ + @Test + void testSingleElement() { + MyListP15 list = new MyListP15<>("a"); + MyListP15 replicated = list.replicate(2); + assertEquals(2, replicated.length()); + assertEquals("a", replicated.elementAt(1 + 0)); + assertEquals("a", replicated.elementAt(1 + 1)); + } + + /** Tests replication with null values. */ + @Test + void testWithNulls() { + MyListP15 list = new MyListP15<>("a", null, "b"); + MyListP15 replicated = list.replicate(2); + assertEquals(6, replicated.length()); + assertEquals("a", replicated.elementAt(1 + 0)); + assertEquals("a", replicated.elementAt(1 + 1)); + assertThrows(NullPointerException.class, () -> replicated.elementAt(1 + 2)); + assertThrows(NullPointerException.class, () -> replicated.elementAt(1 + 3)); + assertEquals("b", replicated.elementAt(1 + 4)); + assertEquals("b", replicated.elementAt(1 + 5)); + } + + /** Tests that replication preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb = new StringBuilder("test"); + MyListP15 list = new MyListP15<>(sb); + MyListP15 replicated = list.replicate(3); + + assertEquals(3, replicated.length()); + for (int i = 0; i < 3; i++) { + assertSame(sb, replicated.elementAt(1 + i)); } - - /** - * Tests replication with negative count. - */ - @Test - void testNegativeReplication() { - MyListP15 list = new MyListP15<>("a", "b", "c"); - assertThrows(IllegalArgumentException.class, () -> list.replicate(-1)); - } - - /** - * Tests replication of an empty list. - */ - @Test - void testEmptyList() { - MyListP15 list = new MyListP15<>(); - MyListP15 replicated = list.replicate(3); - assertEquals(0, replicated.length()); - } - - /** - * Tests replication of a single element. - */ - @Test - void testSingleElement() { - MyListP15 list = new MyListP15<>("a"); - MyListP15 replicated = list.replicate(2); - assertEquals(2, replicated.length()); - assertEquals("a", replicated.elementAt(1+0)); - assertEquals("a", replicated.elementAt(1+1)); - } - - /** - * Tests replication with null values. - */ - @Test - void testWithNulls() { - MyListP15 list = new MyListP15<>("a", null, "b"); - MyListP15 replicated = list.replicate(2); - assertEquals(6, replicated.length()); - assertEquals("a", replicated.elementAt(1+0)); - assertEquals("a", replicated.elementAt(1+1)); - assertThrows(NullPointerException.class,()->replicated.elementAt(1+2)); - assertThrows(NullPointerException.class,()->replicated.elementAt(1+3)); - assertEquals("b", replicated.elementAt(1+4)); - assertEquals("b", replicated.elementAt(1+5)); - } - - /** - * Tests that replication preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb = new StringBuilder("test"); - MyListP15 list = new MyListP15<>(sb); - MyListP15 replicated = list.replicate(3); - - assertEquals(3, replicated.length()); - for (int i = 0; i < 3; i++) { - assertSame(sb, replicated.elementAt(1+i)); - } - } - - /** - * Tests replication with different types. - */ - @Test - void testDifferentTypes() { - // Test with Integer - MyListP15 intList = new MyListP15<>(1, 2); - MyListP15 replicatedInts = intList.replicate(2); - assertEquals(4, replicatedInts.length()); - assertEquals(Integer.valueOf(1), replicatedInts.elementAt(1+0)); - assertEquals(Integer.valueOf(1), replicatedInts.elementAt(1+1)); - assertEquals(Integer.valueOf(2), replicatedInts.elementAt(1+2)); - assertEquals(Integer.valueOf(2), replicatedInts.elementAt(1+3)); - - // Test with Double - MyListP15 doubleList = new MyListP15<>(1.0, 2.0); - MyListP15 replicatedDoubles = doubleList.replicate(2); - assertEquals(4, replicatedDoubles.length()); - assertEquals(1.0, replicatedDoubles.elementAt(1+0), 0.001); - assertEquals(1.0, replicatedDoubles.elementAt(1+1), 0.001); - assertEquals(2.0, replicatedDoubles.elementAt(1+2), 0.001); - assertEquals(2.0, replicatedDoubles.elementAt(1+3), 0.001); - } - - /** - * Tests replication with large numbers. - */ - @Test - void testLargeReplication() { - MyListP15 list = new MyListP15<>("a"); - MyListP15 replicated = list.replicate(1000); - assertEquals(1000, replicated.length()); - for (int i = 0; i < 1000; i++) { - assertEquals("a", replicated.elementAt(1+i)); - } - } - - /** - * Tests replication with single occurrence. - */ - @Test - void testSingleReplication() { - MyListP15 list = new MyListP15<>("a", "b", "c"); - MyListP15 replicated = list.replicate(1); - assertEquals(3, replicated.length()); - assertEquals("a", replicated.elementAt(1+0)); - assertEquals("b", replicated.elementAt(1+1)); - assertEquals("c", replicated.elementAt(1+2)); + } + + /** Tests replication with different types. */ + @Test + void testDifferentTypes() { + // Test with Integer + MyListP15 intList = new MyListP15<>(1, 2); + MyListP15 replicatedInts = intList.replicate(2); + assertEquals(4, replicatedInts.length()); + assertEquals(Integer.valueOf(1), replicatedInts.elementAt(1 + 0)); + assertEquals(Integer.valueOf(1), replicatedInts.elementAt(1 + 1)); + assertEquals(Integer.valueOf(2), replicatedInts.elementAt(1 + 2)); + assertEquals(Integer.valueOf(2), replicatedInts.elementAt(1 + 3)); + + // Test with Double + MyListP15 doubleList = new MyListP15<>(1.0, 2.0); + MyListP15 replicatedDoubles = doubleList.replicate(2); + assertEquals(4, replicatedDoubles.length()); + assertEquals(1.0, replicatedDoubles.elementAt(1 + 0), 0.001); + assertEquals(1.0, replicatedDoubles.elementAt(1 + 1), 0.001); + assertEquals(2.0, replicatedDoubles.elementAt(1 + 2), 0.001); + assertEquals(2.0, replicatedDoubles.elementAt(1 + 3), 0.001); + } + + /** Tests replication with large numbers. */ + @Test + void testLargeReplication() { + MyListP15 list = new MyListP15<>("a"); + MyListP15 replicated = list.replicate(1000); + assertEquals(1000, replicated.length()); + for (int i = 0; i < 1000; i++) { + assertEquals("a", replicated.elementAt(1 + i)); } + } + + /** Tests replication with single occurrence. */ + @Test + void testSingleReplication() { + MyListP15 list = new MyListP15<>("a", "b", "c"); + MyListP15 replicated = list.replicate(1); + assertEquals(3, replicated.length()); + assertEquals("a", replicated.elementAt(1 + 0)); + assertEquals("b", replicated.elementAt(1 + 1)); + assertEquals("c", replicated.elementAt(1 + 2)); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP16Test.java b/src/test/java/org/nintynine/problems/MyListP16Test.java index c23308b..cfa052e 100644 --- a/src/test/java/org/nintynine/problems/MyListP16Test.java +++ b/src/test/java/org/nintynine/problems/MyListP16Test.java @@ -1,152 +1,128 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP16's element dropping functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP16's element dropping functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP16Test { - /** - * Tests basic dropping of elements. - */ - @Test - void testBasicDrop() { - MyListP16 list = new MyListP16<>("a", "b", "c", "d", "e", "f"); - MyListP16 dropped = list.drop(3); - - assertEquals(4, dropped.length()); - assertEquals("a", dropped.elementAt(1+0)); - assertEquals("b", dropped.elementAt(1+1)); - assertEquals("d", dropped.elementAt(1+2)); - assertEquals("e", dropped.elementAt(1+3)); - } - - /** - * Tests dropping with n=1 (should result in empty list). - */ - @Test - void testDropEveryElement() { - MyListP16 list = new MyListP16<>("a", "b", "c"); - MyListP16 dropped = list.drop(1); - assertEquals(0, dropped.length()); - } - - /** - * Tests dropping with n greater than list length. - */ - @Test - void testDropGreaterThanLength() { - MyListP16 list = new MyListP16<>("a", "b", "c"); - MyListP16 dropped = list.drop(4); - - assertEquals(3, dropped.length()); - assertEquals("a", dropped.elementAt(1+0)); - assertEquals("b", dropped.elementAt(1+1)); - assertEquals("c", dropped.elementAt(1+2)); - } - - /** - * Tests dropping from empty list. - */ - @Test - void testEmptyList() { - MyListP16 list = new MyListP16<>(); - MyListP16 dropped = list.drop(2); - assertEquals(0, dropped.length()); - } - - /** - * Tests dropping with invalid n. - */ - @Test - void testInvalidN() { - MyListP16 list = new MyListP16<>("a", "b", "c"); - assertThrows(IllegalArgumentException.class, () -> list.drop(0)); - assertThrows(IllegalArgumentException.class, () -> list.drop(-1)); - } - - /** - * Tests dropping with null values in list. - */ - @Test - void testWithNulls() { - MyListP16 list = new MyListP16<>("a", null, "b", null, "c"); - MyListP16 dropped = list.drop(2); - - assertEquals(3, dropped.length()); - assertEquals("a", dropped.elementAt(1+0)); - assertEquals("b", dropped.elementAt(1+1)); - assertEquals("c", dropped.elementAt(1+2)); - } - - /** - * Tests that object references are preserved. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("test1"); - StringBuilder sb2 = new StringBuilder("test2"); - StringBuilder sb3 = new StringBuilder("test3"); - - MyListP16 list = new MyListP16<>(sb1, sb2, sb3); - MyListP16 dropped = list.drop(2); - - assertEquals(2, dropped.length()); - assertSame(sb1, dropped.elementAt(1+0)); - assertSame(sb3, dropped.elementAt(1+1)); - } - - - - /** - * Tests dropping with different types. - */ - @Test - void testDifferentTypes() { - MyListP16 intList = new MyListP16<>(1, 2, 3, 4, 5); - MyListP16 droppedInts = intList.drop(2); - - assertEquals(3, droppedInts.length()); - assertEquals(Integer.valueOf(1), droppedInts.elementAt(1+0)); - assertEquals(Integer.valueOf(3), droppedInts.elementAt(1+1)); - assertEquals(Integer.valueOf(5), droppedInts.elementAt(1+2)); - - MyListP16 doubleList = new MyListP16<>(1.0, 2.0, 3.0, 4.0); - MyListP16 droppedDoubles = doubleList.drop(3); - - assertEquals(3, droppedDoubles.length()); - assertEquals(1.0, droppedDoubles.elementAt(1+0), 0.001); - assertEquals(2.0, droppedDoubles.elementAt(1+1), 0.001); - assertEquals(4.0, droppedDoubles.elementAt(1+2), 0.001); - } - - /** - * Tests dropping with single element list. - */ - @Test - void testSingleElement() { - MyListP16 list = new MyListP16<>("a"); - MyListP16 dropped = list.drop(2); - - assertEquals(1, dropped.length()); - assertEquals("a", dropped.elementAt(1+0)); - } - - /** - * Tests dropping with a large n value. - */ - @Test - void testLargeN() { - MyListP16 list = new MyListP16<>("a", "b", "c"); - MyListP16 dropped = list.drop(1000); - - assertEquals(3, dropped.length()); - assertEquals("a", dropped.elementAt(1+0)); - assertEquals("b", dropped.elementAt(1+1)); - assertEquals("c", dropped.elementAt(1+2)); - } + /** Tests basic dropping of elements. */ + @Test + void testBasicDrop() { + MyListP16 list = new MyListP16<>("a", "b", "c", "d", "e", "f"); + MyListP16 dropped = list.drop(3); + + assertEquals(4, dropped.length()); + assertEquals("a", dropped.elementAt(1 + 0)); + assertEquals("b", dropped.elementAt(1 + 1)); + assertEquals("d", dropped.elementAt(1 + 2)); + assertEquals("e", dropped.elementAt(1 + 3)); + } + + /** Tests dropping with n=1 (should result in empty list). */ + @Test + void testDropEveryElement() { + MyListP16 list = new MyListP16<>("a", "b", "c"); + MyListP16 dropped = list.drop(1); + assertEquals(0, dropped.length()); + } + + /** Tests dropping with n greater than list length. */ + @Test + void testDropGreaterThanLength() { + MyListP16 list = new MyListP16<>("a", "b", "c"); + MyListP16 dropped = list.drop(4); + + assertEquals(3, dropped.length()); + assertEquals("a", dropped.elementAt(1 + 0)); + assertEquals("b", dropped.elementAt(1 + 1)); + assertEquals("c", dropped.elementAt(1 + 2)); + } + + /** Tests dropping from empty list. */ + @Test + void testEmptyList() { + MyListP16 list = new MyListP16<>(); + MyListP16 dropped = list.drop(2); + assertEquals(0, dropped.length()); + } + + /** Tests dropping with invalid n. */ + @Test + void testInvalidN() { + MyListP16 list = new MyListP16<>("a", "b", "c"); + assertThrows(IllegalArgumentException.class, () -> list.drop(0)); + assertThrows(IllegalArgumentException.class, () -> list.drop(-1)); + } + + /** Tests dropping with null values in list. */ + @Test + void testWithNulls() { + MyListP16 list = new MyListP16<>("a", null, "b", null, "c"); + MyListP16 dropped = list.drop(2); + + assertEquals(3, dropped.length()); + assertEquals("a", dropped.elementAt(1 + 0)); + assertEquals("b", dropped.elementAt(1 + 1)); + assertEquals("c", dropped.elementAt(1 + 2)); + } + + /** Tests that object references are preserved. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("test1"); + StringBuilder sb2 = new StringBuilder("test2"); + StringBuilder sb3 = new StringBuilder("test3"); + + MyListP16 list = new MyListP16<>(sb1, sb2, sb3); + MyListP16 dropped = list.drop(2); + + assertEquals(2, dropped.length()); + assertSame(sb1, dropped.elementAt(1 + 0)); + assertSame(sb3, dropped.elementAt(1 + 1)); + } + + /** Tests dropping with different types. */ + @Test + void testDifferentTypes() { + MyListP16 intList = new MyListP16<>(1, 2, 3, 4, 5); + MyListP16 droppedInts = intList.drop(2); + + assertEquals(3, droppedInts.length()); + assertEquals(Integer.valueOf(1), droppedInts.elementAt(1 + 0)); + assertEquals(Integer.valueOf(3), droppedInts.elementAt(1 + 1)); + assertEquals(Integer.valueOf(5), droppedInts.elementAt(1 + 2)); + + MyListP16 doubleList = new MyListP16<>(1.0, 2.0, 3.0, 4.0); + MyListP16 droppedDoubles = doubleList.drop(3); + + assertEquals(3, droppedDoubles.length()); + assertEquals(1.0, droppedDoubles.elementAt(1 + 0), 0.001); + assertEquals(2.0, droppedDoubles.elementAt(1 + 1), 0.001); + assertEquals(4.0, droppedDoubles.elementAt(1 + 2), 0.001); + } + + /** Tests dropping with single element list. */ + @Test + void testSingleElement() { + MyListP16 list = new MyListP16<>("a"); + MyListP16 dropped = list.drop(2); + + assertEquals(1, dropped.length()); + assertEquals("a", dropped.elementAt(1 + 0)); + } + + /** Tests dropping with a large n value. */ + @Test + void testLargeN() { + MyListP16 list = new MyListP16<>("a", "b", "c"); + MyListP16 dropped = list.drop(1000); + + assertEquals(3, dropped.length()); + assertEquals("a", dropped.elementAt(1 + 0)); + assertEquals("b", dropped.elementAt(1 + 1)); + assertEquals("c", dropped.elementAt(1 + 2)); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP17Test.java b/src/test/java/org/nintynine/problems/MyListP17Test.java index 4149bb5..22acbc6 100644 --- a/src/test/java/org/nintynine/problems/MyListP17Test.java +++ b/src/test/java/org/nintynine/problems/MyListP17Test.java @@ -1,159 +1,139 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -/** - * Test class for MyListP17's list splitting functionality. - */ +import org.junit.jupiter.api.Test; + +/** Test class for MyListP17's list splitting functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP17Test { - /** - * Tests basic list splitting. - */ - @Test - void testBasicSplit() { - MyListP17 list = new MyListP17<>("a", "b", "c", "d", "e"); - MyListP17.Pair, MyListP17> result = list.split(3); - - MyListP17 first = result.first(); - MyListP17 second = result.second(); - - assertEquals(3, first.length()); - assertEquals(2, second.length()); - - assertEquals("a", first.elementAt(1+0)); - assertEquals("b", first.elementAt(1+1)); - assertEquals("c", first.elementAt(1+2)); - - assertEquals("d", second.elementAt(1+0)); - assertEquals("e", second.elementAt(1+1)); - } - - /** - * Tests splitting at position 0. - */ - @Test - void testSplitAtZero() { - MyListP17 list = new MyListP17<>("a", "b", "c"); - MyListP17.Pair, MyListP17> result = list.split(0); - - assertEquals(0, result.first().length()); - assertEquals(3, result.second().length()); - assertEquals("a", result.second().elementAt(1+0)); - assertEquals("c", result.second().elementAt(1+2)); - } - - /** - * Tests splitting at list length. - */ - @Test - void testSplitAtLength() { - MyListP17 list = new MyListP17<>("a", "b", "c"); - MyListP17.Pair, MyListP17> result = list.split(3); - - assertEquals(3, result.first().length()); - assertEquals(0, result.second().length()); - assertEquals("a", result.first().elementAt(1+0)); - assertEquals("c", result.first().elementAt(1+2)); - } - - /** - * Tests splitting empty list. - */ - @Test - void testEmptyList() { - MyListP17 list = new MyListP17<>(); - MyListP17.Pair, MyListP17> result = list.split(0); - - assertEquals(0, result.first().length()); - assertEquals(0, result.second().length()); - } - - /** - * Tests invalid split positions. - */ - @Test - void testInvalidPositions() { - MyListP17 list = new MyListP17<>("a", "b", "c"); - - assertThrows(IllegalArgumentException.class, () -> list.split(-1)); - assertThrows(IllegalArgumentException.class, () -> list.split(4)); - } - - /** - * Tests splitting with null values. - */ - @Test - void testWithNulls() { - MyListP17 list = new MyListP17<>("a", null, "b", null); - MyListP17.Pair, MyListP17> result = list.split(2); - - MyListP17 firstItem = result.first(); - assertEquals(2, firstItem.length()); - MyListP17 secondItem = result.second(); - assertEquals(2, secondItem.length()); - - assertEquals("a", firstItem.elementAt(1+0)); - assertThrows(NullPointerException.class,()-> firstItem.elementAt(1+1)); - assertEquals("b", secondItem.elementAt(1+0)); - assertThrows(NullPointerException.class,()-> secondItem.elementAt(1+1)); - } - - /** - * Tests that object references are preserved. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("test1"); - StringBuilder sb2 = new StringBuilder("test2"); - - MyListP17 list = new MyListP17<>(sb1, sb2); - MyListP17.Pair, MyListP17> result = list.split(1); - - assertSame(sb1, result.first().elementAt(1+0)); - assertSame(sb2, result.second().elementAt(1+0)); - } - - /** - * Tests splitting with different types. - */ - @Test - void testDifferentTypes() { - MyListP17 intList = new MyListP17<>(1, 2, 3, 4); - MyListP17.Pair, MyListP17> intResult = intList.split(2); - - assertEquals(2, intResult.first().length()); - assertEquals(2, intResult.second().length()); - assertEquals(Integer.valueOf(1), intResult.first().elementAt(1+0)); - assertEquals(Integer.valueOf(3), intResult.second().elementAt(1+0)); - - MyListP17 doubleList = new MyListP17<>(1.0, 2.0, 3.0); - MyListP17.Pair, MyListP17> doubleResult = doubleList.split(2); - - assertEquals(2, doubleResult.first().length()); - assertEquals(1, doubleResult.second().length()); - assertEquals(1.0, doubleResult.first().elementAt(1+0), 0.001); - assertEquals(3.0, doubleResult.second().elementAt(1+0), 0.001); - } - - /** - * Tests Pair class equality. - */ - @Test - void testPairEquality() { - MyListP17 list1 = new MyListP17<>("a", "b"); - MyListP17 list2 = new MyListP17<>("c"); - - MyListP17.Pair, MyListP17> pair1 = new MyListP17.Pair<>(list1, list2); - MyListP17.Pair, MyListP17> pair2 = new MyListP17.Pair<>(list1, list2); - MyListP17.Pair, MyListP17> pair3 = new MyListP17.Pair<>(list2, list1); - - assertEquals(pair1, pair2); - assertNotEquals(pair1, pair3); - assertNotEquals(null, pair1); - assertEquals(pair1.hashCode(), pair2.hashCode()); - } + /** Tests basic list splitting. */ + @Test + void testBasicSplit() { + MyListP17 list = new MyListP17<>("a", "b", "c", "d", "e"); + MyListP17.Pair, MyListP17> result = list.split(3); + + MyListP17 first = result.first(); + MyListP17 second = result.second(); + + assertEquals(3, first.length()); + assertEquals(2, second.length()); + + assertEquals("a", first.elementAt(1 + 0)); + assertEquals("b", first.elementAt(1 + 1)); + assertEquals("c", first.elementAt(1 + 2)); + + assertEquals("d", second.elementAt(1 + 0)); + assertEquals("e", second.elementAt(1 + 1)); + } + + /** Tests splitting at position 0. */ + @Test + void testSplitAtZero() { + MyListP17 list = new MyListP17<>("a", "b", "c"); + MyListP17.Pair, MyListP17> result = list.split(0); + + assertEquals(0, result.first().length()); + assertEquals(3, result.second().length()); + assertEquals("a", result.second().elementAt(1 + 0)); + assertEquals("c", result.second().elementAt(1 + 2)); + } + + /** Tests splitting at list length. */ + @Test + void testSplitAtLength() { + MyListP17 list = new MyListP17<>("a", "b", "c"); + MyListP17.Pair, MyListP17> result = list.split(3); + + assertEquals(3, result.first().length()); + assertEquals(0, result.second().length()); + assertEquals("a", result.first().elementAt(1 + 0)); + assertEquals("c", result.first().elementAt(1 + 2)); + } + + /** Tests splitting empty list. */ + @Test + void testEmptyList() { + MyListP17 list = new MyListP17<>(); + MyListP17.Pair, MyListP17> result = list.split(0); + + assertEquals(0, result.first().length()); + assertEquals(0, result.second().length()); + } + + /** Tests invalid split positions. */ + @Test + void testInvalidPositions() { + MyListP17 list = new MyListP17<>("a", "b", "c"); + + assertThrows(IllegalArgumentException.class, () -> list.split(-1)); + assertThrows(IllegalArgumentException.class, () -> list.split(4)); + } + + /** Tests splitting with null values. */ + @Test + void testWithNulls() { + MyListP17 list = new MyListP17<>("a", null, "b", null); + MyListP17.Pair, MyListP17> result = list.split(2); + + MyListP17 firstItem = result.first(); + assertEquals(2, firstItem.length()); + MyListP17 secondItem = result.second(); + assertEquals(2, secondItem.length()); + + assertEquals("a", firstItem.elementAt(1 + 0)); + assertThrows(NullPointerException.class, () -> firstItem.elementAt(1 + 1)); + assertEquals("b", secondItem.elementAt(1 + 0)); + assertThrows(NullPointerException.class, () -> secondItem.elementAt(1 + 1)); + } + + /** Tests that object references are preserved. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("test1"); + StringBuilder sb2 = new StringBuilder("test2"); + + MyListP17 list = new MyListP17<>(sb1, sb2); + MyListP17.Pair, MyListP17> result = list.split(1); + + assertSame(sb1, result.first().elementAt(1 + 0)); + assertSame(sb2, result.second().elementAt(1 + 0)); + } + + /** Tests splitting with different types. */ + @Test + void testDifferentTypes() { + MyListP17 intList = new MyListP17<>(1, 2, 3, 4); + MyListP17.Pair, MyListP17> intResult = intList.split(2); + + assertEquals(2, intResult.first().length()); + assertEquals(2, intResult.second().length()); + assertEquals(Integer.valueOf(1), intResult.first().elementAt(1 + 0)); + assertEquals(Integer.valueOf(3), intResult.second().elementAt(1 + 0)); + + MyListP17 doubleList = new MyListP17<>(1.0, 2.0, 3.0); + MyListP17.Pair, MyListP17> doubleResult = doubleList.split(2); + + assertEquals(2, doubleResult.first().length()); + assertEquals(1, doubleResult.second().length()); + assertEquals(1.0, doubleResult.first().elementAt(1 + 0), 0.001); + assertEquals(3.0, doubleResult.second().elementAt(1 + 0), 0.001); + } + + /** Tests Pair class equality. */ + @Test + void testPairEquality() { + MyListP17 list1 = new MyListP17<>("a", "b"); + MyListP17 list2 = new MyListP17<>("c"); + + MyListP17.Pair, MyListP17> pair1 = new MyListP17.Pair<>(list1, list2); + MyListP17.Pair, MyListP17> pair2 = new MyListP17.Pair<>(list1, list2); + MyListP17.Pair, MyListP17> pair3 = new MyListP17.Pair<>(list2, list1); + + assertEquals(pair1, pair2); + assertNotEquals(pair1, pair3); + assertNotEquals(null, pair1); + assertEquals(pair1.hashCode(), pair2.hashCode()); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP18Test.java b/src/test/java/org/nintynine/problems/MyListP18Test.java index 30f5c4f..1a9a57e 100644 --- a/src/test/java/org/nintynine/problems/MyListP18Test.java +++ b/src/test/java/org/nintynine/problems/MyListP18Test.java @@ -1,186 +1,160 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP18's slice functionality. - */ +/** Test class for MyListP18's slice functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP18Test { - private MyListP18 list; - - @BeforeEach - void setUp() { - list = new MyListP18<>("a", "b", "c", "d", "e", "f", "g"); - } - - /** - * Tests basic slice extraction. - */ - @Test - void testBasicSlice() { - MyListP18 sliced = list.slice(3, 5); - - assertEquals(3, sliced.length()); - assertEquals("c", sliced.elementAt(1+0)); - assertEquals("d", sliced.elementAt(1+1)); - assertEquals("e", sliced.elementAt(1+2)); - } - - /** - * Tests slice of entire list. - */ - @Test - void testFullListSlice() { - MyListP18 sliced = list.slice(1, 7); - - assertEquals(7, sliced.length()); - assertEquals("a", sliced.elementAt(1+0)); - assertEquals("g", sliced.elementAt(1+6)); - } - - /** - * Tests single element slice. - */ - @Test - void testSingleElementSlice() { - MyListP18 sliced = list.slice(3, 3); - - assertEquals(1, sliced.length()); - assertEquals("c", sliced.elementAt(1+0)); - } - - /** - * Tests various invalid slice parameters. - */ - @Test - void testInvalidSliceParameters() { - assertThrows(IllegalArgumentException.class, () -> list.slice(0, 3)); - assertThrows(IllegalArgumentException.class, () -> list.slice(-1, 3)); - assertThrows(IllegalArgumentException.class, () -> list.slice(1, 8)); - assertThrows(IllegalArgumentException.class, () -> list.slice(4, 2)); - } - - /** - * Tests slice with null values. - */ - @Test - void testSliceWithNulls() { - MyListP18 listWithNulls = new MyListP18<>("a", null, "c", null, "e"); - MyListP18 sliced = listWithNulls.slice(2, 4); - - assertEquals(3, sliced.length()); - assertThrows(NullPointerException.class,()->sliced.elementAt(1+0)); - assertEquals("c", sliced.elementAt(1+1)); - assertThrows(NullPointerException.class,()->sliced.elementAt(1+2)); - } - - /** - * Tests that slice preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("test1"); - StringBuilder sb2 = new StringBuilder("test2"); - StringBuilder sb3 = new StringBuilder("test3"); - - MyListP18 builderList = new MyListP18<>(sb1, sb2, sb3); - MyListP18 sliced = builderList.slice(1, 2); - - assertEquals(2, sliced.length()); - assertSame(sb1, sliced.elementAt(1+0)); - assertSame(sb2, sliced.elementAt(1+1)); + private MyListP18 list; + + @BeforeEach + void setUp() { + list = new MyListP18<>("a", "b", "c", "d", "e", "f", "g"); + } + + /** Tests basic slice extraction. */ + @Test + void testBasicSlice() { + MyListP18 sliced = list.slice(3, 5); + + assertEquals(3, sliced.length()); + assertEquals("c", sliced.elementAt(1 + 0)); + assertEquals("d", sliced.elementAt(1 + 1)); + assertEquals("e", sliced.elementAt(1 + 2)); + } + + /** Tests slice of entire list. */ + @Test + void testFullListSlice() { + MyListP18 sliced = list.slice(1, 7); + + assertEquals(7, sliced.length()); + assertEquals("a", sliced.elementAt(1 + 0)); + assertEquals("g", sliced.elementAt(1 + 6)); + } + + /** Tests single element slice. */ + @Test + void testSingleElementSlice() { + MyListP18 sliced = list.slice(3, 3); + + assertEquals(1, sliced.length()); + assertEquals("c", sliced.elementAt(1 + 0)); + } + + /** Tests various invalid slice parameters. */ + @Test + void testInvalidSliceParameters() { + assertThrows(IllegalArgumentException.class, () -> list.slice(0, 3)); + assertThrows(IllegalArgumentException.class, () -> list.slice(-1, 3)); + assertThrows(IllegalArgumentException.class, () -> list.slice(1, 8)); + assertThrows(IllegalArgumentException.class, () -> list.slice(4, 2)); + } + + /** Tests slice with null values. */ + @Test + void testSliceWithNulls() { + MyListP18 listWithNulls = new MyListP18<>("a", null, "c", null, "e"); + MyListP18 sliced = listWithNulls.slice(2, 4); + + assertEquals(3, sliced.length()); + assertThrows(NullPointerException.class, () -> sliced.elementAt(1 + 0)); + assertEquals("c", sliced.elementAt(1 + 1)); + assertThrows(NullPointerException.class, () -> sliced.elementAt(1 + 2)); + } + + /** Tests that slice preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("test1"); + StringBuilder sb2 = new StringBuilder("test2"); + StringBuilder sb3 = new StringBuilder("test3"); + + MyListP18 builderList = new MyListP18<>(sb1, sb2, sb3); + MyListP18 sliced = builderList.slice(1, 2); + + assertEquals(2, sliced.length()); + assertSame(sb1, sliced.elementAt(1 + 0)); + assertSame(sb2, sliced.elementAt(1 + 1)); + } + + /** Tests slicing with different types. */ + @Test + void testDifferentTypes() { + // Test with integers + MyListP18 intList = new MyListP18<>(1, 2, 3, 4, 5); + MyListP18 intSliced = intList.slice(2, 4); + + assertEquals(3, intSliced.length()); + assertEquals(Integer.valueOf(2), intSliced.elementAt(1 + 0)); + assertEquals(Integer.valueOf(4), intSliced.elementAt(1 + 2)); + + // Test with doubles + MyListP18 doubleList = new MyListP18<>(1.0, 2.0, 3.0, 4.0); + MyListP18 doubleSliced = doubleList.slice(2, 3); + + assertEquals(2, doubleSliced.length()); + assertEquals(2.0, doubleSliced.elementAt(1 + 0), 0.001); + assertEquals(3.0, doubleSliced.elementAt(1 + 1), 0.001); + } + + /** Tests slice at list boundaries. */ + @Test + void testBoundarySlices() { + // Slice from start + MyListP18 startSlice = list.slice(1, 3); + assertEquals(3, startSlice.length()); + assertEquals("a", startSlice.elementAt(1 + 0)); + assertEquals("c", startSlice.elementAt(1 + 2)); + + // Slice to end + MyListP18 endSlice = list.slice(5, 7); + assertEquals(3, endSlice.length()); + assertEquals("e", endSlice.elementAt(1 + 0)); + assertEquals("g", endSlice.elementAt(1 + 2)); + } + + /** Tests slice with empty list. */ + @Test + void testEmptyList() { + MyListP18 emptyList = new MyListP18<>(); + assertThrows(IllegalArgumentException.class, () -> emptyList.slice(1, 1)); + } + + /** Tests slice with consecutive indices. */ + @Test + void testConsecutiveIndices() { + for (int i = 1; i < list.length(); i++) { + MyListP18 sliced = list.slice(i, i + 1); + assertEquals(2, sliced.length()); + assertEquals(list.elementAt(1 + i - 1), sliced.elementAt(1 + 0)); + assertEquals(list.elementAt(1 + i), sliced.elementAt(1 + 1)); } + } - /** - * Tests slicing with different types. - */ - @Test - void testDifferentTypes() { - // Test with integers - MyListP18 intList = new MyListP18<>(1, 2, 3, 4, 5); - MyListP18 intSliced = intList.slice(2, 4); - - assertEquals(3, intSliced.length()); - assertEquals(Integer.valueOf(2), intSliced.elementAt(1+0)); - assertEquals(Integer.valueOf(4), intSliced.elementAt(1+2)); - - // Test with doubles - MyListP18 doubleList = new MyListP18<>(1.0, 2.0, 3.0, 4.0); - MyListP18 doubleSliced = doubleList.slice(2, 3); - - assertEquals(2, doubleSliced.length()); - assertEquals(2.0, doubleSliced.elementAt(1+0), 0.001); - assertEquals(3.0, doubleSliced.elementAt(1+1), 0.001); - } + /** Tests that slicing creates a new independent list. */ + @Test + void testSliceIndependence() { + StringBuilder[] builders = { + new StringBuilder("1"), new StringBuilder("2"), new StringBuilder("3") + }; - /** - * Tests slice at list boundaries. - */ - @Test - void testBoundarySlices() { - // Slice from start - MyListP18 startSlice = list.slice(1, 3); - assertEquals(3, startSlice.length()); - assertEquals("a", startSlice.elementAt(1+0)); - assertEquals("c", startSlice.elementAt(1+2)); - - // Slice to end - MyListP18 endSlice = list.slice(5, 7); - assertEquals(3, endSlice.length()); - assertEquals("e", endSlice.elementAt(1+0)); - assertEquals("g", endSlice.elementAt(1+2)); - } + MyListP18 originalList = new MyListP18<>(builders); + MyListP18 sliced = originalList.slice(1, 2); - /** - * Tests slice with empty list. - */ - @Test - void testEmptyList() { - MyListP18 emptyList = new MyListP18<>(); - assertThrows(IllegalArgumentException.class, () -> emptyList.slice(1, 1)); - } + // Modify original StringBuilder objects + builders[0].append("-modified"); + builders[1].append("-modified"); - /** - * Tests slice with consecutive indices. - */ - @Test - void testConsecutiveIndices() { - for (int i = 1; i < list.length(); i++) { - MyListP18 sliced = list.slice(i, i + 1); - assertEquals(2, sliced.length()); - assertEquals(list.elementAt(1+i - 1), sliced.elementAt(1+0)); - assertEquals(list.elementAt(1+i), sliced.elementAt(1+1)); - } - } + // Changes should be reflected in both lists since they share references + assertEquals("1-modified", sliced.elementAt(1 + 0).toString()); + assertEquals("2-modified", sliced.elementAt(1 + 1).toString()); - /** - * Tests that slicing creates a new independent list. - */ - @Test - void testSliceIndependence() { - StringBuilder[] builders = { - new StringBuilder("1"), - new StringBuilder("2"), - new StringBuilder("3") - }; - - MyListP18 originalList = new MyListP18<>(builders); - MyListP18 sliced = originalList.slice(1, 2); - - // Modify original StringBuilder objects - builders[0].append("-modified"); - builders[1].append("-modified"); - - // Changes should be reflected in both lists since they share references - assertEquals("1-modified", sliced.elementAt(1+0).toString()); - assertEquals("2-modified", sliced.elementAt(1+1).toString()); - - // But the lists themselves should be independent - assertNotSame(originalList, sliced); - } + // But the lists themselves should be independent + assertNotSame(originalList, sliced); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP19Test.java b/src/test/java/org/nintynine/problems/MyListP19Test.java index cdd1dd3..f008821 100644 --- a/src/test/java/org/nintynine/problems/MyListP19Test.java +++ b/src/test/java/org/nintynine/problems/MyListP19Test.java @@ -1,196 +1,169 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP19's rotation functionality. - */ +/** Test class for MyListP19's rotation functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP19Test { - private MyListP19 list; - - @BeforeEach - void setUp() { - list = new MyListP19<>("a", "b", "c", "d", "e"); - } - - /** - * Tests basic left rotation. - */ - @Test - void testLeftRotation() { - MyListP19 rotated = list.rotate(2); - - assertEquals(5, rotated.length()); - assertEquals("c", rotated.elementAt(1+(0))); - assertEquals("d", rotated.elementAt(1+(1))); - assertEquals("e", rotated.elementAt(1+(2))); - assertEquals("a", rotated.elementAt(1+(3))); - assertEquals("b", rotated.elementAt(1+(4))); + private MyListP19 list; + + @BeforeEach + void setUp() { + list = new MyListP19<>("a", "b", "c", "d", "e"); + } + + /** Tests basic left rotation. */ + @Test + void testLeftRotation() { + MyListP19 rotated = list.rotate(2); + + assertEquals(5, rotated.length()); + assertEquals("c", rotated.elementAt(1 + (0))); + assertEquals("d", rotated.elementAt(1 + (1))); + assertEquals("e", rotated.elementAt(1 + (2))); + assertEquals("a", rotated.elementAt(1 + (3))); + assertEquals("b", rotated.elementAt(1 + (4))); + } + + /** Tests basic right rotation. */ + @Test + void testRightRotation() { + MyListP19 rotated = list.rotate(-2); + + assertEquals(5, rotated.length()); + assertEquals("d", rotated.elementAt(1 + (0))); + assertEquals("e", rotated.elementAt(1 + (1))); + assertEquals("a", rotated.elementAt(1 + (2))); + assertEquals("b", rotated.elementAt(1 + (3))); + assertEquals("c", rotated.elementAt(1 + (4))); + } + + /** Tests rotation with zero places. */ + @Test + void testZeroRotation() { + MyListP19 rotated = list.rotate(0); + + assertEquals(5, rotated.length()); + for (int i = 0; i < list.length(); i++) { + assertEquals(list.elementAt(1 + (i)), rotated.elementAt(1 + (i))); } + } - /** - * Tests basic right rotation. - */ - @Test - void testRightRotation() { - MyListP19 rotated = list.rotate(-2); - - assertEquals(5, rotated.length()); - assertEquals("d", rotated.elementAt(1+(0))); - assertEquals("e", rotated.elementAt(1+(1))); - assertEquals("a", rotated.elementAt(1+(2))); - assertEquals("b", rotated.elementAt(1+(3))); - assertEquals("c", rotated.elementAt(1+(4))); - } + /** Tests rotation with list length places. */ + @Test + void testFullRotation() { + MyListP19 rotated = list.rotate(Math.toIntExact(list.length())); - /** - * Tests rotation with zero places. - */ - @Test - void testZeroRotation() { - MyListP19 rotated = list.rotate(0); - - assertEquals(5, rotated.length()); - for (int i = 0; i < list.length(); i++) { - assertEquals(list.elementAt(1+(i)), rotated.elementAt(1+(i))); - } + assertEquals(5, rotated.length()); + for (int i = 0; i < list.length(); i++) { + assertEquals(list.elementAt(1 + (i)), rotated.elementAt(1 + (i))); } + } - /** - * Tests rotation with list length places. - */ - @Test - void testFullRotation() { - MyListP19 rotated = list.rotate(Math.toIntExact(list.length())); - - assertEquals(5, rotated.length()); - for (int i = 0; i < list.length(); i++) { - assertEquals(list.elementAt(1+(i)), rotated.elementAt(1+(i))); - } - } + /** Tests rotation with places greater than list length. */ + @Test + void testRotationGreaterThanLength() { + MyListP19 rotated = list.rotate(7); // Equivalent to rotate(2) + MyListP19 expected = list.rotate(2); - /** - * Tests rotation with places greater than list length. - */ - @Test - void testRotationGreaterThanLength() { - MyListP19 rotated = list.rotate(7); // Equivalent to rotate(2) - MyListP19 expected = list.rotate(2); - - assertEquals(expected.length(), rotated.length()); - for (int i = 0; i < rotated.length(); i++) { - assertEquals(expected.elementAt(1+(i)), rotated.elementAt(1+(i))); - } + assertEquals(expected.length(), rotated.length()); + for (int i = 0; i < rotated.length(); i++) { + assertEquals(expected.elementAt(1 + (i)), rotated.elementAt(1 + (i))); } - - /** - * Tests rotation with empty list. - */ - @Test - void testEmptyList() { - MyListP19 emptyList = new MyListP19<>(); - MyListP19 rotated = emptyList.rotate(5); - - assertEquals(0, rotated.length()); - } - - /** - * Tests rotation with single element. - */ - @Test - void testSingleElement() { - MyListP19 singleList = new MyListP19<>("a"); - MyListP19 rotated = singleList.rotate(3); - - assertEquals(1, rotated.length()); - assertEquals("a", rotated.elementAt(1+(0))); - } - - /** - * Tests rotation with null values. - */ - @Test - void testRotationWithNulls() { - MyListP19 listWithNulls = new MyListP19<>("a", null, "c", null); - assertThrows(NullPointerException.class,()->listWithNulls.rotate(2)); - - } - - /** - * Tests that rotation preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("1"); - StringBuilder sb2 = new StringBuilder("2"); - StringBuilder sb3 = new StringBuilder("3"); - - MyListP19 builderList = new MyListP19<>(sb1, sb2, sb3); - MyListP19 rotated = builderList.rotate(1); - - assertEquals(3, rotated.length()); - assertSame(sb2, rotated.elementAt(1+(0))); - assertSame(sb3, rotated.elementAt(1+(1))); - assertSame(sb1, rotated.elementAt(1+(2))); - } - - /** - * Tests rotation with different types. - */ - @Test - void testDifferentTypes() { - MyListP19 intList = new MyListP19<>(1, 2, 3, 4); - MyListP19 rotatedInts = intList.rotate(2); - - assertEquals(4, rotatedInts.length()); - assertEquals(Integer.valueOf(3), rotatedInts.elementAt(1+(0))); - assertEquals(Integer.valueOf(4), rotatedInts.elementAt(1+(1))); - assertEquals(Integer.valueOf(1), rotatedInts.elementAt(1+(2))); - assertEquals(Integer.valueOf(2), rotatedInts.elementAt(1+(3))); - - MyListP19 doubleList = new MyListP19<>(1.0, 2.0, 3.0); - MyListP19 rotatedDoubles = doubleList.rotate(-1); - - assertEquals(3, rotatedDoubles.length()); - assertEquals(3.0, rotatedDoubles.elementAt(1+(0)), 0.001); - assertEquals(1.0, rotatedDoubles.elementAt(1+(1)), 0.001); - assertEquals(2.0, rotatedDoubles.elementAt(1+(2)), 0.001); - } - - /** - * Tests rotation with large numbers. - */ - @Test - void testLargeRotations() { - int bigPositive = Integer.MAX_VALUE; - int bigNegative = Integer.MIN_VALUE; - - MyListP19 rotated1 = list.rotate(bigPositive); - MyListP19 rotated2 = list.rotate(bigNegative); - - // Both rotations should be equivalent to some rotation between 0 and list.length() - assertEquals(5, rotated1.length()); - assertEquals(5, rotated2.length()); - } - - /** - * Tests consecutive rotations. - */ - @Test - void testConsecutiveRotations() { - MyListP19 rotated = list - .rotate(2) // rotate left by 2 - .rotate(-2); // rotate right by 2 - - // Should be back to original - assertEquals(5, rotated.length()); - for (int i = 0; i < list.length(); i++) { - assertEquals(list.elementAt(1+(i)), rotated.elementAt(1+(i))); - } + } + + /** Tests rotation with empty list. */ + @Test + void testEmptyList() { + MyListP19 emptyList = new MyListP19<>(); + MyListP19 rotated = emptyList.rotate(5); + + assertEquals(0, rotated.length()); + } + + /** Tests rotation with single element. */ + @Test + void testSingleElement() { + MyListP19 singleList = new MyListP19<>("a"); + MyListP19 rotated = singleList.rotate(3); + + assertEquals(1, rotated.length()); + assertEquals("a", rotated.elementAt(1 + (0))); + } + + /** Tests rotation with null values. */ + @Test + void testRotationWithNulls() { + MyListP19 listWithNulls = new MyListP19<>("a", null, "c", null); + assertThrows(NullPointerException.class, () -> listWithNulls.rotate(2)); + } + + /** Tests that rotation preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("1"); + StringBuilder sb2 = new StringBuilder("2"); + StringBuilder sb3 = new StringBuilder("3"); + + MyListP19 builderList = new MyListP19<>(sb1, sb2, sb3); + MyListP19 rotated = builderList.rotate(1); + + assertEquals(3, rotated.length()); + assertSame(sb2, rotated.elementAt(1 + (0))); + assertSame(sb3, rotated.elementAt(1 + (1))); + assertSame(sb1, rotated.elementAt(1 + (2))); + } + + /** Tests rotation with different types. */ + @Test + void testDifferentTypes() { + MyListP19 intList = new MyListP19<>(1, 2, 3, 4); + MyListP19 rotatedInts = intList.rotate(2); + + assertEquals(4, rotatedInts.length()); + assertEquals(Integer.valueOf(3), rotatedInts.elementAt(1 + (0))); + assertEquals(Integer.valueOf(4), rotatedInts.elementAt(1 + (1))); + assertEquals(Integer.valueOf(1), rotatedInts.elementAt(1 + (2))); + assertEquals(Integer.valueOf(2), rotatedInts.elementAt(1 + (3))); + + MyListP19 doubleList = new MyListP19<>(1.0, 2.0, 3.0); + MyListP19 rotatedDoubles = doubleList.rotate(-1); + + assertEquals(3, rotatedDoubles.length()); + assertEquals(3.0, rotatedDoubles.elementAt(1 + (0)), 0.001); + assertEquals(1.0, rotatedDoubles.elementAt(1 + (1)), 0.001); + assertEquals(2.0, rotatedDoubles.elementAt(1 + (2)), 0.001); + } + + /** Tests rotation with large numbers. */ + @Test + void testLargeRotations() { + int bigPositive = Integer.MAX_VALUE; + int bigNegative = Integer.MIN_VALUE; + + MyListP19 rotated1 = list.rotate(bigPositive); + MyListP19 rotated2 = list.rotate(bigNegative); + + // Both rotations should be equivalent to some rotation between 0 and list.length() + assertEquals(5, rotated1.length()); + assertEquals(5, rotated2.length()); + } + + /** Tests consecutive rotations. */ + @Test + void testConsecutiveRotations() { + MyListP19 rotated = + list.rotate(2) // rotate left by 2 + .rotate(-2); // rotate right by 2 + + // Should be back to original + assertEquals(5, rotated.length()); + for (int i = 0; i < list.length(); i++) { + assertEquals(list.elementAt(1 + (i)), rotated.elementAt(1 + (i))); } + } } diff --git a/src/test/java/org/nintynine/problems/MyListP20Test.java b/src/test/java/org/nintynine/problems/MyListP20Test.java index 6d1c14f..408d92d 100644 --- a/src/test/java/org/nintynine/problems/MyListP20Test.java +++ b/src/test/java/org/nintynine/problems/MyListP20Test.java @@ -1,212 +1,187 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP20's element removal functionality. - */ +/** Test class for MyListP20's element removal functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP20Test { - private MyListP20 list; - - @BeforeEach - void setUp() { - list = new MyListP20<>("a", "b", "c", "d", "e"); - } - - /** - * Tests basic element removal. - */ - @Test - void testBasicRemoval() { - MyListP17.Pair> result = list.removeAt(2); - - assertEquals("b", result.first()); - MyListP20 newList = result.second(); - - assertEquals(4, newList.length()); - assertEquals("a", newList.elementAt(1+(0))); - assertEquals("c", newList.elementAt(1+(1))); - assertEquals("d", newList.elementAt(1+(2))); - assertEquals("e", newList.elementAt(1+(3))); - } - - /** - * Tests removal of first element. - */ - @Test - void testRemoveFirst() { - MyListP17.Pair> result = list.removeAt(1); - - assertEquals("a", result.first()); - MyListP20 newList = result.second(); - - assertEquals(4, newList.length()); - assertEquals("b", newList.elementAt(1+(0))); - assertEquals("e", newList.elementAt(1+(3))); - } - - /** - * Tests removal of last element. - */ - @Test - void testRemoveLast() { - MyListP17.Pair> result = list.removeAt(5); - - assertEquals("e", result.first()); - MyListP20 newList = result.second(); - - assertEquals(4, newList.length()); - assertEquals("a", newList.elementAt(1+(0))); - assertEquals("d", newList.elementAt(1+(3))); - } - - /** - * Tests invalid positions. - */ - @Test - void testInvalidPositions() { - assertThrows(IllegalArgumentException.class, () -> list.removeAt(0)); - assertThrows(IllegalArgumentException.class, () -> list.removeAt(-1)); - assertThrows(IllegalArgumentException.class, () -> list.removeAt(6)); + private MyListP20 list; + + @BeforeEach + void setUp() { + list = new MyListP20<>("a", "b", "c", "d", "e"); + } + + /** Tests basic element removal. */ + @Test + void testBasicRemoval() { + MyListP17.Pair> result = list.removeAt(2); + + assertEquals("b", result.first()); + MyListP20 newList = result.second(); + + assertEquals(4, newList.length()); + assertEquals("a", newList.elementAt(1 + (0))); + assertEquals("c", newList.elementAt(1 + (1))); + assertEquals("d", newList.elementAt(1 + (2))); + assertEquals("e", newList.elementAt(1 + (3))); + } + + /** Tests removal of first element. */ + @Test + void testRemoveFirst() { + MyListP17.Pair> result = list.removeAt(1); + + assertEquals("a", result.first()); + MyListP20 newList = result.second(); + + assertEquals(4, newList.length()); + assertEquals("b", newList.elementAt(1 + (0))); + assertEquals("e", newList.elementAt(1 + (3))); + } + + /** Tests removal of last element. */ + @Test + void testRemoveLast() { + MyListP17.Pair> result = list.removeAt(5); + + assertEquals("e", result.first()); + MyListP20 newList = result.second(); + + assertEquals(4, newList.length()); + assertEquals("a", newList.elementAt(1 + (0))); + assertEquals("d", newList.elementAt(1 + (3))); + } + + /** Tests invalid positions. */ + @Test + void testInvalidPositions() { + assertThrows(IllegalArgumentException.class, () -> list.removeAt(0)); + assertThrows(IllegalArgumentException.class, () -> list.removeAt(-1)); + assertThrows(IllegalArgumentException.class, () -> list.removeAt(6)); + } + + /** Tests removal from single element list. */ + @Test + void testSingleElementList() { + MyListP20 singleList = new MyListP20<>("a"); + MyListP17.Pair> result = singleList.removeAt(1); + + assertEquals("a", result.first()); + assertEquals(0, result.second().length()); + } + + /** Tests removal with null values. */ + @Test + void testRemovalWithNulls() { + MyListP20 listWithNulls = new MyListP20<>("a", null, "c"); + MyListP17.Pair> result = listWithNulls.removeAt(2); + + assertNull(result.first()); + MyListP20 newList = result.second(); + + assertEquals(2, newList.length()); + assertEquals("a", newList.elementAt(1 + (0))); + assertEquals("c", newList.elementAt(1 + (1))); + } + + /** Tests that removal preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("1"); + StringBuilder sb2 = new StringBuilder("2"); + StringBuilder sb3 = new StringBuilder("3"); + + MyListP20 builderList = new MyListP20<>(sb1, sb2, sb3); + MyListP17.Pair> result = builderList.removeAt(2); + + assertSame(sb2, result.first()); + MyListP20 newList = result.second(); + + assertEquals(2, newList.length()); + assertSame(sb1, newList.elementAt(1 + (0))); + assertSame(sb3, newList.elementAt(1 + (1))); + } + + /** Tests removal with different types. */ + @Test + void testDifferentTypes() { + // Test with integers + MyListP20 intList = new MyListP20<>(1, 2, 3, 4); + MyListP17.Pair> intResult = intList.removeAt(2); + + assertEquals(Integer.valueOf(2), intResult.first()); + assertEquals(3, intResult.second().length()); + assertEquals(Integer.valueOf(1), intResult.second().elementAt(1 + (0))); + assertEquals(Integer.valueOf(4), intResult.second().elementAt(1 + (2))); + + // Test with doubles + MyListP20 doubleList = new MyListP20<>(1.0, 2.0, 3.0); + MyListP17.Pair> doubleResult = doubleList.removeAt(2); + + assertEquals(2.0, doubleResult.first(), 0.001); + assertEquals(2, doubleResult.second().length()); + assertEquals(1.0, doubleResult.second().elementAt(1 + (0)), 0.001); + assertEquals(3.0, doubleResult.second().elementAt(1 + (1)), 0.001); + } + + /** Tests consecutive removals. */ + @Test + void testConsecutiveRemovals() { + MyListP20 result = list; + List removed = new ArrayList<>(); + + // Remove all elements one by one + while (result.length() > 0) { + MyListP17.Pair> pair = result.removeAt(1); + removed.add(pair.first()); + result = pair.second(); } - /** - * Tests removal from single element list. - */ - @Test - void testSingleElementList() { - MyListP20 singleList = new MyListP20<>("a"); - MyListP17.Pair> result = singleList.removeAt(1); - - assertEquals("a", result.first()); - assertEquals(0, result.second().length()); - } - - /** - * Tests removal with null values. - */ - @Test - void testRemovalWithNulls() { - MyListP20 listWithNulls = new MyListP20<>("a", null, "c"); - MyListP17.Pair> result = listWithNulls.removeAt(2); - - assertNull(result.first()); - MyListP20 newList = result.second(); - - assertEquals(2, newList.length()); - assertEquals("a", newList.elementAt(1+(0))); - assertEquals("c", newList.elementAt(1+(1))); - } - - /** - * Tests that removal preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("1"); - StringBuilder sb2 = new StringBuilder("2"); - StringBuilder sb3 = new StringBuilder("3"); - - MyListP20 builderList = new MyListP20<>(sb1, sb2, sb3); - MyListP17.Pair> result = builderList.removeAt(2); - - assertSame(sb2, result.first()); - MyListP20 newList = result.second(); - - assertEquals(2, newList.length()); - assertSame(sb1, newList.elementAt(1+(0))); - assertSame(sb3, newList.elementAt(1+(1))); - } - - /** - * Tests removal with different types. - */ - @Test - void testDifferentTypes() { - // Test with integers - MyListP20 intList = new MyListP20<>(1, 2, 3, 4); - MyListP17.Pair> intResult = intList.removeAt(2); - - assertEquals(Integer.valueOf(2), intResult.first()); - assertEquals(3, intResult.second().length()); - assertEquals(Integer.valueOf(1), intResult.second().elementAt(1+(0))); - assertEquals(Integer.valueOf(4), intResult.second().elementAt(1+(2))); - - // Test with doubles - MyListP20 doubleList = new MyListP20<>(1.0, 2.0, 3.0); - MyListP17.Pair> doubleResult = doubleList.removeAt(2); - - assertEquals(2.0, doubleResult.first(), 0.001); - assertEquals(2, doubleResult.second().length()); - assertEquals(1.0, doubleResult.second().elementAt(1+(0)), 0.001); - assertEquals(3.0, doubleResult.second().elementAt(1+(1)), 0.001); - } - - /** - * Tests consecutive removals. - */ - @Test - void testConsecutiveRemovals() { - MyListP20 result = list; - List removed = new ArrayList<>(); - - // Remove all elements one by one - while (result.length() > 0) { - MyListP17.Pair> pair = result.removeAt(1); - removed.add(pair.first()); - result = pair.second(); - } - - assertEquals(5, removed.size()); - assertEquals("a", removed.get(0)); - assertEquals("e", removed.get(4)); - assertEquals(0, result.length()); - } - - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - int originalLength = Math.toIntExact(list.length()); - String originalFirstElement = list.elementAt(1+(0)) ; - String originalLastElement = list.elementAt(1+(originalLength - 1)); - - list.removeAt(2); - - // Original list should be unchanged - assertEquals(originalLength, list.length()); - assertEquals(originalFirstElement, list.elementAt(1+(0))); - assertEquals(originalLastElement, list.elementAt(1+(originalLength - 1))); - } - - /** - * Tests element removal and list modification combinations. - */ - @Test - void testRemovalAndModificationCombinations() { - // Remove an element and then rotate the result - MyListP17.Pair> removeResult = list.removeAt(2); - MyListP19 rotated = removeResult.second().rotate(1); - - assertEquals(4, rotated.length()); - assertEquals("c", rotated.elementAt(1+(0))); - assertEquals("a", rotated.elementAt(1+(3))); - - // Split the rotated list - MyListP17.Pair, MyListP17> splitResult = rotated.split(2); - - assertEquals(2, splitResult.first().length()); - assertEquals(2, splitResult.second().length()); - assertEquals("c", splitResult.first().elementAt(1+(0))); - assertEquals("d", splitResult.first().elementAt(1+(1))); - } + assertEquals(5, removed.size()); + assertEquals("a", removed.get(0)); + assertEquals("e", removed.get(4)); + assertEquals(0, result.length()); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + int originalLength = Math.toIntExact(list.length()); + String originalFirstElement = list.elementAt(1 + (0)); + String originalLastElement = list.elementAt(1 + (originalLength - 1)); + + list.removeAt(2); + + // Original list should be unchanged + assertEquals(originalLength, list.length()); + assertEquals(originalFirstElement, list.elementAt(1 + (0))); + assertEquals(originalLastElement, list.elementAt(1 + (originalLength - 1))); + } + + /** Tests element removal and list modification combinations. */ + @Test + void testRemovalAndModificationCombinations() { + // Remove an element and then rotate the result + MyListP17.Pair> removeResult = list.removeAt(2); + MyListP19 rotated = removeResult.second().rotate(1); + + assertEquals(4, rotated.length()); + assertEquals("c", rotated.elementAt(1 + (0))); + assertEquals("a", rotated.elementAt(1 + (3))); + + // Split the rotated list + MyListP17.Pair, MyListP17> splitResult = rotated.split(2); + + assertEquals(2, splitResult.first().length()); + assertEquals(2, splitResult.second().length()); + assertEquals("c", splitResult.first().elementAt(1 + (0))); + assertEquals("d", splitResult.first().elementAt(1 + (1))); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP21Test.java b/src/test/java/org/nintynine/problems/MyListP21Test.java index 20d0e0a..563f820 100644 --- a/src/test/java/org/nintynine/problems/MyListP21Test.java +++ b/src/test/java/org/nintynine/problems/MyListP21Test.java @@ -1,244 +1,212 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP21's element insertion functionality. - */ +/** Test class for MyListP21's element insertion functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP21Test { - private MyListP21 list; - - @BeforeEach - void setUp() { - list = new MyListP21<>("a", "b", "c", "d"); - } - - /** - * Tests basic insertion. - */ - @Test - void testBasicInsertion() { - MyListP21 result = list.insertAt("x", 2); - - assertEquals(5, result.length()); - assertEquals("a", result.elementAt(1+0)); - assertEquals("x", result.elementAt(1+1)); - assertEquals("b", result.elementAt(1+2)); - assertEquals("c", result.elementAt(1+3)); - assertEquals("d", result.elementAt(1+4)); - } - - /** - * Tests insertion at the start. - */ - @Test - void testInsertAtStart() { - MyListP21 result = list.insertAt("x", 1); - - assertEquals(5, result.length()); - assertEquals("x", result.elementAt(1+0)); - assertEquals("a", result.elementAt(1+1)); - assertEquals("d", result.elementAt(1+4)); - } - - /** - * Tests insertion at the end. - */ - @Test - void testInsertAtEnd() { - MyListP21 result = list.insertAt("x", Math.toIntExact(list.length() + 1)); - - assertEquals(5, result.length()); - assertEquals("a", result.elementAt(1+0)); - assertEquals("d", result.elementAt(1+3)); - assertEquals("x", result.elementAt(1+4)); - } - - /** - * Tests invalid positions. - */ - @Test - void testInvalidPositions() { - assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", 0)); - assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", -1)); - int intExact = Math.toIntExact(list.length() + 2); - assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", intExact)); - } - - /** - * Tests insertion into an empty list. - */ - @Test - void testEmptyList() { - MyListP21 emptyList = new MyListP21<>(); - MyListP21 result = emptyList.insertAt("x", 1); - - assertEquals(1, result.length()); - assertEquals("x", result.elementAt(1+0)); - } - - /** - * Tests insertion of null value. - */ - @Test - void testInsertNull() { - MyListP21 result = list.insertAt(null, 2); - - assertEquals(5, result.length()); - assertEquals("a", result.elementAt(1+0)); - assertThrows(NullPointerException.class,()->result.elementAt(1+1)); - assertEquals("b", result.elementAt(1+2)); - } - - /** - * Tests that insertion preserves object references. - */ - @Test - void testObjectReferences() { - StringBuilder sb1 = new StringBuilder("1"); - StringBuilder sb2 = new StringBuilder("2"); - MyListP21 builderList = new MyListP21<>(sb1); - - MyListP21 result = builderList.insertAt(sb2, 1); - - assertEquals(2, result.length()); - assertSame(sb2, result.elementAt(1+0)); - assertSame(sb1, result.elementAt(1+1)); - } - - /** - * Tests insertion with different types. - */ - @Test - void testDifferentTypes() { - // Test with integers - MyListP21 intList = new MyListP21<>(1, 2, 3); - MyListP21 intResult = intList.insertAt(99, 2); - - assertEquals(4, intResult.length()); - assertEquals(Integer.valueOf(1), intResult.elementAt(1+0)); - assertEquals(Integer.valueOf(99), intResult.elementAt(1+1)); - assertEquals(Integer.valueOf(3), intResult.elementAt(1+3)); - - // Test with doubles - MyListP21 doubleList = new MyListP21<>(1.0, 2.0); - MyListP21 doubleResult = doubleList.insertAt(3.5, 2); - - assertEquals(3, doubleResult.length()); - assertEquals(1.0, doubleResult.elementAt(1+0), 0.001); - assertEquals(3.5, doubleResult.elementAt(1+1), 0.001); - assertEquals(2.0, doubleResult.elementAt(1+2), 0.001); + private MyListP21 list; + + @BeforeEach + void setUp() { + list = new MyListP21<>("a", "b", "c", "d"); + } + + /** Tests basic insertion. */ + @Test + void testBasicInsertion() { + MyListP21 result = list.insertAt("x", 2); + + assertEquals(5, result.length()); + assertEquals("a", result.elementAt(1 + 0)); + assertEquals("x", result.elementAt(1 + 1)); + assertEquals("b", result.elementAt(1 + 2)); + assertEquals("c", result.elementAt(1 + 3)); + assertEquals("d", result.elementAt(1 + 4)); + } + + /** Tests insertion at the start. */ + @Test + void testInsertAtStart() { + MyListP21 result = list.insertAt("x", 1); + + assertEquals(5, result.length()); + assertEquals("x", result.elementAt(1 + 0)); + assertEquals("a", result.elementAt(1 + 1)); + assertEquals("d", result.elementAt(1 + 4)); + } + + /** Tests insertion at the end. */ + @Test + void testInsertAtEnd() { + MyListP21 result = list.insertAt("x", Math.toIntExact(list.length() + 1)); + + assertEquals(5, result.length()); + assertEquals("a", result.elementAt(1 + 0)); + assertEquals("d", result.elementAt(1 + 3)); + assertEquals("x", result.elementAt(1 + 4)); + } + + /** Tests invalid positions. */ + @Test + void testInvalidPositions() { + assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", 0)); + assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", -1)); + int intExact = Math.toIntExact(list.length() + 2); + assertThrows(IllegalArgumentException.class, () -> list.insertAt("x", intExact)); + } + + /** Tests insertion into an empty list. */ + @Test + void testEmptyList() { + MyListP21 emptyList = new MyListP21<>(); + MyListP21 result = emptyList.insertAt("x", 1); + + assertEquals(1, result.length()); + assertEquals("x", result.elementAt(1 + 0)); + } + + /** Tests insertion of null value. */ + @Test + void testInsertNull() { + MyListP21 result = list.insertAt(null, 2); + + assertEquals(5, result.length()); + assertEquals("a", result.elementAt(1 + 0)); + assertThrows(NullPointerException.class, () -> result.elementAt(1 + 1)); + assertEquals("b", result.elementAt(1 + 2)); + } + + /** Tests that insertion preserves object references. */ + @Test + void testObjectReferences() { + StringBuilder sb1 = new StringBuilder("1"); + StringBuilder sb2 = new StringBuilder("2"); + MyListP21 builderList = new MyListP21<>(sb1); + + MyListP21 result = builderList.insertAt(sb2, 1); + + assertEquals(2, result.length()); + assertSame(sb2, result.elementAt(1 + 0)); + assertSame(sb1, result.elementAt(1 + 1)); + } + + /** Tests insertion with different types. */ + @Test + void testDifferentTypes() { + // Test with integers + MyListP21 intList = new MyListP21<>(1, 2, 3); + MyListP21 intResult = intList.insertAt(99, 2); + + assertEquals(4, intResult.length()); + assertEquals(Integer.valueOf(1), intResult.elementAt(1 + 0)); + assertEquals(Integer.valueOf(99), intResult.elementAt(1 + 1)); + assertEquals(Integer.valueOf(3), intResult.elementAt(1 + 3)); + + // Test with doubles + MyListP21 doubleList = new MyListP21<>(1.0, 2.0); + MyListP21 doubleResult = doubleList.insertAt(3.5, 2); + + assertEquals(3, doubleResult.length()); + assertEquals(1.0, doubleResult.elementAt(1 + 0), 0.001); + assertEquals(3.5, doubleResult.elementAt(1 + 1), 0.001); + assertEquals(2.0, doubleResult.elementAt(1 + 2), 0.001); + } + + /** Tests multiple consecutive insertions. */ + @Test + void testConsecutiveInsertions() { + MyListP21 result = list; + + // Insert multiple elements at different positions + result = + result + .insertAt("x", 1) // At start + .insertAt("y", 3) // In middle + .insertAt("z", Math.toIntExact(result.length() + 3)); // At end + + assertEquals(7, result.length()); + assertEquals("x", result.elementAt(1 + 0)); + assertEquals("y", result.elementAt(1 + 2)); + assertEquals("z", result.elementAt(1 + 6)); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + long originalLength = list.length(); + String originalFirstElement = list.elementAt(1 + 0); + String originalLastElement = list.elementAt(1 + originalLength - 1); + + list.insertAt("x", 2); + + // The original list should be unchanged + assertEquals(originalLength, list.length()); + assertEquals(originalFirstElement, list.elementAt(1 + 0)); + assertEquals(originalLastElement, list.elementAt(1 + originalLength - 1)); + } + + /** Tests insertion and other operations combinations. */ + @Test + void testInsertionCombinations() { + // Insert and then rotate + MyListP21 inserted = list.insertAt("x", 2); + MyListP19 rotated = inserted.rotate(2); + + assertEquals(5, rotated.length()); + assertEquals("x", rotated.elementAt(5)); + + // Insert and then remove + MyListP17.Pair> removed = inserted.removeAt(2); + assertEquals("x", removed.first()); + assertEquals(4, removed.second().length()); + } + + /** Tests insertion at every possible position. */ + @Test + void testInsertionAtEveryPosition() { + for (int i = 1; i <= list.length() + 1; i++) { + MyListP21 result = list.insertAt("x", i); + + assertEquals(list.length() + 1, result.length()); + assertEquals("x", result.elementAt(1 + i - 1)); + + // Check elements before the insertion point + for (int j = 0; j < i - 1; j++) { + assertEquals(list.elementAt(1 + j), result.elementAt(1 + j)); + } + + // Check elements after the insertion point + for (int j = i; j < result.length(); j++) { + assertEquals(list.elementAt(1 + j - 1), result.elementAt(1 + j)); + } } + } - /** - * Tests multiple consecutive insertions. - */ - @Test - void testConsecutiveInsertions() { - MyListP21 result = list; - - // Insert multiple elements at different positions - result = result.insertAt("x", 1) // At start - .insertAt("y", 3) // In middle - .insertAt("z", Math.toIntExact(result.length()+3)); // At end - - assertEquals(7, result.length()); - assertEquals("x", result.elementAt(1+0)); - assertEquals("y", result.elementAt(1+2)); - assertEquals("z", result.elementAt(1+6)); - } + /** Tests insertion with mutable objects. */ + @Test + void testMutableObjects() { + List builders = Arrays.asList(new StringBuilder("1"), new StringBuilder("2")); - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - long originalLength = list.length(); - String originalFirstElement = list.elementAt(1+0); - String originalLastElement = list.elementAt(1+originalLength - 1); - - list.insertAt("x", 2); - - // The original list should be unchanged - assertEquals(originalLength, list.length()); - assertEquals(originalFirstElement, list.elementAt(1+0)); - assertEquals(originalLastElement, list.elementAt(1+originalLength - 1)); - } + MyListP21 builderList = new MyListP21<>(builders.toArray(new StringBuilder[0])); + StringBuilder newBuilder = new StringBuilder("3"); - /** - * Tests insertion and other operations combinations. - */ - @Test - void testInsertionCombinations() { - // Insert and then rotate - MyListP21 inserted = list.insertAt("x", 2); - MyListP19 rotated = inserted.rotate(2); - - assertEquals(5, rotated.length()); - assertEquals("x", rotated.elementAt(5)); - - // Insert and then remove - MyListP17.Pair> removed = inserted.removeAt(2); - assertEquals("x", removed.first()); - assertEquals(4, removed.second().length()); - } - - /** - * Tests insertion at every possible position. - */ - @Test - void testInsertionAtEveryPosition() { - for (int i = 1; i <= list.length() + 1; i++) { - MyListP21 result = list.insertAt("x", i); - - assertEquals(list.length() + 1, result.length()); - assertEquals("x", result.elementAt(1+i - 1)); - - // Check elements before the insertion point - for (int j = 0; j < i - 1; j++) { - assertEquals(list.elementAt(1+j), result.elementAt(1+j)); - } - - // Check elements after the insertion point - for (int j = i; j < result.length(); j++) { - assertEquals(list.elementAt(1+j - 1), result.elementAt(1+j)); - } - } - } + MyListP21 result = builderList.insertAt(newBuilder, 2); - /** - * Tests insertion with mutable objects. - */ - @Test - void testMutableObjects() { - List builders = Arrays.asList( - new StringBuilder("1"), - new StringBuilder("2") - ); + // Modify the inserted object + newBuilder.append("-modified"); - MyListP21 builderList = new MyListP21<>( - builders.toArray(new StringBuilder[0]) - ); - StringBuilder newBuilder = new StringBuilder("3"); + // The modification should be reflected in the new list + assertEquals("3-modified", result.elementAt(1 + 1).toString()); - MyListP21 result = builderList.insertAt(newBuilder, 2); - - // Modify the inserted object - newBuilder.append("-modified"); - - // The modification should be reflected in the new list - assertEquals("3-modified", result.elementAt(1+1).toString()); - - // Original objects should still be in their positions - assertEquals("1", result.elementAt(1+0).toString()); - assertEquals("2", result.elementAt(1+2).toString()); - } + // Original objects should still be in their positions + assertEquals("1", result.elementAt(1 + 0).toString()); + assertEquals("2", result.elementAt(1 + 2).toString()); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP22Test.java b/src/test/java/org/nintynine/problems/MyListP22Test.java index a409d40..f47edd1 100644 --- a/src/test/java/org/nintynine/problems/MyListP22Test.java +++ b/src/test/java/org/nintynine/problems/MyListP22Test.java @@ -1,208 +1,178 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP22's range functionality. - */ +/** Test class for MyListP22's range functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP22Test { - /** - * Tests basic ascending range. - */ - @Test - void testAscendingRange() { - MyListP22 result = MyListP22.range(4, 9); - - assertEquals(6, result.length()); - assertEquals(4, result.elementAt(1+0)); - assertEquals(Integer.valueOf(5), result.elementAt(1+1)); - assertEquals(Integer.valueOf(6), result.elementAt(1+2)); - assertEquals(Integer.valueOf(7), result.elementAt(1+3)); - assertEquals(Integer.valueOf(8), result.elementAt(1+4)); - assertEquals(Integer.valueOf(9), result.elementAt(1+5)); - } - - /** - * Tests basic descending range. - */ - @Test - void testDescendingRange() { - MyListP22 result = MyListP22.range(9, 4); - - assertEquals(6, result.length()); - assertEquals(Integer.valueOf(9), result.elementAt(1+0)); - assertEquals(Integer.valueOf(8), result.elementAt(1+1)); - assertEquals(Integer.valueOf(7), result.elementAt(1+2)); - assertEquals(Integer.valueOf(6), result.elementAt(1+3)); - assertEquals(Integer.valueOf(5), result.elementAt(1+4)); - assertEquals(Integer.valueOf(4), result.elementAt(1+5)); + /** Tests basic ascending range. */ + @Test + void testAscendingRange() { + MyListP22 result = MyListP22.range(4, 9); + + assertEquals(6, result.length()); + assertEquals(4, result.elementAt(1 + 0)); + assertEquals(Integer.valueOf(5), result.elementAt(1 + 1)); + assertEquals(Integer.valueOf(6), result.elementAt(1 + 2)); + assertEquals(Integer.valueOf(7), result.elementAt(1 + 3)); + assertEquals(Integer.valueOf(8), result.elementAt(1 + 4)); + assertEquals(Integer.valueOf(9), result.elementAt(1 + 5)); + } + + /** Tests basic descending range. */ + @Test + void testDescendingRange() { + MyListP22 result = MyListP22.range(9, 4); + + assertEquals(6, result.length()); + assertEquals(Integer.valueOf(9), result.elementAt(1 + 0)); + assertEquals(Integer.valueOf(8), result.elementAt(1 + 1)); + assertEquals(Integer.valueOf(7), result.elementAt(1 + 2)); + assertEquals(Integer.valueOf(6), result.elementAt(1 + 3)); + assertEquals(Integer.valueOf(5), result.elementAt(1 + 4)); + assertEquals(Integer.valueOf(4), result.elementAt(1 + 5)); + } + + /** Tests single number range. */ + @Test + void testSingleNumberRange() { + MyListP22 result = MyListP22.range(3, 3); + + assertEquals(1, result.length()); + assertEquals(Integer.valueOf(3), result.elementAt(1 + 0)); + } + + /** Tests negative numbers range. */ + @Test + void testNegativeRange() { + MyListP22 result = MyListP22.range(-3, 2); + + assertEquals(6, result.length()); + assertEquals(Integer.valueOf(-3), result.elementAt(1 + 0)); + assertEquals(Integer.valueOf(-2), result.elementAt(1 + 1)); + assertEquals(Integer.valueOf(-1), result.elementAt(1 + 2)); + assertEquals(Integer.valueOf(0), result.elementAt(1 + 3)); + assertEquals(Integer.valueOf(1), result.elementAt(1 + 4)); + assertEquals(Integer.valueOf(2), result.elementAt(1 + 5)); + } + + /** Tests descending negative numbers range. */ + @Test + void testDescendingNegativeRange() { + MyListP22 result = MyListP22.range(2, -3); + + assertEquals(6, result.length()); + assertEquals(Integer.valueOf(2), result.elementAt(1 + 0)); + assertEquals(Integer.valueOf(1), result.elementAt(1 + 1)); + assertEquals(Integer.valueOf(0), result.elementAt(1 + 2)); + assertEquals(Integer.valueOf(-1), result.elementAt(1 + 3)); + assertEquals(Integer.valueOf(-2), result.elementAt(1 + 4)); + assertEquals(Integer.valueOf(-3), result.elementAt(1 + 5)); + } + + /** Tests large range size. */ + @Test + void testLargeRange() { + MyListP22 result = MyListP22.range(1, 1000); + + assertEquals(1000, result.length()); + assertEquals(Integer.valueOf(1), result.elementAt(1 + 0)); + assertEquals(Integer.valueOf(1000), result.elementAt(1 + 999)); + + // Check some values in between + assertEquals(Integer.valueOf(500), result.elementAt(1 + 499)); + assertEquals(Integer.valueOf(750), result.elementAt(1 + 749)); + } + + /** Tests range combined with other operations. */ + @Test + void testRangeWithOperations() { + MyListP22 range = MyListP22.range(1, 5); + + // Test insertion + MyListP21 withInserted = range.insertAt(99, 3); + assertEquals(6, withInserted.length()); + assertEquals(Integer.valueOf(99), withInserted.elementAt(1 + 2)); + + // Test removal + MyListP17.Pair> removed = range.removeAt(2); + assertEquals(Integer.valueOf(2), removed.first()); + assertEquals(4, removed.second().length()); + + // Test rotation + MyListP19 rotated = range.rotate(2); + assertEquals(Integer.valueOf(3), rotated.elementAt(1 + 0)); + assertEquals(Integer.valueOf(2), rotated.elementAt(1 + 4)); + } + + /** Tests validation of list contents. */ + @Test + void testRangeValidation() { + MyListP22 ascending = MyListP22.range(1, 5); + MyListP22 descending = MyListP22.range(5, 1); + + // Check ascending order + for (int i = 0; i < ascending.length() - 1; i++) { + assertTrue(ascending.elementAt(1 + i) < ascending.elementAt(1 + i + 1)); } - /** - * Tests single number range. - */ - @Test - void testSingleNumberRange() { - MyListP22 result = MyListP22.range(3, 3); - - assertEquals(1, result.length()); - assertEquals(Integer.valueOf(3), result.elementAt(1+0)); - } - - /** - * Tests negative numbers range. - */ - @Test - void testNegativeRange() { - MyListP22 result = MyListP22.range(-3, 2); - - assertEquals(6, result.length()); - assertEquals(Integer.valueOf(-3), result.elementAt(1+0)); - assertEquals(Integer.valueOf(-2), result.elementAt(1+1)); - assertEquals(Integer.valueOf(-1), result.elementAt(1+2)); - assertEquals(Integer.valueOf(0), result.elementAt(1+3)); - assertEquals(Integer.valueOf(1), result.elementAt(1+4)); - assertEquals(Integer.valueOf(2), result.elementAt(1+5)); - } - - /** - * Tests descending negative numbers range. - */ - @Test - void testDescendingNegativeRange() { - MyListP22 result = MyListP22.range(2, -3); - - assertEquals(6, result.length()); - assertEquals(Integer.valueOf(2), result.elementAt(1+0)); - assertEquals(Integer.valueOf(1), result.elementAt(1+1)); - assertEquals(Integer.valueOf(0), result.elementAt(1+2)); - assertEquals(Integer.valueOf(-1), result.elementAt(1+3)); - assertEquals(Integer.valueOf(-2), result.elementAt(1+4)); - assertEquals(Integer.valueOf(-3), result.elementAt(1+5)); - } - - /** - * Tests large range size. - */ - @Test - void testLargeRange() { - MyListP22 result = MyListP22.range(1, 1000); - - assertEquals(1000, result.length()); - assertEquals(Integer.valueOf(1), result.elementAt(1+0)); - assertEquals(Integer.valueOf(1000), result.elementAt(1+999)); - - // Check some values in between - assertEquals(Integer.valueOf(500), result.elementAt(1+499)); - assertEquals(Integer.valueOf(750), result.elementAt(1+749)); - } - - /** - * Tests range combined with other operations. - */ - @Test - void testRangeWithOperations() { - MyListP22 range = MyListP22.range(1, 5); - - // Test insertion - MyListP21 withInserted = range.insertAt(99, 3); - assertEquals(6, withInserted.length()); - assertEquals(Integer.valueOf(99), withInserted.elementAt(1+2)); - - // Test removal - MyListP17.Pair> removed = range.removeAt(2); - assertEquals(Integer.valueOf(2), removed.first()); - assertEquals(4, removed.second().length()); - - // Test rotation - MyListP19 rotated = range.rotate(2); - assertEquals(Integer.valueOf(3), rotated.elementAt(1+0)); - assertEquals(Integer.valueOf(2), rotated.elementAt(1+4)); - } - - /** - * Tests validation of list contents. - */ - @Test - void testRangeValidation() { - MyListP22 ascending = MyListP22.range(1, 5); - MyListP22 descending = MyListP22.range(5, 1); - - // Check ascending order - for (int i = 0; i < ascending.length() - 1; i++) { - assertTrue(ascending.elementAt(1+i) < ascending.elementAt(1+i + 1)); - } - - // Check descending order - for (int i = 0; i < descending.length() - 1; i++) { - assertTrue(descending.elementAt(1+i) > descending.elementAt(1+i + 1)); - } - } - - /** - * Tests consecutive range operations. - */ - @Test - void testConsecutiveRanges() { - MyListP22 first = MyListP22.range(1, 3); - MyListP22 second = MyListP22.range(3, 1); - - // Combine ranges using existing operations - MyListP22 combined = new MyListP22<>( - Stream.concat( - Arrays.stream(first.items), - Arrays.stream(second.items) - ).toArray(Integer[]::new) - ); - - assertEquals(6, combined.length()); - assertEquals(Integer.valueOf(1), combined.elementAt(1+0)); - assertEquals(Integer.valueOf(3), combined.elementAt(1+2)); - assertEquals(Integer.valueOf(3), combined.elementAt(1+3)); - assertEquals(Integer.valueOf(1), combined.elementAt(1+5)); - } - - @Test - void testBoundaryCases() { - // Test range crossing zero - MyListP22 crossingZero = MyListP22.range(-2, 2); - assertEquals(5, crossingZero.length()); - assertEquals(Integer.valueOf(-2), crossingZero.elementAt(1+0)); - assertEquals(Integer.valueOf(0), crossingZero.elementAt(1+2)); - assertEquals(Integer.valueOf(2), crossingZero.elementAt(1+4)); - - // Test range with maximum gap of 1 - MyListP22 minGap = MyListP22.range(100, 101); - assertEquals(2, minGap.length()); - assertEquals(Integer.valueOf(100), minGap.elementAt(1+0)); - assertEquals(Integer.valueOf(101), minGap.elementAt(1+1)); - } - - /** - * Tests range with arithmetic operations. - */ - @Test - void testRangeArithmetic() { - MyListP22 range = MyListP22.range(1, 5); - - // Calculate sum - int sum = Arrays.stream(range.items) - .mapToInt(Integer::intValue) - .sum(); - assertEquals(15, sum); // 1 + 2 + 3 + 4 + 5 - - // Calculate product - int product = Arrays.stream(range.items) - .mapToInt(Integer::intValue) - .reduce(1, (a, b) -> a * b); - assertEquals(120, product); // 1 * 2 * 3 * 4 * 5 + // Check descending order + for (int i = 0; i < descending.length() - 1; i++) { + assertTrue(descending.elementAt(1 + i) > descending.elementAt(1 + i + 1)); } + } + + /** Tests consecutive range operations. */ + @Test + void testConsecutiveRanges() { + MyListP22 first = MyListP22.range(1, 3); + MyListP22 second = MyListP22.range(3, 1); + + // Combine ranges using existing operations + MyListP22 combined = + new MyListP22<>( + Stream.concat(Arrays.stream(first.items), Arrays.stream(second.items)) + .toArray(Integer[]::new)); + + assertEquals(6, combined.length()); + assertEquals(Integer.valueOf(1), combined.elementAt(1 + 0)); + assertEquals(Integer.valueOf(3), combined.elementAt(1 + 2)); + assertEquals(Integer.valueOf(3), combined.elementAt(1 + 3)); + assertEquals(Integer.valueOf(1), combined.elementAt(1 + 5)); + } + + @Test + void testBoundaryCases() { + // Test range crossing zero + MyListP22 crossingZero = MyListP22.range(-2, 2); + assertEquals(5, crossingZero.length()); + assertEquals(Integer.valueOf(-2), crossingZero.elementAt(1 + 0)); + assertEquals(Integer.valueOf(0), crossingZero.elementAt(1 + 2)); + assertEquals(Integer.valueOf(2), crossingZero.elementAt(1 + 4)); + + // Test range with maximum gap of 1 + MyListP22 minGap = MyListP22.range(100, 101); + assertEquals(2, minGap.length()); + assertEquals(Integer.valueOf(100), minGap.elementAt(1 + 0)); + assertEquals(Integer.valueOf(101), minGap.elementAt(1 + 1)); + } + + /** Tests range with arithmetic operations. */ + @Test + void testRangeArithmetic() { + MyListP22 range = MyListP22.range(1, 5); + + // Calculate sum + int sum = Arrays.stream(range.items).mapToInt(Integer::intValue).sum(); + assertEquals(15, sum); // 1 + 2 + 3 + 4 + 5 + + // Calculate product + int product = Arrays.stream(range.items).mapToInt(Integer::intValue).reduce(1, (a, b) -> a * b); + assertEquals(120, product); // 1 * 2 * 3 * 4 * 5 + } } - diff --git a/src/test/java/org/nintynine/problems/MyListP23Test.java b/src/test/java/org/nintynine/problems/MyListP23Test.java index 38e5ca0..01917f1 100644 --- a/src/test/java/org/nintynine/problems/MyListP23Test.java +++ b/src/test/java/org/nintynine/problems/MyListP23Test.java @@ -1,206 +1,179 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP23's random selection functionality. - */ +/** Test class for MyListP23's random selection functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP23Test { - private MyListP23 list; - private static final int STATISTICAL_TEST_ITERATIONS = 10000; + private MyListP23 list; + private static final int STATISTICAL_TEST_ITERATIONS = 10000; - @BeforeEach - void setUp() { - list = new MyListP23<>("a", "b", "c", "d", "e"); - } - - /** - * Tests basic random selection. - */ - @Test - void testBasicRandomSelection() { - MyListP23 result = list.rndSelect(3); - - assertEquals(3, result.length()); - // All elements should be from the original list - for (int i = 0; i < result.length(); i++) { - assertTrue(containsElement(list, result.elementAt(1 + i))); - } - } + @BeforeEach + void setUp() { + list = new MyListP23<>("a", "b", "c", "d", "e"); + } - /** - * Tests selection with n=0. - */ - @Test - void testZeroSelection() { - MyListP23 result = list.rndSelect(0); - assertEquals(0, result.length()); - } + /** Tests basic random selection. */ + @Test + void testBasicRandomSelection() { + MyListP23 result = list.rndSelect(3); - /** - * Tests selection with n greater than list size. - */ - @Test - void testOverflowSelection() { - MyListP23 result = list.rndSelect(10); - - assertEquals(list.length(), result.length()); - // Should contain all original elements - for (int i = 0; i < list.length(); i++) { - assertTrue(containsElement(result, list.elementAt(1 + i))); - } + assertEquals(3, result.length()); + // All elements should be from the original list + for (int i = 0; i < result.length(); i++) { + assertTrue(containsElement(list, result.elementAt(1 + i))); } - - /** - * Tests selection with negative n. - */ - @Test - void testNegativeSelection() { - assertThrows(IllegalArgumentException.class, () -> list.rndSelect(-1)); + } + + /** Tests selection with n=0. */ + @Test + void testZeroSelection() { + MyListP23 result = list.rndSelect(0); + assertEquals(0, result.length()); + } + + /** Tests selection with n greater than list size. */ + @Test + void testOverflowSelection() { + MyListP23 result = list.rndSelect(10); + + assertEquals(list.length(), result.length()); + // Should contain all original elements + for (int i = 0; i < list.length(); i++) { + assertTrue(containsElement(result, list.elementAt(1 + i))); } - - /** - * Tests selection from a single element list. - */ - @Test - void testSingleElementList() { - MyListP23 singleList = new MyListP23<>("a"); - MyListP23 result = singleList.rndSelect(1); - - assertEquals(1, result.length()); - assertEquals("a", result.elementAt(1 + 0)); + } + + /** Tests selection with negative n. */ + @Test + void testNegativeSelection() { + assertThrows(IllegalArgumentException.class, () -> list.rndSelect(-1)); + } + + /** Tests selection from a single element list. */ + @Test + void testSingleElementList() { + MyListP23 singleList = new MyListP23<>("a"); + MyListP23 result = singleList.rndSelect(1); + + assertEquals(1, result.length()); + assertEquals("a", result.elementAt(1 + 0)); + } + + /** Tests selection from an empty list. */ + @Test + void testEmptyList() { + MyListP23 emptyList = new MyListP23<>(); + MyListP23 result = emptyList.rndSelect(5); + + assertEquals(0, result.length()); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + int originalLength = Math.toIntExact(list.length()); + String[] originalElements = new String[originalLength]; + for (int i = 0; i < originalLength; i++) { + originalElements[i] = list.elementAt(1 + i); } - /** - * Tests selection from an empty list. - */ - @Test - void testEmptyList() { - MyListP23 emptyList = new MyListP23<>(); - MyListP23 result = emptyList.rndSelect(5); + list.rndSelect(3); - assertEquals(0, result.length()); + assertEquals(originalLength, list.length()); + for (int i = 0; i < originalLength; i++) { + assertEquals(originalElements[i], list.elementAt(1 + i)); } - - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - int originalLength = Math.toIntExact(list.length()); - String[] originalElements = new String[originalLength]; - for (int i = 0; i < originalLength; i++) { - originalElements[i] = list.elementAt(1 + i); - } - - list.rndSelect(3); - - assertEquals(originalLength, list.length()); - for (int i = 0; i < originalLength; i++) { - assertEquals(originalElements[i], list.elementAt(1 + i)); - } + } + + /** Tests statistical properties of random selection. */ + @Test + void testRandomDistribution() { + Map selectionCounts = new HashMap<>(); + int selectSize = 2; + + // Perform many selections to check distribution + for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { + MyListP23 selected = list.rndSelect(selectSize); + for (int j = 0; j < selected.length(); j++) { + String element = selected.elementAt(1 + j); + selectionCounts.merge(element, 1, Integer::sum); + } } - /** - * Tests statistical properties of random selection. - */ - @Test - void testRandomDistribution() { - Map selectionCounts = new HashMap<>(); - int selectSize = 2; - - // Perform many selections to check distribution - for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { - MyListP23 selected = list.rndSelect(selectSize); - for (int j = 0; j < selected.length(); j++) { - String element = selected.elementAt(1 + j); - selectionCounts.merge(element, 1, Integer::sum); - } - } - - // Check that all elements were selected at least once - for (int i = 0; i < list.length(); i++) { - assertTrue(selectionCounts.containsKey(list.elementAt(1 + i))); - } - - // Check that selections are roughly evenly distributed - // (within 20% of the expected frequency) - double expectedCount = (STATISTICAL_TEST_ITERATIONS * selectSize) / (double) list.length(); - double tolerance = expectedCount * 0.2; // 20% tolerance - - for (Integer count : selectionCounts.values()) { - assertTrue(Math.abs(count - expectedCount) < tolerance, - "Selection frequency " + count + " deviates too much from expected " + expectedCount); - } + // Check that all elements were selected at least once + for (int i = 0; i < list.length(); i++) { + assertTrue(selectionCounts.containsKey(list.elementAt(1 + i))); } + // Check that selections are roughly evenly distributed + // (within 20% of the expected frequency) + double expectedCount = (STATISTICAL_TEST_ITERATIONS * selectSize) / (double) list.length(); + double tolerance = expectedCount * 0.2; // 20% tolerance - /** - * Tests consecutive random selections. - */ - @Test - void testConsecutiveSelections() { - MyListP23 firstSelection = list.rndSelect(2); - MyListP23 secondSelection = firstSelection.rndSelect(1); - - assertEquals(2, firstSelection.length()); - assertEquals(1, secondSelection.length()); - assertTrue(containsElement(firstSelection, secondSelection.elementAt(1 + 0))); + for (Integer count : selectionCounts.values()) { + assertTrue( + Math.abs(count - expectedCount) < tolerance, + "Selection frequency " + count + " deviates too much from expected " + expectedCount); } - - /** - * Tests with different types. - */ - @Test - void testDifferentTypes() { - MyListP23 intList = new MyListP23<>(1, 2, 3, 4, 5); - MyListP23 intResult = intList.rndSelect(3); - - assertEquals(3, intResult.length()); - for (int i = 0; i < intResult.length(); i++) { - assertTrue(containsElement(intList, intResult.elementAt(1 + i))); - } - - MyListP23 doubleList = new MyListP23<>(1.0, 2.0, 3.0); - MyListP23 doubleResult = doubleList.rndSelect(2); - - assertEquals(2, doubleResult.length()); - for (int i = 0; i < doubleResult.length(); i++) { - assertTrue(containsElement(doubleList, doubleResult.elementAt(1 + i))); - } + } + + /** Tests consecutive random selections. */ + @Test + void testConsecutiveSelections() { + MyListP23 firstSelection = list.rndSelect(2); + MyListP23 secondSelection = firstSelection.rndSelect(1); + + assertEquals(2, firstSelection.length()); + assertEquals(1, secondSelection.length()); + assertTrue(containsElement(firstSelection, secondSelection.elementAt(1 + 0))); + } + + /** Tests with different types. */ + @Test + void testDifferentTypes() { + MyListP23 intList = new MyListP23<>(1, 2, 3, 4, 5); + MyListP23 intResult = intList.rndSelect(3); + + assertEquals(3, intResult.length()); + for (int i = 0; i < intResult.length(); i++) { + assertTrue(containsElement(intList, intResult.elementAt(1 + i))); } - /** - * Tests that no duplicates are selected. - */ - @Test - void testNoDuplicates() { - MyListP23 result = list.rndSelect(3); - Set uniqueElements = new HashSet<>(); - - for (int i = 0; i < result.length(); i++) { - assertTrue(uniqueElements.add(result.elementAt(1 + i)), - "Duplicate element found: " + result.elementAt(1 + i)); - } - } + MyListP23 doubleList = new MyListP23<>(1.0, 2.0, 3.0); + MyListP23 doubleResult = doubleList.rndSelect(2); - /** - * Helper method to check if the list contains an element. - */ - private boolean containsElement(MyListP23 list, T element) { - for (int i = 0; i < list.length(); i++) { - if (Objects.equals(list.elementAt(1 + i), element)) { - return true; - } - } - return false; + assertEquals(2, doubleResult.length()); + for (int i = 0; i < doubleResult.length(); i++) { + assertTrue(containsElement(doubleList, doubleResult.elementAt(1 + i))); + } + } + + /** Tests that no duplicates are selected. */ + @Test + void testNoDuplicates() { + MyListP23 result = list.rndSelect(3); + Set uniqueElements = new HashSet<>(); + + for (int i = 0; i < result.length(); i++) { + assertTrue( + uniqueElements.add(result.elementAt(1 + i)), + "Duplicate element found: " + result.elementAt(1 + i)); + } + } + + /** Helper method to check if the list contains an element. */ + private boolean containsElement(MyListP23 list, T element) { + for (int i = 0; i < list.length(); i++) { + if (Objects.equals(list.elementAt(1 + i), element)) { + return true; + } } + return false; + } } - diff --git a/src/test/java/org/nintynine/problems/MyListP24Test.java b/src/test/java/org/nintynine/problems/MyListP24Test.java index e327075..ec7e842 100644 --- a/src/test/java/org/nintynine/problems/MyListP24Test.java +++ b/src/test/java/org/nintynine/problems/MyListP24Test.java @@ -1,219 +1,195 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.IntStream; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP24's lotto number generation functionality. - */ +/** Test class for MyListP24's lotto number generation functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP24Test { - private static final int STATISTICAL_TEST_ITERATIONS = 10000; - - /** - * Tests basic lotto selection. - */ - @Test - void testBasicLottoSelection() { - MyListP24 result = MyListP24.lottoSelect(6, 49); - - assertEquals(6, result.length()); - // Check range - IntStream.iterate(0, i -> i < result.length(), i -> i + 1).map(i -> result.elementAt(1 + i)).mapToObj(number -> number >= 1 && number <= 49).forEach(Assertions::assertTrue); + private static final int STATISTICAL_TEST_ITERATIONS = 10000; + + /** Tests basic lotto selection. */ + @Test + void testBasicLottoSelection() { + MyListP24 result = MyListP24.lottoSelect(6, 49); + + assertEquals(6, result.length()); + // Check range + IntStream.iterate(0, i -> i < result.length(), i -> i + 1) + .map(i -> result.elementAt(1 + i)) + .mapToObj(number -> number >= 1 && number <= 49) + .forEach(Assertions::assertTrue); + } + + /** Tests edge cases with minimum values. */ + @Test + void testMinimumValues() { + // Select one number from range 1..1 + MyListP24 result = MyListP24.lottoSelect(1, 1); + + assertEquals(1, result.length()); + assertEquals(Integer.valueOf(1), result.elementAt(1 + 0)); + } + + /** Tests invalid inputs. */ + @Test + void testInvalidInputs() { + assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(-1, 10)); + assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(5, 0)); + assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(10, 5)); + assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(0, -1)); + } + + /** Tests selecting zero numbers. */ + @Test + void testZeroSelection() { + MyListP24 result = MyListP24.lottoSelect(0, 10); + assertEquals(0, result.length()); + } + + /** Tests selecting all numbers in range. */ + @Test + void testSelectAll() { + MyListP24 result = MyListP24.lottoSelect(5, 5); + + assertEquals(5, result.length()); + // Should contain all numbers 1-5 in some order + Set numbers = new HashSet<>(); + for (int i = 0; i < result.length(); i++) { + numbers.add(result.elementAt(1 + i)); } - - /** - * Tests edge cases with minimum values. - */ - @Test - void testMinimumValues() { - // Select one number from range 1..1 - MyListP24 result = MyListP24.lottoSelect(1, 1); - - assertEquals(1, result.length()); - assertEquals(Integer.valueOf(1), result.elementAt(1+0)); + assertEquals(Set.of(1, 2, 3, 4, 5), numbers); + } + + /** Tests that no duplicates are generated. */ + @Test + void testNoDuplicates() { + MyListP24 result = MyListP24.lottoSelect(6, 49); + Set numbers = new HashSet<>(); + + for (int i = 0; i < result.length(); i++) { + assertTrue( + numbers.add(result.elementAt(1 + i)), + "Duplicate number found: " + result.elementAt(1 + i)); } - - /** - * Tests invalid inputs. - */ - @Test - void testInvalidInputs() { - assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(-1, 10)); - assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(5, 0)); - assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(10, 5)); - assertThrows(IllegalArgumentException.class, () -> MyListP24.lottoSelect(0, -1)); - } - - /** - * Tests selecting zero numbers. - */ - @Test - void testZeroSelection() { - MyListP24 result = MyListP24.lottoSelect(0, 10); - assertEquals(0, result.length()); - } - - /** - * Tests selecting all numbers in range. - */ - @Test - void testSelectAll() { - MyListP24 result = MyListP24.lottoSelect(5, 5); - - assertEquals(5, result.length()); - // Should contain all numbers 1-5 in some order - Set numbers = new HashSet<>(); - for (int i = 0; i < result.length(); i++) { - numbers.add(result.elementAt(1+i)); - } - assertEquals(Set.of(1, 2, 3, 4, 5), numbers); + } + + /** Tests statistical properties of number generation. */ + @Test + void testRandomDistribution() { + Map numberCounts = new HashMap<>(); + int n = 1; + int m = 10; + + // Perform many selections to check distribution + for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { + MyListP24 result = MyListP24.lottoSelect(n, m); + for (int j = 0; j < result.length(); j++) { + int number = result.elementAt(1 + j); + numberCounts.merge(number, 1, Integer::sum); + } } - /** - * Tests that no duplicates are generated. - */ - @Test - void testNoDuplicates() { - MyListP24 result = MyListP24.lottoSelect(6, 49); - Set numbers = new HashSet<>(); - - for (int i = 0; i < result.length(); i++) { - assertTrue(numbers.add(result.elementAt(1+i)), - "Duplicate number found: " + result.elementAt(1+i)); - } + // Check that all possible numbers were selected at least once + for (int i = 1; i <= m; i++) { + assertTrue(numberCounts.containsKey(i), "Number " + i + " was never selected"); } - /** - * Tests statistical properties of number generation. - */ - @Test - void testRandomDistribution() { - Map numberCounts = new HashMap<>(); - int n = 1; - int m = 10; - - // Perform many selections to check distribution - for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { - MyListP24 result = MyListP24.lottoSelect(n, m); - for (int j = 0; j < result.length(); j++) { - int number = result.elementAt(1+j); - numberCounts.merge(number, 1, Integer::sum); - } - } - - // Check that all possible numbers were selected at least once - for (int i = 1; i <= m; i++) { - assertTrue(numberCounts.containsKey(i), - "Number " + i + " was never selected"); - } - - // Check that selections are roughly evenly distributed - // (within 20% of expected frequency) - double expectedCount = (STATISTICAL_TEST_ITERATIONS * n) / (double) m; - double tolerance = expectedCount * 0.2; // 20% tolerance - - for (Map.Entry entry : numberCounts.entrySet()) { - assertTrue(Math.abs(entry.getValue() - expectedCount) < tolerance, - "Selection frequency for " + entry.getKey() + - " deviates too much from expected"); - } - } + // Check that selections are roughly evenly distributed + // (within 20% of expected frequency) + double expectedCount = (STATISTICAL_TEST_ITERATIONS * n) / (double) m; + double tolerance = expectedCount * 0.2; // 20% tolerance - /** - * Tests consecutive lotto selections. - */ - @Test - void testConsecutiveSelections() { - MyListP24 first = MyListP24.lottoSelect(3, 10); - MyListP24 second = MyListP24.lottoSelect(3, 10); - - // Both selections should be valid - assertEquals(3, first.length()); - assertEquals(3, second.length()); - - // Check ranges - for (int i = 0; i < first.length(); i++) { - assertTrue(first.elementAt(1+i) >= 1 && first.elementAt(1+i) <= 10); - assertTrue(second.elementAt(1+i) >= 1 && second.elementAt(1+i) <= 10); - } + for (Map.Entry entry : numberCounts.entrySet()) { + assertTrue( + Math.abs(entry.getValue() - expectedCount) < tolerance, + "Selection frequency for " + entry.getKey() + " deviates too much from expected"); } - - /** - * Tests boundary conditions. - */ - @Test - void testBoundaryConditions() { - // Test selecting just one less than maximum - MyListP24 almostAll = MyListP24.lottoSelect(9, 10); - assertEquals(9, almostAll.length()); - - // Test with consecutive numbers - MyListP24 consecutive = MyListP24.lottoSelect(3, 3); - assertEquals(3, consecutive.length()); - Set numbers = new HashSet<>(); - for (int i = 0; i < consecutive.length(); i++) { - numbers.add(consecutive.elementAt(1+i)); - } - assertEquals(Set.of(1, 2, 3), numbers); + } + + /** Tests consecutive lotto selections. */ + @Test + void testConsecutiveSelections() { + MyListP24 first = MyListP24.lottoSelect(3, 10); + MyListP24 second = MyListP24.lottoSelect(3, 10); + + // Both selections should be valid + assertEquals(3, first.length()); + assertEquals(3, second.length()); + + // Check ranges + for (int i = 0; i < first.length(); i++) { + assertTrue(first.elementAt(1 + i) >= 1 && first.elementAt(1 + i) <= 10); + assertTrue(second.elementAt(1 + i) >= 1 && second.elementAt(1 + i) <= 10); } - - /** - * Tests that results are within specified range. - */ - @Test - void testNumbersInRange() { - int n = 10; - int m = 100; - MyListP24 result = MyListP24.lottoSelect(n, m); - - for (int i = 0; i < result.length(); i++) { - int number = result.elementAt(1+i); - assertTrue(number >= 1 && number <= m, - "Generated number " + number + " is outside range 1.." + m); - } + } + + /** Tests boundary conditions. */ + @Test + void testBoundaryConditions() { + // Test selecting just one less than maximum + MyListP24 almostAll = MyListP24.lottoSelect(9, 10); + assertEquals(9, almostAll.length()); + + // Test with consecutive numbers + MyListP24 consecutive = MyListP24.lottoSelect(3, 3); + assertEquals(3, consecutive.length()); + Set numbers = new HashSet<>(); + for (int i = 0; i < consecutive.length(); i++) { + numbers.add(consecutive.elementAt(1 + i)); } - - /** - * Tests with varying range sizes. - */ - @Test - void testVaryingRangeSizes() { - // Small range - MyListP24 small = MyListP24.lottoSelect(2, 3); - assertEquals(2, small.length()); - - // Medium range - MyListP24 medium = MyListP24.lottoSelect(5, 20); - assertEquals(5, medium.length()); - - // Large range - MyListP24 large = MyListP24.lottoSelect(10, 100); - assertEquals(10, large.length()); - - // Verify all are within their respective ranges - verifyRange(small, 3); - verifyRange(medium, 20); - verifyRange(large, 100); + assertEquals(Set.of(1, 2, 3), numbers); + } + + /** Tests that results are within specified range. */ + @Test + void testNumbersInRange() { + int n = 10; + int m = 100; + MyListP24 result = MyListP24.lottoSelect(n, m); + + for (int i = 0; i < result.length(); i++) { + int number = result.elementAt(1 + i); + assertTrue( + number >= 1 && number <= m, "Generated number " + number + " is outside range 1.." + m); } - - /** - * Helper method to verify numbers are within range. - */ - private void verifyRange(MyListP24 list, int max) { - for (int i = 0; i < list.length(); i++) { - int number = list.elementAt(1+i); - assertTrue(number >= 1 && number <= max, - "Number " + number + " outside range " + 1 + ".." + max); - } + } + + /** Tests with varying range sizes. */ + @Test + void testVaryingRangeSizes() { + // Small range + MyListP24 small = MyListP24.lottoSelect(2, 3); + assertEquals(2, small.length()); + + // Medium range + MyListP24 medium = MyListP24.lottoSelect(5, 20); + assertEquals(5, medium.length()); + + // Large range + MyListP24 large = MyListP24.lottoSelect(10, 100); + assertEquals(10, large.length()); + + // Verify all are within their respective ranges + verifyRange(small, 3); + verifyRange(medium, 20); + verifyRange(large, 100); + } + + /** Helper method to verify numbers are within range. */ + private void verifyRange(MyListP24 list, int max) { + for (int i = 0; i < list.length(); i++) { + int number = list.elementAt(1 + i); + assertTrue( + number >= 1 && number <= max, "Number " + number + " outside range " + 1 + ".." + max); } + } } diff --git a/src/test/java/org/nintynine/problems/MyListP25Test.java b/src/test/java/org/nintynine/problems/MyListP25Test.java index 5de29ed..6c95c8f 100644 --- a/src/test/java/org/nintynine/problems/MyListP25Test.java +++ b/src/test/java/org/nintynine/problems/MyListP25Test.java @@ -1,235 +1,204 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.*; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -/** - * Test class for MyListP25's random permutation functionality. - */ +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Test class for MyListP25's random permutation functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP25Test { - private MyListP25 list; - private static final int STATISTICAL_TEST_ITERATIONS = 10000; + private MyListP25 list; + private static final int STATISTICAL_TEST_ITERATIONS = 10000; - @BeforeEach - void setUp() { - list = new MyListP25<>("a", "b", "c", "d", "e"); - } - - /** - * Tests basic permutation functionality. - */ - @Test - void testBasicPermutation() { - MyListP25 result = list.randomPermutation(); - - assertEquals(list.length(), result.length()); - // All elements should be present - for (int i = 0; i < list.length(); i++) { - assertTrue(containsElement(result, list.elementAt(1+i))); - } - } + @BeforeEach + void setUp() { + list = new MyListP25<>("a", "b", "c", "d", "e"); + } + /** Tests basic permutation functionality. */ + @Test + void testBasicPermutation() { + MyListP25 result = list.randomPermutation(); + assertEquals(list.length(), result.length()); + // All elements should be present + for (int i = 0; i < list.length(); i++) { + assertTrue(containsElement(result, list.elementAt(1 + i))); + } + } + + /** Tests permutation of a single element list. */ + @Test + void testSingleElementPermutation() { + MyListP25 singleList = new MyListP25<>("a"); + MyListP25 result = singleList.randomPermutation(); + + assertEquals(1, result.length()); + assertEquals("a", result.elementAt(1 + 0)); + } + + /** Tests permutation of an empty list. */ + @Test + void testEmptyListPermutation() { + MyListP25 emptyList = new MyListP25<>(); + MyListP25 result = emptyList.randomPermutation(); + + assertEquals(0, result.length()); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + String[] original = new String[Math.toIntExact(list.length())]; + for (int i = 0; i < list.length(); i++) { + original[i] = list.elementAt(1 + i); + } - /** - * Tests permutation of a single element list. - */ - @Test - void testSingleElementPermutation() { - MyListP25 singleList = new MyListP25<>("a"); - MyListP25 result = singleList.randomPermutation(); + list.randomPermutation(); - assertEquals(1, result.length()); - assertEquals("a", result.elementAt(1+0)); + // The original list should be unchanged + for (int i = 0; i < list.length(); i++) { + assertEquals(original[i], list.elementAt(1 + i)); + } + } + + /** Tests that elements appear exactly once. */ + @Test + void testNoDuplicates() { + MyListP25 result = list.randomPermutation(); + Set uniqueElements = new HashSet<>(); + + for (int i = 0; i < result.length(); i++) { + assertTrue( + uniqueElements.add(result.elementAt(1 + i)), + "Duplicate element found: " + result.elementAt(1 + i)); } + } - /** - * Tests permutation of an empty list. - */ - @Test - void testEmptyListPermutation() { - MyListP25 emptyList = new MyListP25<>(); - MyListP25 result = emptyList.randomPermutation(); + /** Tests statistical properties of permutations. */ + @Test + void testRandomDistribution() { + // Count how many times each element appears at each position + Map> positionCounts = new HashMap<>(); - assertEquals(0, result.length()); + for (int i = 0; i < list.length(); i++) { + positionCounts.put(list.elementAt(1 + i), new HashMap<>()); } - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - String[] original = new String[Math.toIntExact(list.length())]; - for (int i = 0; i < list.length(); i++) { - original[i] = list.elementAt(1+i); - } - - list.randomPermutation(); - - // The original list should be unchanged - for (int i = 0; i < list.length(); i++) { - assertEquals(original[i], list.elementAt(1+i)); - } + for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { + MyListP25 permutation = list.randomPermutation(); + for (int pos = 0; pos < permutation.length(); pos++) { + String element = permutation.elementAt(1 + pos); + positionCounts.get(element).merge(pos, 1, Integer::sum); + } } - /** - * Tests that elements appear exactly once. - */ - @Test - void testNoDuplicates() { - MyListP25 result = list.randomPermutation(); - Set uniqueElements = new HashSet<>(); - - for (int i = 0; i < result.length(); i++) { - assertTrue(uniqueElements.add(result.elementAt(1+i)), - "Duplicate element found: " + result.elementAt(1+i)); - } + // Each element should appear at each position roughly equally often + double expectedCount = STATISTICAL_TEST_ITERATIONS / (double) list.length(); + double tolerance = expectedCount * 0.2; // 20% tolerance + + for (Map counts : positionCounts.values()) { + for (int pos = 0; pos < list.length(); pos++) { + int count = counts.getOrDefault(pos, 0); + assertTrue( + Math.abs(count - expectedCount) < tolerance, + "Position distribution not random enough: " + count + " vs expected " + expectedCount); + } } - - /** - * Tests statistical properties of permutations. - */ - @Test - void testRandomDistribution() { - // Count how many times each element appears at each position - Map> positionCounts = new HashMap<>(); - - for (int i = 0; i < list.length(); i++) { - positionCounts.put(list.elementAt(1+i), new HashMap<>()); - } - - for (int i = 0; i < STATISTICAL_TEST_ITERATIONS; i++) { - MyListP25 permutation = list.randomPermutation(); - for (int pos = 0; pos < permutation.length(); pos++) { - String element = permutation.elementAt(1+pos); - positionCounts.get(element).merge(pos, 1, Integer::sum); - } - } - - // Each element should appear at each position roughly equally often - double expectedCount = STATISTICAL_TEST_ITERATIONS / (double) list.length(); - double tolerance = expectedCount * 0.2; // 20% tolerance - - for (Map counts : positionCounts.values()) { - for (int pos = 0; pos < list.length(); pos++) { - int count = counts.getOrDefault(pos, 0); - assertTrue(Math.abs(count - expectedCount) < tolerance, - "Position distribution not random enough: " + count + - " vs expected " + expectedCount); - } - } + } + + /** Tests consecutive permutations. */ + @Test + void testConsecutivePermutations() { + MyListP25 firstPermutation = list.randomPermutation(); + MyListP25 secondPermutation = firstPermutation.randomPermutation(); + + assertEquals(list.length(), firstPermutation.length()); + assertEquals(list.length(), secondPermutation.length()); + + // Both should contain all original elements + for (int i = 0; i < list.length(); i++) { + String element = list.elementAt(1 + i); + assertTrue(containsElement(firstPermutation, element)); + assertTrue(containsElement(secondPermutation, element)); + } + } + + /** Tests permutation with different types. */ + @Test + void testDifferentTypes() { + // Test with integers + MyListP25 intList = new MyListP25<>(1, 2, 3, 4, 5); + MyListP25 intResult = intList.randomPermutation(); + + assertEquals(intList.length(), intResult.length()); + for (int i = 0; i < intList.length(); i++) { + assertTrue(containsElement(intResult, intList.elementAt(1 + i))); } + // Test with doubles + MyListP25 doubleList = new MyListP25<>(1.0, 2.0, 3.0); + MyListP25 doubleResult = doubleList.randomPermutation(); - - /** - * Tests consecutive permutations. - */ - @Test - void testConsecutivePermutations() { - MyListP25 firstPermutation = list.randomPermutation(); - MyListP25 secondPermutation = firstPermutation.randomPermutation(); - - assertEquals(list.length(), firstPermutation.length()); - assertEquals(list.length(), secondPermutation.length()); - - // Both should contain all original elements - for (int i = 0; i < list.length(); i++) { - String element = list.elementAt(1+i); - assertTrue(containsElement(firstPermutation, element)); - assertTrue(containsElement(secondPermutation, element)); - } + assertEquals(doubleList.length(), doubleResult.length()); + for (int i = 0; i < doubleList.length(); i++) { + assertTrue(containsElement(doubleResult, doubleList.elementAt(1 + i))); } + } - /** - * Tests permutation with different types. - */ - @Test - void testDifferentTypes() { - // Test with integers - MyListP25 intList = new MyListP25<>(1, 2, 3, 4, 5); - MyListP25 intResult = intList.randomPermutation(); - - assertEquals(intList.length(), intResult.length()); - for (int i = 0; i < intList.length(); i++) { - assertTrue(containsElement(intResult, intList.elementAt(1+i))); - } - - // Test with doubles - MyListP25 doubleList = new MyListP25<>(1.0, 2.0, 3.0); - MyListP25 doubleResult = doubleList.randomPermutation(); - - assertEquals(doubleList.length(), doubleResult.length()); - for (int i = 0; i < doubleList.length(); i++) { - assertTrue(containsElement(doubleResult, doubleList.elementAt(1+i))); - } - } + /** Tests that at least some permutations are different. */ + @Test + void testPermutationsAreDifferent() { + Set differentPermutations = new HashSet<>(); - /** - * Tests that at least some permutations are different. - */ - @Test - void testPermutationsAreDifferent() { - Set differentPermutations = new HashSet<>(); - - // Generate several permutations - for (int i = 0; i < 100; i++) { - MyListP25 result = list.randomPermutation(); - differentPermutations.add(permutationToString(result)); - } - - // We should get more than one different permutation - assertTrue(differentPermutations.size() > 1, - "All permutations were identical"); + // Generate several permutations + for (int i = 0; i < 100; i++) { + MyListP25 result = list.randomPermutation(); + differentPermutations.add(permutationToString(result)); } - /** - * Tests permutations of lists with duplicate elements. - */ - @Test - void testPermutationWithDuplicates() { - MyListP25 listWithDuplicates = new MyListP25<>("a", "b", "a", "b"); - MyListP25 result = listWithDuplicates.randomPermutation(); + // We should get more than one different permutation + assertTrue(differentPermutations.size() > 1, "All permutations were identical"); + } - assertEquals(4, result.length()); + /** Tests permutations of lists with duplicate elements. */ + @Test + void testPermutationWithDuplicates() { + MyListP25 listWithDuplicates = new MyListP25<>("a", "b", "a", "b"); + MyListP25 result = listWithDuplicates.randomPermutation(); - // Count occurrences of each element - Map counts = new HashMap<>(); - for (int i = 0; i < result.length(); i++) { - counts.merge(result.elementAt(1+i), 1, Integer::sum); - } + assertEquals(4, result.length()); - assertEquals(2, counts.get("a")); - assertEquals(2, counts.get("b")); + // Count occurrences of each element + Map counts = new HashMap<>(); + for (int i = 0; i < result.length(); i++) { + counts.merge(result.elementAt(1 + i), 1, Integer::sum); } - /** - * Helper method to check if a list contains an element. - */ - private boolean containsElement(MyListP25 list, T element) { - for (int i = 0; i < list.length(); i++) { - if (Objects.equals(list.elementAt(1+i), element)) { - return true; - } - } - return false; - } + assertEquals(2, counts.get("a")); + assertEquals(2, counts.get("b")); + } - /** - * Helper method to convert permutation to string for comparison. - */ - private String permutationToString(MyListP25 permutation) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < permutation.length(); i++) { - sb.append(permutation.elementAt(1+i)).append(","); - } - return sb.toString(); + /** Helper method to check if a list contains an element. */ + private boolean containsElement(MyListP25 list, T element) { + for (int i = 0; i < list.length(); i++) { + if (Objects.equals(list.elementAt(1 + i), element)) { + return true; + } + } + return false; + } + + /** Helper method to convert permutation to string for comparison. */ + private String permutationToString(MyListP25 permutation) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < permutation.length(); i++) { + sb.append(permutation.elementAt(1 + i)).append(","); } + return sb.toString(); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP26Test.java b/src/test/java/org/nintynine/problems/MyListP26Test.java index 1376c28..ae3020c 100644 --- a/src/test/java/org/nintynine/problems/MyListP26Test.java +++ b/src/test/java/org/nintynine/problems/MyListP26Test.java @@ -1,232 +1,200 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.List; import java.util.Objects; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP26's combination generation functionality. - */ +/** Test class for MyListP26's combination generation functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP26Test { - private MyListP26 list; - - @BeforeEach - void setUp() { - list = new MyListP26<>("a", "b", "c", "d"); + private MyListP26 list; + + @BeforeEach + void setUp() { + list = new MyListP26<>("a", "b", "c", "d"); + } + + /** Tests basic combination generation. */ + @Test + void testBasicCombinations() { + List> result = list.combinations(2); + + // C(4,2) = 6 combinations + assertEquals(6, result.size()); + + // Verify some specific combinations + assertTrue(containsCombination(result, "a", "b")); + assertTrue(containsCombination(result, "a", "c")); + assertTrue(containsCombination(result, "a", "d")); + assertTrue(containsCombination(result, "b", "c")); + assertTrue(containsCombination(result, "b", "d")); + assertTrue(containsCombination(result, "c", "d")); + } + + /** Tests combinations with k=1. */ + @Test + void testSingleElementCombinations() { + List> result = list.combinations(1); + + assertEquals(4, result.size()); + assertTrue(containsCombination(result, "a")); + assertTrue(containsCombination(result, "b")); + assertTrue(containsCombination(result, "c")); + assertTrue(containsCombination(result, "d")); + } + + /** Tests combinations with k=n (full set). */ + @Test + void testFullSetCombination() { + List> result = list.combinations(4); + + assertEquals(1, result.size()); + assertTrue(containsCombination(result, "a", "b", "c", "d")); + } + + /** Tests combinations with k=0. */ + @Test + void testEmptyCombination() { + List> result = list.combinations(0); + + assertEquals(1, result.size()); + assertEquals(0, result.getFirst().length()); + } + + /** Tests invalid k values. */ + @Test + void testInvalidInput() { + assertThrows(IllegalArgumentException.class, () -> list.combinations(-1)); + assertThrows(IllegalArgumentException.class, () -> list.combinations(5)); + } + + /** Tests combinations with an empty list. */ + @Test + void testEmptyList() { + MyListP26 emptyList = new MyListP26<>(); + List> result = emptyList.combinations(0); + + assertEquals(1, result.size()); + assertEquals(0, result.getFirst().length()); + + assertThrows(IllegalArgumentException.class, () -> emptyList.combinations(1)); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + String[] original = new String[Math.toIntExact(list.length())]; + for (int i = 0; i < list.length(); i++) { + original[i] = list.elementAt(1 + i); } - /** - * Tests basic combination generation. - */ - @Test - void testBasicCombinations() { - List> result = list.combinations(2); - - // C(4,2) = 6 combinations - assertEquals(6, result.size()); - - // Verify some specific combinations - assertTrue(containsCombination(result, "a", "b")); - assertTrue(containsCombination(result, "a", "c")); - assertTrue(containsCombination(result, "a", "d")); - assertTrue(containsCombination(result, "b", "c")); - assertTrue(containsCombination(result, "b", "d")); - assertTrue(containsCombination(result, "c", "d")); - } + list.combinations(2); - /** - * Tests combinations with k=1. - */ - @Test - void testSingleElementCombinations() { - List> result = list.combinations(1); - - assertEquals(4, result.size()); - assertTrue(containsCombination(result, "a")); - assertTrue(containsCombination(result, "b")); - assertTrue(containsCombination(result, "c")); - assertTrue(containsCombination(result, "d")); + for (int i = 0; i < list.length(); i++) { + assertEquals(original[i], list.elementAt(1 + i)); } - - /** - * Tests combinations with k=n (full set). - */ - @Test - void testFullSetCombination() { - List> result = list.combinations(4); - - assertEquals(1, result.size()); - assertTrue(containsCombination(result, "a", "b", "c", "d")); + } + + /** Tests binomial coefficient calculations. */ + @Test + void testBinomialCoefficient() { + assertEquals(1, MyListP26.binomialCoefficient(5, 0)); + assertEquals(5, MyListP26.binomialCoefficient(5, 1)); + assertEquals(10, MyListP26.binomialCoefficient(5, 2)); + assertEquals(10, MyListP26.binomialCoefficient(5, 3)); + assertEquals(5, MyListP26.binomialCoefficient(5, 4)); + assertEquals(1, MyListP26.binomialCoefficient(5, 5)); + assertEquals(0, MyListP26.binomialCoefficient(5, 6)); + } + + /** Tests that the number of combinations matches binomial coefficient. */ + @Test + void testCombinationCount() { + for (int k = 0; k <= list.length(); k++) { + List> combinations = list.combinations(k); + assertEquals( + MyListP26.binomialCoefficient(Math.toIntExact(list.length()), k), combinations.size()); } - - /** - * Tests combinations with k=0. - */ - @Test - void testEmptyCombination() { - List> result = list.combinations(0); - - assertEquals(1, result.size()); - assertEquals(0, result.getFirst().length()); - } - - /** - * Tests invalid k values. - */ - @Test - void testInvalidInput() { - assertThrows(IllegalArgumentException.class, () -> list.combinations(-1)); - assertThrows(IllegalArgumentException.class, () -> list.combinations(5)); - } - - /** - * Tests combinations with an empty list. - */ - @Test - void testEmptyList() { - MyListP26 emptyList = new MyListP26<>(); - List> result = emptyList.combinations(0); - - assertEquals(1, result.size()); - assertEquals(0, result.getFirst().length()); - - assertThrows(IllegalArgumentException.class, () -> emptyList.combinations(1)); - } - - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - String[] original = new String[Math.toIntExact(list.length())]; - for (int i = 0; i < list.length(); i++) { - original[i] = list.elementAt(1+i); - } - - list.combinations(2); - - for (int i = 0; i < list.length(); i++) { - assertEquals(original[i], list.elementAt(1+i)); - } - } - - /** - * Tests binomial coefficient calculations. - */ - @Test - void testBinomialCoefficient() { - assertEquals(1, MyListP26.binomialCoefficient(5, 0)); - assertEquals(5, MyListP26.binomialCoefficient(5, 1)); - assertEquals(10, MyListP26.binomialCoefficient(5, 2)); - assertEquals(10, MyListP26.binomialCoefficient(5, 3)); - assertEquals(5, MyListP26.binomialCoefficient(5, 4)); - assertEquals(1, MyListP26.binomialCoefficient(5, 5)); - assertEquals(0, MyListP26.binomialCoefficient(5, 6)); - } - - /** - * Tests that the number of combinations matches binomial coefficient. - */ - @Test - void testCombinationCount() { - for (int k = 0; k <= list.length(); k++) { - List> combinations = list.combinations(k); - assertEquals(MyListP26.binomialCoefficient(Math.toIntExact(list.length()), k), - combinations.size()); - } - } - - /** - * Tests combinations with different types. - */ - @Test - void testDifferentTypes() { - MyListP26 intList = new MyListP26<>(1, 2, 3, 4); - List> intResult = intList.combinations(2); - - assertEquals(6, intResult.size()); - assertTrue(containsCombination(intResult, 1, 2)); - assertTrue(containsCombination(intResult, 3, 4)); - - MyListP26 doubleList = new MyListP26<>(1.0, 2.0, 3.0); - List> doubleResult = doubleList.combinations(2); - - assertEquals(3, doubleResult.size()); - assertTrue(containsCombination(doubleResult, 1.0, 2.0)); - assertTrue(containsCombination(doubleResult, 2.0, 3.0)); - } - - /** - * Tests combinations with null values. - */ - @Test - void testCombinationsWithNulls() { - MyListP26 listWithNulls = new MyListP26<>("a", null, "c"); - assertThrows(NullPointerException.class,()->listWithNulls.combinations(2)); - - - } - - /** - * Tests combination order consistency. - */ - @Test - void testCombinationOrder() { - List> result = list.combinations(2); - - // First combination should be first two elements - MyListP26 firstCombo = result.getFirst(); - assertEquals("a", firstCombo.elementAt(1+0)); - assertEquals("b", firstCombo.elementAt(1+1)); - - // Last combination should be last two elements - MyListP26 lastCombo = result.getLast(); - assertEquals("c", lastCombo.elementAt(1+0)); - assertEquals("d", lastCombo.elementAt(1+1)); - } - - /** - * Tests large combinations for performance. - */ - @Test - void testLargeCombinations() { - MyListP26 largeList = new MyListP26<>(); - for (int i = 0; i < 20; i++) { - largeList = new MyListP26<>(Arrays.copyOf( - largeList.stream().toList().toArray(new Integer[0]), - (int) (largeList.length() + 1) - )); - largeList.items[Math.toIntExact(largeList.length() - 1)] = i; - } - - // Test combinations of size 3 from 20 elements - List> result = largeList.combinations(3); - assertEquals(MyListP26.binomialCoefficient(20, 3), result.size()); + } + + /** Tests combinations with different types. */ + @Test + void testDifferentTypes() { + MyListP26 intList = new MyListP26<>(1, 2, 3, 4); + List> intResult = intList.combinations(2); + + assertEquals(6, intResult.size()); + assertTrue(containsCombination(intResult, 1, 2)); + assertTrue(containsCombination(intResult, 3, 4)); + + MyListP26 doubleList = new MyListP26<>(1.0, 2.0, 3.0); + List> doubleResult = doubleList.combinations(2); + + assertEquals(3, doubleResult.size()); + assertTrue(containsCombination(doubleResult, 1.0, 2.0)); + assertTrue(containsCombination(doubleResult, 2.0, 3.0)); + } + + /** Tests combinations with null values. */ + @Test + void testCombinationsWithNulls() { + MyListP26 listWithNulls = new MyListP26<>("a", null, "c"); + assertThrows(NullPointerException.class, () -> listWithNulls.combinations(2)); + } + + /** Tests combination order consistency. */ + @Test + void testCombinationOrder() { + List> result = list.combinations(2); + + // First combination should be first two elements + MyListP26 firstCombo = result.getFirst(); + assertEquals("a", firstCombo.elementAt(1 + 0)); + assertEquals("b", firstCombo.elementAt(1 + 1)); + + // Last combination should be last two elements + MyListP26 lastCombo = result.getLast(); + assertEquals("c", lastCombo.elementAt(1 + 0)); + assertEquals("d", lastCombo.elementAt(1 + 1)); + } + + /** Tests large combinations for performance. */ + @Test + void testLargeCombinations() { + MyListP26 largeList = new MyListP26<>(); + for (int i = 0; i < 20; i++) { + largeList = + new MyListP26<>( + Arrays.copyOf( + largeList.stream().toList().toArray(new Integer[0]), + (int) (largeList.length() + 1))); + largeList.items[Math.toIntExact(largeList.length() - 1)] = i; } - /** - * Helper method to check if combinations contain specific elements. - */ - @SafeVarargs - private boolean containsCombination(List> combinations, T... elements) { - outer: - for (MyListP26 combination : combinations) { - if (combination.length() != elements.length) continue; - - for (int i = 0; i < elements.length; i++) { - if (!Objects.equals(combination.elementAt(1+i), elements[i])) { - continue outer; - } - } - return true; + // Test combinations of size 3 from 20 elements + List> result = largeList.combinations(3); + assertEquals(MyListP26.binomialCoefficient(20, 3), result.size()); + } + + /** Helper method to check if combinations contain specific elements. */ + @SafeVarargs + private boolean containsCombination(List> combinations, T... elements) { + outer: + for (MyListP26 combination : combinations) { + if (combination.length() != elements.length) continue; + + for (int i = 0; i < elements.length; i++) { + if (!Objects.equals(combination.elementAt(1 + i), elements[i])) { + continue outer; } - return false; + } + return true; } + return false; + } } diff --git a/src/test/java/org/nintynine/problems/MyListP27Test.java b/src/test/java/org/nintynine/problems/MyListP27Test.java index 7058578..21dc7a1 100644 --- a/src/test/java/org/nintynine/problems/MyListP27Test.java +++ b/src/test/java/org/nintynine/problems/MyListP27Test.java @@ -1,211 +1,176 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP27's group generation functionality. - */ +/** Test class for MyListP27's group generation functionality. */ class MyListP27Test { - private MyListP27 list9; - private MyListP27 list5; + private MyListP27 list9; + private MyListP27 list5; - @BeforeEach - void setUp() { - list9 = new MyListP27<>("a", "b", "c", "d", "e", "f", "g", "h", "i"); - list5 = new MyListP27<>("a", "b", "c", "d", "e"); - } + @BeforeEach + void setUp() { + list9 = new MyListP27<>("a", "b", "c", "d", "e", "f", "g", "h", "i"); + list5 = new MyListP27<>("a", "b", "c", "d", "e"); + } - /** - * Tests basic group3 functionality. - */ - @Test - void testGroup3() { - List>> result = list9.group3(); - - assertFalse(result.isEmpty()); - - // Verify the structure of each grouping - for (List> grouping : result) { - assertEquals(3, grouping.size()); - assertEquals(2, grouping.get(0).length()); - assertEquals(3, grouping.get(1).length()); - assertEquals(4, grouping.get(2).length()); - } - } + /** Tests basic group3 functionality. */ + @Test + void testGroup3() { + List>> result = list9.group3(); - /** - * Tests custom group sizes. - */ - @Test - void testCustomGroups() { - List>> result = - list5.group(Arrays.asList(2, 3)); - - assertFalse(result.isEmpty()); - - // Verify the structure of each grouping - for (List> grouping : result) { - assertEquals(2, grouping.size()); - assertEquals(2, grouping.get(0).length()); - assertEquals(3, grouping.get(1).length()); - } - } + assertFalse(result.isEmpty()); - /** - * Tests invalid group sizes. - */ - @Test - void testInvalidGroupSizes() { - assertThrows(IllegalArgumentException.class, - () -> list5.group(Arrays.asList(2, 2))); - assertThrows(IllegalArgumentException.class, - () -> list5.group(Arrays.asList(2, 4))); + // Verify the structure of each grouping + for (List> grouping : result) { + assertEquals(3, grouping.size()); + assertEquals(2, grouping.get(0).length()); + assertEquals(3, grouping.get(1).length()); + assertEquals(4, grouping.get(2).length()); } + } - /** - * Tests empty list and single element groups. - */ - @Test - void testEdgeCases() { - MyListP27 emptyList = new MyListP27<>(); - assertEquals(1, emptyList.group(Collections.emptyList()).size()); - - MyListP27 singleList = new MyListP27<>("a"); - List>> result = - singleList.group(Collections.singletonList(1)); - assertEquals(1, result.size()); - assertEquals(1, result.getFirst().size()); - assertEquals(1, result.getFirst().getFirst().length()); - } + /** Tests custom group sizes. */ + @Test + void testCustomGroups() { + List>> result = list5.group(Arrays.asList(2, 3)); - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - String[] original = new String[Math.toIntExact(list5.length())]; - for (int i = 0; i < list5.length(); i++) { - original[i] = list5.elementAt(1+i); - } + assertFalse(result.isEmpty()); - list5.group(Arrays.asList(2, 3)); - - for (int i = 0; i < list5.length(); i++) { - assertEquals(original[i], list5.elementAt(1+i)); - } + // Verify the structure of each grouping + for (List> grouping : result) { + assertEquals(2, grouping.size()); + assertEquals(2, grouping.get(0).length()); + assertEquals(3, grouping.get(1).length()); } - - /** - * Tests multinomial coefficient calculation. - */ - @Test - void testMultinomialCoefficient() { - assertEquals(1, MyListP27.multinomialCoefficient(1, 1)); - assertEquals(6, MyListP27.multinomialCoefficient(4, 2, 2)); - assertEquals(90, MyListP27.multinomialCoefficient(6, 2, 2, 2)); + } + + /** Tests invalid group sizes. */ + @Test + void testInvalidGroupSizes() { + assertThrows(IllegalArgumentException.class, () -> list5.group(Arrays.asList(2, 2))); + assertThrows(IllegalArgumentException.class, () -> list5.group(Arrays.asList(2, 4))); + } + + /** Tests empty list and single element groups. */ + @Test + void testEdgeCases() { + MyListP27 emptyList = new MyListP27<>(); + assertEquals(1, emptyList.group(Collections.emptyList()).size()); + + MyListP27 singleList = new MyListP27<>("a"); + List>> result = singleList.group(Collections.singletonList(1)); + assertEquals(1, result.size()); + assertEquals(1, result.getFirst().size()); + assertEquals(1, result.getFirst().getFirst().length()); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + String[] original = new String[Math.toIntExact(list5.length())]; + for (int i = 0; i < list5.length(); i++) { + original[i] = list5.elementAt(1 + i); } - /** - * Tests that the number of groups matches multinomial coefficient. - */ - @Test - void testGroupCount() { - List>> result = list5.group(Arrays.asList(2, 3)); - assertEquals(MyListP27.multinomialCoefficient(5, 2, 3), result.size()); - } + list5.group(Arrays.asList(2, 3)); - /** - * Tests groups with different types. - */ - @Test - void testDifferentTypes() { - MyListP27 intList = new MyListP27<>(1, 2, 3, 4); - List>> intResult = - intList.group(Arrays.asList(2, 2)); - - assertFalse(intResult.isEmpty()); - for (List> grouping : intResult) { - assertEquals(2, grouping.size()); - assertEquals(2, grouping.get(0).length()); - assertEquals(2, grouping.get(1).length()); - } + for (int i = 0; i < list5.length(); i++) { + assertEquals(original[i], list5.elementAt(1 + i)); } - - /** - * Tests that groups are disjoint. - */ - @Test - void testDisjointGroups() { - List>> result = - list5.group(Arrays.asList(2, 3)); - - for (List> grouping : result) { - Set allElements = new HashSet<>(); - for (MyListP27 group : grouping) { - for (int i = 0; i < group.length(); i++) { - assertTrue(allElements.add(group.elementAt(1+i)), - "Element appears in multiple groups: " + group.elementAt(1+i)); - } - } - } + } + + /** Tests multinomial coefficient calculation. */ + @Test + void testMultinomialCoefficient() { + assertEquals(1, MyListP27.multinomialCoefficient(1, 1)); + assertEquals(6, MyListP27.multinomialCoefficient(4, 2, 2)); + assertEquals(90, MyListP27.multinomialCoefficient(6, 2, 2, 2)); + } + + /** Tests that the number of groups matches multinomial coefficient. */ + @Test + void testGroupCount() { + List>> result = list5.group(Arrays.asList(2, 3)); + assertEquals(MyListP27.multinomialCoefficient(5, 2, 3), result.size()); + } + + /** Tests groups with different types. */ + @Test + void testDifferentTypes() { + MyListP27 intList = new MyListP27<>(1, 2, 3, 4); + List>> intResult = intList.group(Arrays.asList(2, 2)); + + assertFalse(intResult.isEmpty()); + for (List> grouping : intResult) { + assertEquals(2, grouping.size()); + assertEquals(2, grouping.get(0).length()); + assertEquals(2, grouping.get(1).length()); } - - /** - * Tests that each element appears in some group. - */ - @Test - void testCompleteGroups() { - List>> result = - list5.group(Arrays.asList(2, 3)); - - for (List> grouping : result) { - Set allElements = new HashSet<>(); - for (MyListP27 group : grouping) { - for (int i = 0; i < group.length(); i++) { - allElements.add(group.elementAt(1+i)); - } - } - assertEquals(list5.length(), allElements.size()); + } + + /** Tests that groups are disjoint. */ + @Test + void testDisjointGroups() { + List>> result = list5.group(Arrays.asList(2, 3)); + + for (List> grouping : result) { + Set allElements = new HashSet<>(); + for (MyListP27 group : grouping) { + for (int i = 0; i < group.length(); i++) { + assertTrue( + allElements.add(group.elementAt(1 + i)), + "Element appears in multiple groups: " + group.elementAt(1 + i)); } + } } - - /** - * Tests group order consistency. - */ - @Test - void testGroupOrder() { - List>> result = - list5.group(Arrays.asList(2, 3)); - - for (List> grouping : result) { - assertEquals(2, grouping.get(0).length()); - assertEquals(3, grouping.get(1).length()); + } + + /** Tests that each element appears in some group. */ + @Test + void testCompleteGroups() { + List>> result = list5.group(Arrays.asList(2, 3)); + + for (List> grouping : result) { + Set allElements = new HashSet<>(); + for (MyListP27 group : grouping) { + for (int i = 0; i < group.length(); i++) { + allElements.add(group.elementAt(1 + i)); } + } + assertEquals(list5.length(), allElements.size()); } + } + /** Tests group order consistency. */ + @Test + void testGroupOrder() { + List>> result = list5.group(Arrays.asList(2, 3)); - /** - * Tests performance with larger groups. - */ - @Test - void testLargeGroups() { - MyListP27 largeList = new MyListP27<>(); - for (int i = 0; i < 8; i++) { - largeList = new MyListP27<>(Arrays.copyOf( - largeList.stream().toList().toArray(new Integer[0]), - Math.toIntExact(largeList.length() + 1) - )); - largeList.items[Math.toIntExact(largeList.length() - 1)] = i; - } - - List>> result = - largeList.group(Arrays.asList(3, 2, 3)); - assertFalse(result.isEmpty()); + for (List> grouping : result) { + assertEquals(2, grouping.get(0).length()); + assertEquals(3, grouping.get(1).length()); + } + } + + /** Tests performance with larger groups. */ + @Test + void testLargeGroups() { + MyListP27 largeList = new MyListP27<>(); + for (int i = 0; i < 8; i++) { + largeList = + new MyListP27<>( + Arrays.copyOf( + largeList.stream().toList().toArray(new Integer[0]), + Math.toIntExact(largeList.length() + 1))); + largeList.items[Math.toIntExact(largeList.length() - 1)] = i; } + + List>> result = largeList.group(Arrays.asList(3, 2, 3)); + assertFalse(result.isEmpty()); + } } diff --git a/src/test/java/org/nintynine/problems/MyListP28Test.java b/src/test/java/org/nintynine/problems/MyListP28Test.java index 641c918..6629794 100644 --- a/src/test/java/org/nintynine/problems/MyListP28Test.java +++ b/src/test/java/org/nintynine/problems/MyListP28Test.java @@ -1,210 +1,174 @@ package org.nintynine.problems; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Test class for MyListP28's list sorting functionality. - */ +/** Test class for MyListP28's list sorting functionality. */ @SuppressWarnings("PointlessArithmeticExpression") class MyListP28Test { - private MyListP28 listOfLists; - - @BeforeEach - void setUp() { - listOfLists = MyListP28.of( - new MyListP28<>("a", "b", "c"), - new MyListP28<>("d", "e"), - new MyListP28<>("f", "g", "h"), - new MyListP28<>("d", "e"), - new MyListP28<>("i", "j", "k", "l"), - new MyListP28<>("m", "n"), - new MyListP28<>("o") - ); - } - - /** - * Tests basic length-based sorting. - */ - @Test - void testLSort() { - MyListP28 sorted = listOfLists.lsort(); - - // Verify ascending order by length - int prevLength = -1; - for (int i = 0; i < sorted.length(); i++) { - int currentLength = Math.toIntExact(sorted.elementAt(1 + i).length()); - assertTrue(currentLength >= prevLength, String.format("At index %d, expected length %d, got %d", i, prevLength, currentLength)); - prevLength = currentLength; - } - } - - /** - * Tests frequency-based sorting. - */ - @Test - void testLFSort() { - MyListP28 sorted = listOfLists.lfsort(); - - // Verify rare lengths come first - Map lengthFreq = new HashMap<>(); - for (int i = 0; i < sorted.length(); i++) { - lengthFreq.merge(Math.toIntExact(sorted.elementAt(1 + i).length()), 1, Integer::sum); - } - - int prevFreq = -1; - for (int i = 0; i < sorted.length(); i++) { - int currentFreq = lengthFreq.get(Math.toIntExact(sorted.elementAt(1+i).length())); - assertTrue(currentFreq >= prevFreq); - prevFreq = currentFreq; - } - } - - /** - * Tests empty list handling. - */ - @Test - void testEmptyList() { - MyListP28 emptyList = MyListP28.of(); - - assertEquals(0, emptyList.lsort().length()); - assertEquals(0, emptyList.lfsort().length()); + private MyListP28 listOfLists; + + @BeforeEach + void setUp() { + listOfLists = + MyListP28.of( + new MyListP28<>("a", "b", "c"), + new MyListP28<>("d", "e"), + new MyListP28<>("f", "g", "h"), + new MyListP28<>("d", "e"), + new MyListP28<>("i", "j", "k", "l"), + new MyListP28<>("m", "n"), + new MyListP28<>("o")); + } + + /** Tests basic length-based sorting. */ + @Test + void testLSort() { + MyListP28 sorted = listOfLists.lsort(); + + // Verify ascending order by length + int prevLength = -1; + for (int i = 0; i < sorted.length(); i++) { + int currentLength = Math.toIntExact(sorted.elementAt(1 + i).length()); + assertTrue( + currentLength >= prevLength, + String.format("At index %d, expected length %d, got %d", i, prevLength, currentLength)); + prevLength = currentLength; } + } - /** - * Tests list with a single element. - */ - @Test - void testSingleElement() { - MyListP28 singleList = MyListP28.of( - new MyListP28<>("a", "b") - ); - - assertEquals(1, singleList.lsort().length()); - assertEquals(1, singleList.lfsort().length()); - } - - /** - * Tests that original list remains unchanged. - */ - @Test - void testOriginalListUnchanged() { - MyListP28[] original = Arrays.copyOf( - listOfLists.items, - Math.toIntExact(listOfLists.length()) - ); - - listOfLists.lsort(); - listOfLists.lfsort(); - - assertArrayEquals(original, listOfLists.items); - } - - /** - * Tests sorting with different types. - */ - @Test - void testDifferentTypes() { - MyListP28 intListOfLists = MyListP28.of( - new MyListP28<>(1, 2, 3), - new MyListP28<>(4, 5), - new MyListP28<>(6) - ); - - MyListP28 sortedByLength = intListOfLists.lsort(); - assertEquals(1, sortedByLength.elementAt(1+0).length()); - assertEquals(2, sortedByLength.elementAt(1+1).length()); - assertEquals(3, sortedByLength.elementAt(1+2).length()); - } - - /** - * Tests lists with same lengths. - */ - @Test - void testSameLengths() { - MyListP28 sameLengths = MyListP28.of( - new MyListP28<>("a", "b"), - new MyListP28<>("c", "d"), - new MyListP28<>("e", "f") - ); - - assertEquals(3, sameLengths.lsort().length()); - assertEquals(3, sameLengths.lfsort().length()); - } - - /** - * Tests lists with null elements. - */ - @Test - void testWithNulls() { - MyListP28 listWithNulls = MyListP28.of( - new MyListP28<>("a", null), - new MyListP28<>(null, null, null) - ); - - MyListP28 sorted = listWithNulls.lsort(); - assertEquals(2, sorted.elementAt(1+0).length()); - assertEquals(3, sorted.elementAt(1+1).length()); - } - - /** - * Tests stability of sorting. - */ - @Test - void testSortingStability() { - MyListP28 list = MyListP28.of( - new MyListP28<>("a", "b"), - new MyListP28<>("c", "d"), - new MyListP28<>("e", "f", "g"), - new MyListP28<>("h", "i") - ); - - MyListP28 sorted = list.lsort(); - - // Check that the relative order of same-length lists is preserved - assertEquals("a", sorted.elementAt(1+0).elementAt(1+0).elementAt(1+0).toString()); - assertEquals("c", sorted.elementAt(1+1).elementAt(1+0).elementAt(1+0).toString()); - } + /** Tests frequency-based sorting. */ + @Test + void testLFSort() { + MyListP28 sorted = listOfLists.lfsort(); - /** - * Tests edge cases with varying lengths. - */ - @Test - void testVaryingLengths() { - MyListP28 varying = MyListP28.of( - new MyListP28<>(1), - new MyListP28<>(1, 2, 3, 4, 5), - new MyListP28<>(1, 2), - new MyListP28<>(1, 2, 3) - ); - - MyListP28 sorted = varying.lsort(); - assertEquals(1, sorted.elementAt(1+0).length()); - assertEquals(5, sorted.elementAt(1+3).length()); + // Verify rare lengths come first + Map lengthFreq = new HashMap<>(); + for (int i = 0; i < sorted.length(); i++) { + lengthFreq.merge(Math.toIntExact(sorted.elementAt(1 + i).length()), 1, Integer::sum); } - /** - * Tests frequency sorting with equal frequencies. - */ - @Test - void testEqualFrequencies() { - MyListP28 equalFreq = MyListP28.of( - new MyListP28<>("a"), - new MyListP28<>("b", "c"), - new MyListP28<>("d", "e", "f") - ); - - MyListP28 sorted = equalFreq.lfsort(); - // When frequencies are equal, should maintain length order - assertEquals(1, sorted.elementAt(1+0).length()); - assertEquals(2, sorted.elementAt(1+1).length()); - assertEquals(3, sorted.elementAt(1+2).length()); + int prevFreq = -1; + for (int i = 0; i < sorted.length(); i++) { + int currentFreq = lengthFreq.get(Math.toIntExact(sorted.elementAt(1 + i).length())); + assertTrue(currentFreq >= prevFreq); + prevFreq = currentFreq; } + } + + /** Tests empty list handling. */ + @Test + void testEmptyList() { + MyListP28 emptyList = MyListP28.of(); + + assertEquals(0, emptyList.lsort().length()); + assertEquals(0, emptyList.lfsort().length()); + } + + /** Tests list with a single element. */ + @Test + void testSingleElement() { + MyListP28 singleList = MyListP28.of(new MyListP28<>("a", "b")); + + assertEquals(1, singleList.lsort().length()); + assertEquals(1, singleList.lfsort().length()); + } + + /** Tests that original list remains unchanged. */ + @Test + void testOriginalListUnchanged() { + MyListP28[] original = + Arrays.copyOf(listOfLists.items, Math.toIntExact(listOfLists.length())); + + listOfLists.lsort(); + listOfLists.lfsort(); + + assertArrayEquals(original, listOfLists.items); + } + + /** Tests sorting with different types. */ + @Test + void testDifferentTypes() { + MyListP28 intListOfLists = + MyListP28.of(new MyListP28<>(1, 2, 3), new MyListP28<>(4, 5), new MyListP28<>(6)); + + MyListP28 sortedByLength = intListOfLists.lsort(); + assertEquals(1, sortedByLength.elementAt(1 + 0).length()); + assertEquals(2, sortedByLength.elementAt(1 + 1).length()); + assertEquals(3, sortedByLength.elementAt(1 + 2).length()); + } + + /** Tests lists with same lengths. */ + @Test + void testSameLengths() { + MyListP28 sameLengths = + MyListP28.of( + new MyListP28<>("a", "b"), new MyListP28<>("c", "d"), new MyListP28<>("e", "f")); + + assertEquals(3, sameLengths.lsort().length()); + assertEquals(3, sameLengths.lfsort().length()); + } + + /** Tests lists with null elements. */ + @Test + void testWithNulls() { + MyListP28 listWithNulls = + MyListP28.of(new MyListP28<>("a", null), new MyListP28<>(null, null, null)); + + MyListP28 sorted = listWithNulls.lsort(); + assertEquals(2, sorted.elementAt(1 + 0).length()); + assertEquals(3, sorted.elementAt(1 + 1).length()); + } + + /** Tests stability of sorting. */ + @Test + void testSortingStability() { + MyListP28 list = + MyListP28.of( + new MyListP28<>("a", "b"), + new MyListP28<>("c", "d"), + new MyListP28<>("e", "f", "g"), + new MyListP28<>("h", "i")); + + MyListP28 sorted = list.lsort(); + + // Check that the relative order of same-length lists is preserved + assertEquals("a", sorted.elementAt(1 + 0).elementAt(1 + 0).elementAt(1 + 0).toString()); + assertEquals("c", sorted.elementAt(1 + 1).elementAt(1 + 0).elementAt(1 + 0).toString()); + } + + /** Tests edge cases with varying lengths. */ + @Test + void testVaryingLengths() { + MyListP28 varying = + MyListP28.of( + new MyListP28<>(1), + new MyListP28<>(1, 2, 3, 4, 5), + new MyListP28<>(1, 2), + new MyListP28<>(1, 2, 3)); + + MyListP28 sorted = varying.lsort(); + assertEquals(1, sorted.elementAt(1 + 0).length()); + assertEquals(5, sorted.elementAt(1 + 3).length()); + } + + /** Tests frequency sorting with equal frequencies. */ + @Test + void testEqualFrequencies() { + MyListP28 equalFreq = + MyListP28.of( + new MyListP28<>("a"), new MyListP28<>("b", "c"), new MyListP28<>("d", "e", "f")); + + MyListP28 sorted = equalFreq.lfsort(); + // When frequencies are equal, should maintain length order + assertEquals(1, sorted.elementAt(1 + 0).length()); + assertEquals(2, sorted.elementAt(1 + 1).length()); + assertEquals(3, sorted.elementAt(1 + 2).length()); + } } diff --git a/src/test/java/org/nintynine/problems/TruthP46Test.java b/src/test/java/org/nintynine/problems/TruthP46Test.java index 69f67a8..346cce8 100644 --- a/src/test/java/org/nintynine/problems/TruthP46Test.java +++ b/src/test/java/org/nintynine/problems/TruthP46Test.java @@ -1,126 +1,115 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - class TruthP46Test { - @Test - @DisplayName("Test example: (and A (or A B))") - void testExample() { - List table = - TruthP46.table("(and A (or A B))"); - - assertFalse(table.get(0).result()); // F F -> F - assertFalse(table.get(1).result()); // F T -> F - assertTrue(table.get(2).result()); // T F -> T - assertTrue(table.get(3).result()); // T T -> T - - // Print the table - System.out.println("Truth table for (and A (or A B)):"); - System.out.println(TruthP46.formatTruthTable(table)); - } - - @Test - @DisplayName("Test all logical operators") - void testAllOperators() { - // Test AND - verifyOperation("(and A B)", - new boolean[]{false, false, false, true}); - - // Test OR - verifyOperation("(or A B)", - new boolean[]{false, true, true, true}); - - // Test NAND - verifyOperation("(nand A B)", - new boolean[]{true, true, true, false}); - - // Test NOR - verifyOperation("(nor A B)", - new boolean[]{true, false, false, false}); - - // Test XOR - verifyOperation("(xor A B)", - new boolean[]{false, true, true, false}); - - // Test IMPL - verifyOperation("(impl A B)", - new boolean[]{true, true, false, true}); - - // Test EQU - verifyOperation("(equ A B)", - new boolean[]{true, false, false, true}); + @Test + @DisplayName("Test example: (and A (or A B))") + void testExample() { + List table = TruthP46.table("(and A (or A B))"); + + assertFalse(table.get(0).result()); // F F -> F + assertFalse(table.get(1).result()); // F T -> F + assertTrue(table.get(2).result()); // T F -> T + assertTrue(table.get(3).result()); // T T -> T + + // Print the table + System.out.println("Truth table for (and A (or A B)):"); + System.out.println(TruthP46.formatTruthTable(table)); + } + + @Test + @DisplayName("Test all logical operators") + void testAllOperators() { + // Test AND + verifyOperation("(and A B)", new boolean[] {false, false, false, true}); + + // Test OR + verifyOperation("(or A B)", new boolean[] {false, true, true, true}); + + // Test NAND + verifyOperation("(nand A B)", new boolean[] {true, true, true, false}); + + // Test NOR + verifyOperation("(nor A B)", new boolean[] {true, false, false, false}); + + // Test XOR + verifyOperation("(xor A B)", new boolean[] {false, true, true, false}); + + // Test IMPL + verifyOperation("(impl A B)", new boolean[] {true, true, false, true}); + + // Test EQU + verifyOperation("(equ A B)", new boolean[] {true, false, false, true}); + } + + @Test + @DisplayName("Test complex expressions") + void testComplexExpressions() { + // (A or B) and (A nand B) + List table = TruthP46.table("(and (or A B) (nand A B))"); + + System.out.println("Truth table for (and (or A B) (nand A B)):"); + System.out.println(TruthP46.formatTruthTable(table)); + + // Verify results + assertFalse(table.get(0).result()); // F F -> F + assertTrue(table.get(1).result()); // F T -> T + assertTrue(table.get(2).result()); // T F -> T + assertFalse(table.get(3).result()); // T T -> F + } + + @ParameterizedTest + @DisplayName("Test invalid expressions") + @ValueSource( + strings = { + "", // Empty + "X", // Invalid variable + "()", // Empty parentheses + "(and)", // Missing operands + "(and A)", // Missing second operand + "(invalid A B)", // Invalid operator + "(and A B C)", // Too many operands + "(and A (or B))" // Incomplete nested expression + }) + void testInvalidExpressions(String expression) { + assertThrows(IllegalArgumentException.class, () -> TruthP46.table(expression)); + } + + @Test + @DisplayName("Test nested expressions") + void testNestedExpressions() { + // ((A and B) or (A xor B)) + List table = TruthP46.table("(or (and A B) (xor A B))"); + + System.out.println("Truth table for (or (and A B) (xor A B)):"); + System.out.println(TruthP46.formatTruthTable(table)); + + // Verify specific cases + assertFalse(table.get(0).result()); // F F -> F + assertTrue(table.get(1).result()); // F T -> T + assertTrue(table.get(2).result()); // T F -> T + assertTrue(table.get(3).result()); // T T -> T + } + + private void verifyOperation(String expression, boolean[] expectedResults) { + List table = TruthP46.table(expression); + assertEquals(4, table.size()); + + for (int i = 0; i < 4; i++) { + assertEquals( + expectedResults[i], table.get(i).result(), "Mismatch at row " + i + " for " + expression); } - @Test - @DisplayName("Test complex expressions") - void testComplexExpressions() { - // (A or B) and (A nand B) - List table = - TruthP46.table("(and (or A B) (nand A B))"); - - System.out.println("Truth table for (and (or A B) (nand A B)):"); - System.out.println(TruthP46.formatTruthTable(table)); - - // Verify results - assertFalse(table.get(0).result()); // F F -> F - assertTrue(table.get(1).result()); // F T -> T - assertTrue(table.get(2).result()); // T F -> T - assertFalse(table.get(3).result()); // T T -> F - } - - @ParameterizedTest - @DisplayName("Test invalid expressions") - @ValueSource(strings = { - "", // Empty - "X", // Invalid variable - "()", // Empty parentheses - "(and)", // Missing operands - "(and A)", // Missing second operand - "(invalid A B)", // Invalid operator - "(and A B C)", // Too many operands - "(and A (or B))" // Incomplete nested expression - }) - void testInvalidExpressions(String expression) { - assertThrows(IllegalArgumentException.class, - () -> TruthP46.table(expression)); - } - - @Test - @DisplayName("Test nested expressions") - void testNestedExpressions() { - // ((A and B) or (A xor B)) - List table = - TruthP46.table("(or (and A B) (xor A B))"); - - System.out.println("Truth table for (or (and A B) (xor A B)):"); - System.out.println(TruthP46.formatTruthTable(table)); - - // Verify specific cases - assertFalse(table.get(0).result()); // F F -> F - assertTrue(table.get(1).result()); // F T -> T - assertTrue(table.get(2).result()); // T F -> T - assertTrue(table.get(3).result()); // T T -> T - } - - private void verifyOperation(String expression, boolean[] expectedResults) { - List table = TruthP46.table(expression); - assertEquals(4, table.size()); - - for (int i = 0; i < 4; i++) { - assertEquals(expectedResults[i], table.get(i).result(), - "Mismatch at row " + i + " for " + expression); - } - - // Print the table - System.out.println("Truth table for " + expression + ":"); - System.out.println(TruthP46.formatTruthTable(table)); - } + // Print the table + System.out.println("Truth table for " + expression + ":"); + System.out.println(TruthP46.formatTruthTable(table)); + } } diff --git a/src/test/java/org/nintynine/problems/TruthP47Test.java b/src/test/java/org/nintynine/problems/TruthP47Test.java index 0d08084..0498184 100644 --- a/src/test/java/org/nintynine/problems/TruthP47Test.java +++ b/src/test/java/org/nintynine/problems/TruthP47Test.java @@ -1,137 +1,124 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - class TruthP47Test { - @Test - @DisplayName("Test example: A and (A or (not B))") - void testExample() { - List table = - TruthP47.table("(A and (A or (not B)))"); - - System.out.println("Truth table for (A and (A or (not B))):"); - System.out.println(TruthP47.formatTruthTable(table)); - - assertFalse(table.get(0).result()); // F F -> F - assertFalse(table.get(1).result()); // F T -> F - assertTrue(table.get(2).result()); // T F -> T - assertTrue(table.get(3).result()); // T T -> T - } - - @Test - @DisplayName("Test all binary operators") - void testAllBinaryOperators() { - // Test AND - verifyOperation("(A and B)", - new boolean[]{false, false, false, true}); - - // Test OR - verifyOperation("(A or B)", - new boolean[]{false, true, true, true}); - - // Test NAND - verifyOperation("(A nand B)", - new boolean[]{true, true, true, false}); - - // Test NOR - verifyOperation("(A nor B)", - new boolean[]{true, false, false, false}); - - // Test XOR - verifyOperation("(A xor B)", - new boolean[]{false, true, true, false}); - - // Test IMPL - verifyOperation("(A impl B)", - new boolean[]{true, true, false, true}); - - // Test EQU - verifyOperation("(A equ B)", - new boolean[]{true, false, false, true}); + @Test + @DisplayName("Test example: A and (A or (not B))") + void testExample() { + List table = TruthP47.table("(A and (A or (not B)))"); + + System.out.println("Truth table for (A and (A or (not B))):"); + System.out.println(TruthP47.formatTruthTable(table)); + + assertFalse(table.get(0).result()); // F F -> F + assertFalse(table.get(1).result()); // F T -> F + assertTrue(table.get(2).result()); // T F -> T + assertTrue(table.get(3).result()); // T T -> T + } + + @Test + @DisplayName("Test all binary operators") + void testAllBinaryOperators() { + // Test AND + verifyOperation("(A and B)", new boolean[] {false, false, false, true}); + + // Test OR + verifyOperation("(A or B)", new boolean[] {false, true, true, true}); + + // Test NAND + verifyOperation("(A nand B)", new boolean[] {true, true, true, false}); + + // Test NOR + verifyOperation("(A nor B)", new boolean[] {true, false, false, false}); + + // Test XOR + verifyOperation("(A xor B)", new boolean[] {false, true, true, false}); + + // Test IMPL + verifyOperation("(A impl B)", new boolean[] {true, true, false, true}); + + // Test EQU + verifyOperation("(A equ B)", new boolean[] {true, false, false, true}); + } + + @Test + @DisplayName("Test NOT operator") + void testNotOperator() { + // Test simple NOT + verifyOperation("(not A)", new boolean[] {true, true, false, false}); + + // Test NOT with AND + verifyOperation("(not (A and B))", new boolean[] {true, true, true, false}); + + // Test nested NOT + verifyOperation("(not (not (A and B)))", new boolean[] {false, false, false, true}); + } + + @Test + @DisplayName("Test complex expressions") + void testComplexExpressions() { + // Test expression with multiple operators + List table = TruthP47.table("((A and B) or (not (A and B)))"); + + System.out.println("Truth table for ((A and B) or (not (A and B))):"); + System.out.println(TruthP47.formatTruthTable(table)); + + // This expression is a tautology (always true) + assertTrue(table.stream().allMatch(TruthP47.TruthTableRow::result)); + } + + @ParameterizedTest + @DisplayName("Test invalid expressions") + @ValueSource( + strings = { + "", // Empty + "X", // Invalid variable + "()", // Empty parentheses + "(A and)", // Missing operand + "(and A B)", // Prefix notation (invalid) + "(A invalid B)", // Invalid operator + "(A and B C)", // Too many operands + "(A and (B))", // Malformed expression + "A and B" // Missing parentheses + }) + void testInvalidExpressions(String expression) { + assertThrows(IllegalArgumentException.class, () -> TruthP47.table(expression)); + } + + @Test + @DisplayName("Test deeply nested expressions") + void testDeeplyNestedExpressions() { + String expression = "(A and (not (B or (not (A and B)))))"; + List table = TruthP47.table(expression); + + System.out.println("Truth table for " + expression + ":"); + System.out.println(TruthP47.formatTruthTable(table)); + + // Verify specific cases + assertFalse(table.get(0).result()); // F F -> F + assertFalse(table.get(1).result()); // F T -> F + assertFalse(table.get(2).result()); // T F -> F + assertFalse(table.get(3).result()); // T T -> T + } + + private void verifyOperation(String expression, boolean[] expectedResults) { + List table = TruthP47.table(expression); + assertEquals(4, table.size()); + + for (int i = 0; i < 4; i++) { + assertEquals( + expectedResults[i], table.get(i).result(), "Mismatch at row " + i + " for " + expression); } - @Test - @DisplayName("Test NOT operator") - void testNotOperator() { - // Test simple NOT - verifyOperation("(not A)", - new boolean[]{true, true, false, false}); - - // Test NOT with AND - verifyOperation("(not (A and B))", - new boolean[]{true, true, true, false}); - - // Test nested NOT - verifyOperation("(not (not (A and B)))", - new boolean[]{false, false, false, true}); - } - - @Test - @DisplayName("Test complex expressions") - void testComplexExpressions() { - // Test expression with multiple operators - List table = - TruthP47.table("((A and B) or (not (A and B)))"); - - System.out.println("Truth table for ((A and B) or (not (A and B))):"); - System.out.println(TruthP47.formatTruthTable(table)); - - // This expression is a tautology (always true) - assertTrue(table.stream().allMatch(TruthP47.TruthTableRow::result)); - } - - @ParameterizedTest - @DisplayName("Test invalid expressions") - @ValueSource(strings = { - "", // Empty - "X", // Invalid variable - "()", // Empty parentheses - "(A and)", // Missing operand - "(and A B)", // Prefix notation (invalid) - "(A invalid B)", // Invalid operator - "(A and B C)", // Too many operands - "(A and (B))", // Malformed expression - "A and B" // Missing parentheses - }) - void testInvalidExpressions(String expression) { - assertThrows(IllegalArgumentException.class, - () -> TruthP47.table(expression)); - } - - @Test - @DisplayName("Test deeply nested expressions") - void testDeeplyNestedExpressions() { - String expression = "(A and (not (B or (not (A and B)))))"; - List table = TruthP47.table(expression); - - System.out.println("Truth table for " + expression + ":"); - System.out.println(TruthP47.formatTruthTable(table)); - - // Verify specific cases - assertFalse(table.get(0).result()); // F F -> F - assertFalse(table.get(1).result()); // F T -> F - assertFalse(table.get(2).result()); // T F -> F - assertFalse(table.get(3).result()); // T T -> T - } - - private void verifyOperation(String expression, boolean[] expectedResults) { - List table = TruthP47.table(expression); - assertEquals(4, table.size()); - - for (int i = 0; i < 4; i++) { - assertEquals(expectedResults[i], table.get(i).result(), - "Mismatch at row " + i + " for " + expression); - } - - System.out.println("Truth table for " + expression + ":"); - System.out.println(TruthP47.formatTruthTable(table)); - } + System.out.println("Truth table for " + expression + ":"); + System.out.println(TruthP47.formatTruthTable(table)); + } } diff --git a/src/test/java/org/nintynine/problems/TruthP48Test.java b/src/test/java/org/nintynine/problems/TruthP48Test.java index ca97a41..477eb9f 100644 --- a/src/test/java/org/nintynine/problems/TruthP48Test.java +++ b/src/test/java/org/nintynine/problems/TruthP48Test.java @@ -1,172 +1,173 @@ package org.nintynine.problems; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.*; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Arrays; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TruthP48Test { - private ByteArrayOutputStream outContent; - - @BeforeEach - void setUp() { - outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); - } - - @Test - void testBasicOperations() { - // Test AND - List vars = Arrays.asList("A", "B"); - TruthP48.table(vars, "A and B"); - String output = outContent.toString(); - assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\b.*")); - assertTrue(output.matches("(?s).*\\bfalse\\s+true\\s+false\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+false\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+true\\b.*")); - - // Clear output - outContent.reset(); - - // Test OR - TruthP48.table(vars, "A or B"); - output = outContent.toString(); - assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\b.*")); - assertTrue(output.matches("(?s).*\\bfalse\\s+true\\s+true\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+true\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+true\\b.*")); - } - - @Test - void testNotOperation() { - List vars = List.of("A"); - TruthP48.table(vars, "not A"); - String output = outContent.toString(); - assertTrue(output.matches("(?s).*false\\s+true.*")); // matches any number of spaces - assertTrue(output.matches("(?s).*true\\s+false.*")); - } - - @Test - void testEquivalence() { - List vars = Arrays.asList("A", "B"); - TruthP48.table(vars, "A equ B"); - String output = outContent.toString(); - assertTrue(output.matches("(?s).*false(?s).*false(?s).*true.*")); - assertTrue(output.matches("(?s).*false(?s).*true(?s).*false.*")); - assertTrue(output.matches("(?s).*true(?s).*false(?s).*false.*")); - assertTrue(output.matches("(?s).*true(?s).*true(?s).*true.*")); - } - - @Test - void testComplexExpression() { - List vars = Arrays.asList("A", "B", "C"); - TruthP48.table(vars, "(A and (B or C)) equ ((A and B) or (A and C))"); - String output = outContent.toString(); - // This is a tautology - each result line should end with "true" - assertTrue(output.matches("(?s).*\\n[^\\n]+\\s+true\\s*\\n.*")); // header and separator lines - assertFalse(output.matches("(?s).*\\n[^\\n]+\\s+false\\s*\\n.*")); // no lines should end with false - } - - @Test - void testThreeVariables() { - List vars = Arrays.asList("A", "B", "C"); - TruthP48.table(vars, "A and (B or C)"); - String output = outContent.toString(); - - // First verify the header format - assertTrue(output.matches("(?s)A\\s+B\\s+C\\s+Result.*")); - - // Verify the number of rows (should be 8 for 3 variables, plus header and separator) - assertEquals(10, output.trim().split("\n").length); - - // Check some specific combinations with proper spacing - assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\s+false\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+false\\s+true\\b.*")); - assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+true\\s+true\\b.*")); - - // Verify no consecutive variables are printed without space - assertFalse(output.contains("falsefalse")); - assertFalse(output.contains("truetrue")); - assertFalse(output.contains("falsetrue")); - assertFalse(output.contains("truefalse")); - } - - @Test - void testNestedExpressions() { - List vars = Arrays.asList("A", "B"); - TruthP48.table(vars, "not (A and (not B))"); - String output = outContent.toString(); - String[] lines = output.split("\n"); - // Skip header (first line) and separator (second line) - String actualOutput = String.join("\n", Arrays.copyOfRange(lines, 2, lines.length)); - - String expected = """ + private ByteArrayOutputStream outContent; + + @BeforeEach + void setUp() { + outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + } + + @Test + void testBasicOperations() { + // Test AND + List vars = Arrays.asList("A", "B"); + TruthP48.table(vars, "A and B"); + String output = outContent.toString(); + assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\b.*")); + assertTrue(output.matches("(?s).*\\bfalse\\s+true\\s+false\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+false\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+true\\b.*")); + + // Clear output + outContent.reset(); + + // Test OR + TruthP48.table(vars, "A or B"); + output = outContent.toString(); + assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\b.*")); + assertTrue(output.matches("(?s).*\\bfalse\\s+true\\s+true\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+true\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+true\\b.*")); + } + + @Test + void testNotOperation() { + List vars = List.of("A"); + TruthP48.table(vars, "not A"); + String output = outContent.toString(); + assertTrue(output.matches("(?s).*false\\s+true.*")); // matches any number of spaces + assertTrue(output.matches("(?s).*true\\s+false.*")); + } + + @Test + void testEquivalence() { + List vars = Arrays.asList("A", "B"); + TruthP48.table(vars, "A equ B"); + String output = outContent.toString(); + assertTrue(output.matches("(?s).*false(?s).*false(?s).*true.*")); + assertTrue(output.matches("(?s).*false(?s).*true(?s).*false.*")); + assertTrue(output.matches("(?s).*true(?s).*false(?s).*false.*")); + assertTrue(output.matches("(?s).*true(?s).*true(?s).*true.*")); + } + + @Test + void testComplexExpression() { + List vars = Arrays.asList("A", "B", "C"); + TruthP48.table(vars, "(A and (B or C)) equ ((A and B) or (A and C))"); + String output = outContent.toString(); + // This is a tautology - each result line should end with "true" + assertTrue(output.matches("(?s).*\\n[^\\n]+\\s+true\\s*\\n.*")); // header and separator lines + assertFalse( + output.matches("(?s).*\\n[^\\n]+\\s+false\\s*\\n.*")); // no lines should end with false + } + + @Test + void testThreeVariables() { + List vars = Arrays.asList("A", "B", "C"); + TruthP48.table(vars, "A and (B or C)"); + String output = outContent.toString(); + + // First verify the header format + assertTrue(output.matches("(?s)A\\s+B\\s+C\\s+Result.*")); + + // Verify the number of rows (should be 8 for 3 variables, plus header and separator) + assertEquals(10, output.trim().split("\n").length); + + // Check some specific combinations with proper spacing + assertTrue(output.matches("(?s).*\\bfalse\\s+false\\s+false\\s+false\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+true\\s+false\\s+true\\b.*")); + assertTrue(output.matches("(?s).*\\btrue\\s+false\\s+true\\s+true\\b.*")); + + // Verify no consecutive variables are printed without space + assertFalse(output.contains("falsefalse")); + assertFalse(output.contains("truetrue")); + assertFalse(output.contains("falsetrue")); + assertFalse(output.contains("truefalse")); + } + + @Test + void testNestedExpressions() { + List vars = Arrays.asList("A", "B"); + TruthP48.table(vars, "not (A and (not B))"); + String output = outContent.toString(); + String[] lines = output.split("\n"); + // Skip header (first line) and separator (second line) + String actualOutput = String.join("\n", Arrays.copyOfRange(lines, 2, lines.length)); + + String expected = + """ false false true true false false false true true true true true"""; - - assertEquals(expected.trim(), actualOutput.trim()); - } - - @Test - void testSingleVariable() { - List vars = List.of("A"); - TruthP48.table(vars, "A"); - String output = outContent.toString(); - String[] lines = output.trim().split("\n"); - assertTrue(lines.length >= 3); // Header, separator, and at least two value lines - assertTrue(output.matches("(?s).*A\\s+Result.*")); // Header - assertTrue(output.matches("(?s).*false\\s+false.*")); // First case - assertTrue(output.matches("(?s).*true\\s+true.*")); // Second case - } - - @Test - void testInvalidExpression() { - List vars = Arrays.asList("A", "B"); - assertThrows(IllegalArgumentException.class, () -> TruthP48.table(vars, "A invalid B")); - } - - @Test - void testMissingVariable() { - List vars = List.of("A"); - assertThrows(NullPointerException.class, () -> TruthP48.table(vars, "A and B")); - } - - @Test - void testHeaderFormat() { - List vars = Arrays.asList("A", "B"); - TruthP48.table(vars, "A and B"); - String output = outContent.toString(); - String[] lines = output.split("\n"); - - // Check header format - assertTrue(lines[0].contains("A")); - assertTrue(lines[0].contains("B")); - assertTrue(lines[0].contains("Result")); - - // Check the separator line - assertTrue(lines[1].matches("^-+$")); - } - @Test - void testDistributiveProperty() { - List vars = Arrays.asList("A", "B", "C"); - // Test distributive property: A and (B or C) = (A and B) or (A and C) - TruthP48.table(vars, "(A and (B or C)) equ ((A and B) or (A and C))"); - String output = outContent.toString(); - String[] lines = output.trim().split("\n"); - - // Skip header and separator lines - for (int i = 2; i < lines.length; i++) { - String[] columns = lines[i].trim().split("\\s+"); - String result = columns[columns.length - 1]; // Get last column - assertEquals("true", result, "Expected true for all results in truth table"); - } + assertEquals(expected.trim(), actualOutput.trim()); + } + + @Test + void testSingleVariable() { + List vars = List.of("A"); + TruthP48.table(vars, "A"); + String output = outContent.toString(); + String[] lines = output.trim().split("\n"); + assertTrue(lines.length >= 3); // Header, separator, and at least two value lines + assertTrue(output.matches("(?s).*A\\s+Result.*")); // Header + assertTrue(output.matches("(?s).*false\\s+false.*")); // First case + assertTrue(output.matches("(?s).*true\\s+true.*")); // Second case + } + + @Test + void testInvalidExpression() { + List vars = Arrays.asList("A", "B"); + assertThrows(IllegalArgumentException.class, () -> TruthP48.table(vars, "A invalid B")); + } + + @Test + void testMissingVariable() { + List vars = List.of("A"); + assertThrows(NullPointerException.class, () -> TruthP48.table(vars, "A and B")); + } + + @Test + void testHeaderFormat() { + List vars = Arrays.asList("A", "B"); + TruthP48.table(vars, "A and B"); + String output = outContent.toString(); + String[] lines = output.split("\n"); + + // Check header format + assertTrue(lines[0].contains("A")); + assertTrue(lines[0].contains("B")); + assertTrue(lines[0].contains("Result")); + + // Check the separator line + assertTrue(lines[1].matches("^-+$")); + } + + @Test + void testDistributiveProperty() { + List vars = Arrays.asList("A", "B", "C"); + // Test distributive property: A and (B or C) = (A and B) or (A and C) + TruthP48.table(vars, "(A and (B or C)) equ ((A and B) or (A and C))"); + String output = outContent.toString(); + String[] lines = output.trim().split("\n"); + + // Skip header and separator lines + for (int i = 2; i < lines.length; i++) { + String[] columns = lines[i].trim().split("\\s+"); + String result = columns[columns.length - 1]; // Get last column + assertEquals("true", result, "Expected true for all results in truth table"); } + } } diff --git a/src/test/java/org/nintynine/problems/TruthP55Test.java b/src/test/java/org/nintynine/problems/TruthP55Test.java index cc0ca0b..963251f 100644 --- a/src/test/java/org/nintynine/problems/TruthP55Test.java +++ b/src/test/java/org/nintynine/problems/TruthP55Test.java @@ -1,115 +1,115 @@ package org.nintynine.problems; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - class TruthP55Test { - @Test - @DisplayName("Test empty and single node trees") - void testBasicCases() { - // Test empty tree - List emptyTree = TruthP55.cbalTree(0); - assertTrue(emptyTree.isEmpty(), "Tree with 0 nodes should be empty"); - - // Test single node tree - List singleNode = TruthP55.cbalTree(1); - assertEquals(1, singleNode.size(), "Should be exactly one tree with 1 node"); - assertEquals("(X NIL NIL)", singleNode.getFirst().toString(), "Single node should have NIL children"); - } - - @Test - @DisplayName("Test two node trees") - void testTwoNodes() { - List twoNodes = TruthP55.cbalTree(2); - assertEquals(2, twoNodes.size(), "Should be exactly one tree with 2 nodes"); - assertEquals("(X (X NIL NIL) NIL)", twoNodes.getFirst().toString()); - } - - @Test - @DisplayName("Test three node trees") - void testThreeNodes() { - List threeNodes = TruthP55.cbalTree(3); - assertEquals(2, threeNodes.size(), "Should be exactly two trees with 3 nodes"); - assertTrue(threeNodes.stream().anyMatch(n -> n.toString().equals("(X (X NIL NIL) (X NIL NIL))"))); - } - - @Test - @DisplayName("Test four node trees") - void testFourNodes() { - List fourNodes = TruthP55.cbalTree(4); - assertEquals(4, fourNodes.size(), "Should be exactly four trees with 4 nodes"); - - // Check for expected patterns - assertTrue(fourNodes.stream().anyMatch(n -> - n.toString().equals("(X (X NIL NIL) (X NIL (X NIL NIL)))") || - n.toString().equals("(X (X NIL NIL) (X (X NIL NIL) NIL))") - )); + @Test + @DisplayName("Test empty and single node trees") + void testBasicCases() { + // Test empty tree + List emptyTree = TruthP55.cbalTree(0); + assertTrue(emptyTree.isEmpty(), "Tree with 0 nodes should be empty"); + + // Test single node tree + List singleNode = TruthP55.cbalTree(1); + assertEquals(1, singleNode.size(), "Should be exactly one tree with 1 node"); + assertEquals( + "(X NIL NIL)", singleNode.getFirst().toString(), "Single node should have NIL children"); + } + + @Test + @DisplayName("Test two node trees") + void testTwoNodes() { + List twoNodes = TruthP55.cbalTree(2); + assertEquals(2, twoNodes.size(), "Should be exactly one tree with 2 nodes"); + assertEquals("(X (X NIL NIL) NIL)", twoNodes.getFirst().toString()); + } + + @Test + @DisplayName("Test three node trees") + void testThreeNodes() { + List threeNodes = TruthP55.cbalTree(3); + assertEquals(2, threeNodes.size(), "Should be exactly two trees with 3 nodes"); + assertTrue( + threeNodes.stream().anyMatch(n -> n.toString().equals("(X (X NIL NIL) (X NIL NIL))"))); + } + + @Test + @DisplayName("Test four node trees") + void testFourNodes() { + List fourNodes = TruthP55.cbalTree(4); + assertEquals(4, fourNodes.size(), "Should be exactly four trees with 4 nodes"); + + // Check for expected patterns + assertTrue( + fourNodes.stream() + .anyMatch( + n -> + n.toString().equals("(X (X NIL NIL) (X NIL (X NIL NIL)))") + || n.toString().equals("(X (X NIL NIL) (X (X NIL NIL) NIL))"))); + } + + @ParameterizedTest + @DisplayName("Test node count in generated trees") + @ValueSource(ints = {1, 2, 3, 4, 5}) + void testNodeCount(int n) { + List trees = TruthP55.cbalTree(n); + for (TruthP55.Node tree : trees) { + assertEquals(n, countNodes(tree), "Each generated tree should have exactly " + n + " nodes"); } - - @ParameterizedTest - @DisplayName("Test node count in generated trees") - @ValueSource(ints = {1, 2, 3, 4, 5}) - void testNodeCount(int n) { - List trees = TruthP55.cbalTree(n); - for (TruthP55.Node tree : trees) { - assertEquals(n, countNodes(tree), - "Each generated tree should have exactly " + n + " nodes"); - } - } - - @Test - @DisplayName("Test balance property") - void testBalanceProperty() { - // Test for trees with 5 nodes - List trees = TruthP55.cbalTree(5); - for (TruthP55.Node tree : trees) { - assertTrue(isBalanced(tree), - "Tree should be completely balanced"); - } - } - - @Test - @DisplayName("Test node equality") - void testNodeEquality() { - TruthP55.Node node1 = new TruthP55.Node("X", null, null); - TruthP55.Node node2 = new TruthP55.Node("X", null, null); - TruthP55.Node node3 = new TruthP55.Node("X", - new TruthP55.Node("X", null, null), null); - - assertEquals(node1, node2, "Identical nodes should be equal"); - assertNotEquals(node1, node3, "Different nodes should not be equal"); - assertNotEquals(null, node1, "Node should not be equal to null"); - assertNotEquals("X", node1, "Node should not be equal to string"); - } - - // Helper method to count nodes in a tree - private int countNodes(TruthP55.Node root) { - if (root == null) return 0; - return 1 + countNodes(root.left) + countNodes(root.right); - } - - // Helper method to check if tree is balanced - private boolean isBalanced(TruthP55.Node root) { - if (root == null) return true; - - int leftHeight = getHeight(root.left); - int rightHeight = getHeight(root.right); - - return Math.abs(leftHeight - rightHeight) <= 1 - && isBalanced(root.left) - && isBalanced(root.right); - } - - // Helper method to get height of tree - private int getHeight(TruthP55.Node node) { - if (node == null) return 0; - return 1 + Math.max(getHeight(node.left), getHeight(node.right)); + } + + @Test + @DisplayName("Test balance property") + void testBalanceProperty() { + // Test for trees with 5 nodes + List trees = TruthP55.cbalTree(5); + for (TruthP55.Node tree : trees) { + assertTrue(isBalanced(tree), "Tree should be completely balanced"); } + } + + @Test + @DisplayName("Test node equality") + void testNodeEquality() { + TruthP55.Node node1 = new TruthP55.Node("X", null, null); + TruthP55.Node node2 = new TruthP55.Node("X", null, null); + TruthP55.Node node3 = new TruthP55.Node("X", new TruthP55.Node("X", null, null), null); + + assertEquals(node1, node2, "Identical nodes should be equal"); + assertNotEquals(node1, node3, "Different nodes should not be equal"); + assertNotEquals(null, node1, "Node should not be equal to null"); + assertNotEquals("X", node1, "Node should not be equal to string"); + } + + // Helper method to count nodes in a tree + private int countNodes(TruthP55.Node root) { + if (root == null) return 0; + return 1 + countNodes(root.left) + countNodes(root.right); + } + + // Helper method to check if tree is balanced + private boolean isBalanced(TruthP55.Node root) { + if (root == null) return true; + + int leftHeight = getHeight(root.left); + int rightHeight = getHeight(root.right); + + return Math.abs(leftHeight - rightHeight) <= 1 + && isBalanced(root.left) + && isBalanced(root.right); + } + + // Helper method to get height of tree + private int getHeight(TruthP55.Node node) { + if (node == null) return 0; + return 1 + Math.max(getHeight(node.left), getHeight(node.right)); + } } From ff403478d4578d7726e4446bf39d006875965dcf Mon Sep 17 00:00:00 2001 From: ganesh47 <22994026+ganesh47@users.noreply.github.com> Date: Sun, 15 Jun 2025 12:59:07 +0530 Subject: [PATCH 2/2] Add tests to improve coverage --- .../problems/AdditionalCoverageTest.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/test/java/org/nintynine/problems/AdditionalCoverageTest.java diff --git a/src/test/java/org/nintynine/problems/AdditionalCoverageTest.java b/src/test/java/org/nintynine/problems/AdditionalCoverageTest.java new file mode 100644 index 0000000..13738fb --- /dev/null +++ b/src/test/java/org/nintynine/problems/AdditionalCoverageTest.java @@ -0,0 +1,78 @@ +package org.nintynine.problems; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** Additional tests to improve coverage of small utility classes. */ +class AdditionalCoverageTest { + + @Test + @DisplayName("BTree54Node handles raw expression values") + void testBTree54NodeRawValue() { + String raw = "(a nil nil)"; + BTree54.BTree54Node node = new BTree54.BTree54Node(raw); + assertEquals(raw, node.toString()); + } + + @Test + @DisplayName("BTreeP58Node equality and toString") + void testBTreeP58NodeEquality() { + BTreeP58.BTreeP58Node left1 = new BTreeP58.BTreeP58Node('A'); + BTreeP58.BTreeP58Node right1 = new BTreeP58.BTreeP58Node('B'); + BTreeP58.BTreeP58Node root1 = new BTreeP58.BTreeP58Node('X'); + root1.left = left1; + root1.right = right1; + + BTreeP58.BTreeP58Node left2 = new BTreeP58.BTreeP58Node('A'); + BTreeP58.BTreeP58Node right2 = new BTreeP58.BTreeP58Node('B'); + BTreeP58.BTreeP58Node root2 = new BTreeP58.BTreeP58Node('X'); + root2.left = left2; + root2.right = right2; + + assertEquals(root1, root2); + assertEquals(root1.hashCode(), root2.hashCode()); + assertEquals("X(A,B)", root1.toString()); + } + + @Test + @DisplayName("BTreeP59Node equality and toString") + void testBTreeP59NodeEquality() { + BTreeP59.BTree59Node left1 = new BTreeP59.BTree59Node('L'); + BTreeP59.BTree59Node right1 = new BTreeP59.BTree59Node('R'); + BTreeP59.BTree59Node root1 = new BTreeP59.BTree59Node('X'); + root1.left = left1; + root1.right = right1; + + BTreeP59.BTree59Node left2 = new BTreeP59.BTree59Node('L'); + BTreeP59.BTree59Node right2 = new BTreeP59.BTree59Node('R'); + BTreeP59.BTree59Node root2 = new BTreeP59.BTree59Node('X'); + root2.left = left2; + root2.right = right2; + + assertEquals(root1, root2); + assertEquals(root1.hashCode(), root2.hashCode()); + assertEquals("X(L,R)", root1.toString()); + } + + @Test + @DisplayName("Pair toString includes both lists") + void testPairToString() { + MyListP17 list1 = new MyListP17<>("a", "b"); + MyListP17 list2 = new MyListP17<>("c"); + MyListP17.Pair, MyListP17> pair = new MyListP17.Pair<>(list1, list2); + assertEquals("(" + list1 + ", " + list2 + ")", pair.toString()); + } + + @Test + @DisplayName("PrimeTotientResult toString formats correctly") + void testPrimeTotientResultToString() { + MathP34.PrimeTotientResult res1 = new MathP34.PrimeTotientResult(true, 9); + assertEquals("Number is prime, \u03c6(m) = 9", res1.toString()); + + MathP34.PrimeTotientResult res2 = new MathP34.PrimeTotientResult(false, 8); + assertEquals("Number is not prime, \u03c6(m) = 8", res2.toString()); + } +}