diff --git a/README.md b/README.md index 8b780b5..94495ba 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Countroll - Description -Countroll is designed to make using counting bots a bit more interesting. It turns integers into complex, unreadable +Countroll is designed to make using counting bots a bit more interesting. It turns integers into complex, unreadable mathematical expressions, perfect for showing off your mathematical knowledge to you friends! Countroll uses the following operators to make your integer as complex as possible @@ -14,7 +14,9 @@ Countroll uses the following operators to make your integer as complex as possib ## Compatibility -Countroll is currently only compatible with [Numselli's counting bot](https://counting.numselli.xyz/), although I hope to be able to support more counting bots soon! +Countroll is currently compatible with the following bots, please open an issue if you find another bot that is compatible or one that isn't compatible! +- [Numselli's counting bot](https://counting.numselli.xyz/) +- [DuckGroup's Counting bot](https://countingbot.com/) ## Usage @@ -34,6 +36,15 @@ There are multiple command line arguments you can use for ease of use | --color | -rgb | Enables colored output for debug/it looks cool | | --deep | -d | Will run the Complexers on the Increaser values | | --help | --h, -h | Shows a message like this table | +| --mode | -m | Changes the mode of the bot | + +## Modes: +You can change the bot's mode with the --mode option +- `--mode=numselli` or `-m=n` Uses Square Root +- `--mode=duckgroup` or `-m=d` Does not use Square Root +- `--mode=TEST` or `-m=t` testing mode (evaluates a given expression) + +DuckGroup does not support square roots, which is why they are seperate # Compiling Make sure you have Java 17 or higher installed on your system! @@ -42,3 +53,7 @@ Make sure you have Java 17 or higher installed on your system! 3. Build with gradle `$ ./gradlew build` 4. Build will be output to `/Countroll/build/libs` +# Up Next +Development will continue with the addition of bitwise operations AND (&) and OR (|) +- Both bots support these operators, and it will be in both modes + diff --git a/build.gradle b/build.gradle index 3b80127..33dd302 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { } group 'me.trouper' -version '0.0.2' +version '0.0.3' repositories { mavenCentral() diff --git a/src/main/java/me/trouper/Functions/Complexers.java b/src/main/java/me/trouper/Functions/Complexers.java index 1d573e1..3489b17 100644 --- a/src/main/java/me/trouper/Functions/Complexers.java +++ b/src/main/java/me/trouper/Functions/Complexers.java @@ -1,29 +1,119 @@ package me.trouper.Functions; +import me.trouper.Main; +import me.trouper.Utils.Utils; + import java.util.Random; import static me.trouper.Functions.Eval.eval; +import static me.trouper.Functions.Eval.isPerfectSquare; public class Complexers { - public static String divide(int i) { + + /** + * Safe to use with D mode + * @param i Integer to divide + * @return Colored String + */ + public static String divide(int i, boolean deep) { + Main.divideCount++; Random random = new Random(); + int factor = random.nextInt(9)+1; int doubled = i * factor; + boolean expFac = false; + boolean expDoub = false; + + if (isPerfectSquare(factor)) expFac = true; + if (isPerfectSquare(doubled)) expDoub = true; + String result = "<&f>(<&r><&e>" + doubled + "<&b>/<&r><&e>" + factor + "<&f>)<&r>"; - if (eval(result) == i) { - return result; + if (deep) { + result = "<&3>(<&r><&d>" + ((expDoub) ? power(doubled,false) : divide(doubled,false)) + "<&b>/<&r><&d>" + ((expFac) ? power(factor,false) : divide(factor,false)) + "<&3>)<&r>"; } - return "(" + i + ")"; + if (eval(result) != i) Utils.verbose("Failed to divide " + i + ", Attempted: " + result + "=" + eval(result)); + return eval(result) == i ? result : "(" + i + ")"; } - public static String root(int i) { + /** + * Safe to use with D mode + * Only to be used with perfect squares + * @param i Integer to root+square + * @return Colored String + */ + public static String power(int i, boolean deep) { + Main.powerCount++; + if (!Eval.isPerfectSquare(i)) { + return "(" + i + ")"; + } + + int root = (int) Math.sqrt(i); + String result = "<&r><&f>(<&e>" + root + "<&b>^<&e>2<&f>)<&r>"; + + if (deep) { + result = "<&r><&3>(<&d>" + divide(root,false) + "<&b>^<&d>2<&3>)<&r>"; + } + if (eval(result) != i) Utils.verbose("<&ch>Failed to power <&r>" + i + ", Attempted: " + result + "=" + eval(result)); + return eval(result) == i ? result : "(" + i + ")"; + } + + /** + * Uses sqrt(), not safe with D mode + * @param i integer to square+root + * @return Colored String + */ + public static String root(int i, boolean deep) { + Main.rootCount++; int squared = (int) Math.pow(i,2); String result = "<&9>sqrt<&r><&f>(<&r><&e>" + squared + "<&f>)<&r>"; - if (eval(result) == i){ - return result; + if (deep) { + result = "<&1>sqrt<&r><&3>(<&r><&d>" + divide(squared,false) + "<&3>)<&r>"; } - return "(" + i + ")"; + if (eval(result) != i) Utils.verbose("<&ch>Failed to root <&r>" + i + ", Attempted: " + result + "=" + eval(result)); + return (eval(result) == i) ? result : "(" + i + ")"; + } + + /** + * Uses modulus (ri%divisor)=i + * @param i Modulus to return + * @return Colored string + */ + public static String mRootDivisor(int i, boolean deep) { + Main.rDivisorCount++; + Random random = new Random(); + int dividend = random.nextInt(9)+i+10; + int divisor = Utils.moduRootDivisor(dividend,i); + String result = "<&r><&f>(<&e>" + dividend + "<&b>%<&e>" + divisor + "<&f>)<&r>"; + Utils.verbose("<&dh><&b>mRootDivisor has been ran!<&r>" + + "\nWanted: " + i + + "\nDivisor: " + divisor + + "\nDividend: " + dividend + + "\nCheck: " + dividend + "%" + divisor + "=" + i + + "\nResult: " + result); + if (eval(result) != i) Utils.verbose("<&ch>Failed to mRootDivisor<&r> " + i + ", Attempted: " + result + "=" + eval(result)); + return (eval(result) == i) ? result : "(" + i + ")"; + } + + /** + * Uses modulus (dividend%ri)=i + * @param i Modulus to return + * @return Colored String + */ + public static String mRootDividend(int i, boolean deep) { + Main.rDividendCount++; + Random random = new Random(); + int divisor = random.nextInt(9)+i+10; + int dividend = Utils.moduRootDividend(divisor,i); + String result = "<&r><&f>(<&e>" + dividend + "<&b>%<&e>" + divisor + "<&f>)<&r>"; + Utils.verbose("<&dh><&b>mRootDividend has been ran!<&r>" + + "\nWanted:" + i + + "\nDivisor: " + divisor + + "\nDividend: " + dividend + + "\nCheck: " + dividend + "%" + divisor + "=" + i + + "\nResult: " + result); + if (eval(result) != i) Utils.verbose("<&ch>Failed to mRootDividend<&r> " + i + ", Attempted: " + result + "=" + eval(result)); + return (eval(result) == i) ? result : "(" + i + ")"; } } diff --git a/src/main/java/me/trouper/Functions/Increasers.java b/src/main/java/me/trouper/Functions/Increasers.java index bf1dfb8..9d93f5d 100644 --- a/src/main/java/me/trouper/Functions/Increasers.java +++ b/src/main/java/me/trouper/Functions/Increasers.java @@ -1,22 +1,29 @@ package me.trouper.Functions; import static me.trouper.Functions.Eval.eval; +import static me.trouper.Functions.Eval.isPerfectSquare; public class Increasers { - public static String multiply(int i, int factor) { + public static String multiply(int i, int factor, boolean deep) { + boolean useExp = isPerfectSquare(i); + String result = "<&7>(<&r><&2>" + i + "<&b>*<&r><&2>" + factor + "<&7>)<&r>"; - if (eval(result) == i * factor) { - return result; + if (deep) { + result = "<&7>(<&r><&2>" + (useExp ? Complexers.power(i,true) : Complexers.divide(i,true)) + "<&b>*<&r><&2>" + factor + "<&7>)<&r>"; } - return "(" + i + ")"; + + return eval(result) == i * factor ? result : "(" + i + ")"; } - public static String power(int i, int exp) { + public static String power(int i, int exp, boolean deep) { + boolean useExp = isPerfectSquare(i); + String result = "<&7>(<&r><&2>" + i + "<&b>^<&r><&2>" + exp + "<&7>)<&r>"; - if (eval(result) == Math.pow(i,exp)) { - return result; + if (deep) { + result = "<&7>(<&r><&2>" + (useExp ? Complexers.power(i,true) : Complexers.divide(i,true)) + "<&b>^<&r><&2>" + exp + "<&7>)<&r>"; } - return "(" + i + ")"; + + return eval(result) == Math.pow(i,exp) ? result : "(" + i + ")"; } } diff --git a/src/main/java/me/trouper/Functions/Obf.java b/src/main/java/me/trouper/Functions/Obf.java index 7e929c6..ff24ef4 100644 --- a/src/main/java/me/trouper/Functions/Obf.java +++ b/src/main/java/me/trouper/Functions/Obf.java @@ -1,5 +1,7 @@ package me.trouper.Functions; +import me.trouper.Main; + import java.util.Random; import static me.trouper.Functions.Eval.*; @@ -8,7 +10,13 @@ import static me.trouper.Utils.Utils.removeColors; import static me.trouper.Utils.Utils.verbose; public class Obf { - public static String obfInt(int target, boolean deep) { + /** + * ObfIntN will work for Numselli's counting bot + * @param target Integer to reach + * @param deep When True, doubles the use of Complexers and Increasers + * @return A colored string + */ + public static String obfIntN(int target, boolean deep) { if (deep) System.out.println("Deep Obfuscation is coming soon!"); StringBuilder expression = new StringBuilder(); @@ -18,17 +26,9 @@ public class Obf { verbose("Initializing Expression: " + initializer); expression.append("<&dh><&f>").append(initializer).append("<&r>"); - int cubeCount = 0; - int factorCount = 0; - int addCount = 0; - int subCount = 0; - int rootCount = 0; - int divideCount = 0; - int perfectCount = 0; - int total = 0; while (eval(expression.toString()) != target) { - total++; + Main.total++; int eval = (int) eval(expression.toString()); int ri = random.nextInt(9)+1; int op = random.nextInt(2); @@ -47,77 +47,128 @@ public class Obf { verbose("Current: " + eval(expression.toString())); if (isPerfectSquare(eval) && eval != 1) { - perfectCount++; - verbose("PERFECT SQUARE TIME! (" + perfectCount+ ")"); + Main.perfectCount++; + verbose("PERFECT SQUARE TIME! (" + Main.perfectCount+ ")"); expression.insert(0,"<&eh><&b>sqrt(<&r>").append("<&eh><&b>)<&r>"); eval = (int) eval(expression.toString()); } - if (target - eval > 4069) { - mult = true; - cubeCount++; - verbose("Large than (" + cubeCount + ")"); - final String toAdd = Increasers.power(ri,3); - expression.append("<&b>+<&r><&a>").append(toAdd).append("<&r>"); - } else if (target - eval > 1048) { - mult = true; - cubeCount++; - verbose("Large than (" + cubeCount + ")"); - final String toAdd = Increasers.power(ri,2); - expression.append("<&b>+<&r><&a>").append(toAdd).append("<&r>"); - } else if (target - eval > 128) { - factorCount++; - verbose("Big than (" + factorCount + ")"); - final String toAdd = Increasers.multiply(ri,9); - expression.append("<&b>+<&r><&a>").append(toAdd).append("<&r>"); - continue; - } + + final String toAdd = complex(ri,deep,"n"); if (eval < target) { - addCount++; - if (op == 0) { - divideCount++; - } else { - rootCount++; + if (target - eval > 4069) { + Main.expCount++; + verbose("Large than (" + Main.expCount + ")"); + expression.append("<&b>*<&r><&a>").append(Increasers.power(ri,3,deep)).append("<&r>"); + } else if (target - eval > 1048) { + Main.expCount++; + verbose("Large than (" + Main.expCount + ")"); + expression.append("<&b>*<&r><&a>").append(Increasers.power(ri,2,deep)).append("<&r>"); + } else if (target - eval > 128) { + Main.factorCount++; + verbose("Big than (" + Main.factorCount + ")"); + expression.append("<&b>*<&r><&a>").append(Increasers.multiply(ri,9,deep)).append("<&r>"); } - - final String toAdd = (op == 0) ? Complexers.divide(ri) : Complexers.root(ri); - - expression.append((mult) ? "<&b>*<&r>" : "<&b>+<&r><&e>").append(toAdd).append("<&r>"); - verbose("Less than (" + addCount + ")"); + Main.addCount++; + expression.append("<&b>+<&r><&e>").append(toAdd).append("<&r>"); + verbose("Less than (" + Main.addCount + ")"); } if (eval > target) { - subCount++; - if (op == 0) { - divideCount++; - } else { - rootCount++; - } - - final String toAdd = (op == 0) ? Complexers.divide(ri) : Complexers.root(ri); - /* - String colored = Utils.highlightReg(toAdd); - if (deep) { - colored = Utils.highlightDeep(toAdd); - }*/ + Main.subCount++; expression.insert(0,"<&c>(<&r>").append("<&c>)<&r>"); expression.append("<&b>-<&r><&e>").append(toAdd).append("<&r>"); - verbose("Greater than (" + subCount + ")"); + verbose("Greater than (" + Main.subCount + ")"); } } verbose("Broke out of loop. Value: " + eval(expression.toString())); verbose("Expression: " + expression); verbose("Expression (Cleaned): " + removeColors(expression.toString())); - System.out.println("\n\n\n\nStatistics: " + - "\nCubes: " + cubeCount + - "\nFactors: " + factorCount + - "\nAdditions: " + addCount + - "\nSubtractions: " + subCount + - "\nRoots Taken: " + rootCount + - "\nDivisors: " + divideCount + - "\nPerfect Squares Found: " + perfectCount + - "\nTotal steps taken: " + total); return expression.toString(); } + + /** + * ObfIntD will work with DuckGroups's Counting bot + * @param target Integer to reach + * @param deep When True, doubles the use of Complexers and Increasers + * @return A colored string + */ + public static String obfIntD(int target, boolean deep) { + if (deep) System.out.println("Deep Obfuscation is coming soon!"); + StringBuilder expression = new StringBuilder(); + + Random random = new Random(); + + int initializer = random.nextInt(9)+1; + verbose("Initializing Expression: " + initializer); + expression.append("<&dh><&f>").append(initializer).append("<&r>"); + + while (eval(expression.toString()) != target) { + Main.total++; + int eval = (int) eval(expression.toString()); + int ri = random.nextInt(9)+1; + + + final String toAdd = complex(ri,deep,"d"); + + if (eval < target) { + if (target - eval > 4096) { + Main.expCount++; + expression.append("<&b>*<&r>").append(Increasers.power(ri,4,deep)); + } else if (target - eval > 1048) { + Main.expCount++; + expression.append("<&b>*<&r>").append(Increasers.power(ri,2,deep)); + } else if (target - eval > 128) { + Main.factorCount++; + expression.append("<&b>*<&r>").append(Increasers.multiply(ri,2,deep)); + } + Main.addCount++; + expression.append("<&b>+<&r>").append(toAdd); + } + if (eval > target) { + if (eval - target > 4096) { + Main.expCount++; + expression.append("<&b>-<&r>").append(Increasers.power(ri,5,deep)); + } else if (eval - target> 1048) { + Main.expCount++; + expression.append("<&b>-<&r>").append(Increasers.power(ri,3,deep)); + } else if (eval - target > 128) { + Main.factorCount++; + expression.append("<&b>-<&r>").append(Increasers.multiply(ri,2,deep)); + } + Main.subCount++; + expression.insert(0,"<&c>(<&r>").append("<&c>)<&r>"); + expression.append("<&b>-<&r>").append(toAdd); + } + } + return expression.toString(); + } + public static String increase(int target, int current, boolean deep, String mode) { + return target + "" + current; + } + public static String complex(int target, boolean deep, String mode) { + Random random = new Random(); + String toAdd = "(" + target + ")"; + int rComplexer; + switch (mode) { + case "n" -> rComplexer = random.nextInt(4)+1; + case "d" -> rComplexer = random.nextInt(3)+1; + default -> rComplexer = 1; + } + if (target == 1) { + toAdd = Complexers.power(target,deep); + } else if (isPerfectSquare(target)) { + toAdd = Complexers.power(target,deep); + } else { + switch (rComplexer) { + case 1 -> toAdd = Complexers.divide(target,deep); + case 2 -> toAdd = Complexers.mRootDivisor(target,deep); + case 3 -> toAdd = Complexers.mRootDividend(target,deep); + case 4 -> toAdd = Complexers.root(target,deep); // Won't reach this one, if its "d" due to it stopping at 3 + } + } + + return (eval(toAdd) == target) ? toAdd : "(" + target + ")"; + } } diff --git a/src/main/java/me/trouper/Main.java b/src/main/java/me/trouper/Main.java index ae5d42c..efa2928 100644 --- a/src/main/java/me/trouper/Main.java +++ b/src/main/java/me/trouper/Main.java @@ -14,9 +14,35 @@ public class Main { public static boolean deep; public static boolean color; public static boolean printHelp; + /* Statistics */ + public static int expCount = 0; + public static int factorCount = 0; + public static int addCount = 0; + public static int subCount = 0; + public static int divideCount = 0; + public static int powerCount = 0; + public static int rDivisorCount = 0; + public static int rDividendCount = 0; + public static int rootCount = 0; + public static int perfectCount = 0; + public static int total = 0; + public static void clearStats() { + expCount = 0; + factorCount = 0; + addCount = 0; + subCount = 0; + divideCount = 0; + powerCount = 0; + rDivisorCount = 0; + rDividendCount = 0; + rootCount = 0; + perfectCount = 0; + total = 0; + } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); boolean doCopy = false; + String mode = "N"; for (String arg : args) { @@ -26,6 +52,27 @@ public class Main { case "--deep", "-d" -> deep = true; case "--color", "-rgb" -> color = true; case "--help", "--h", "-h" -> printHelp = true; + case "--mode=numselli", "-m=n" -> mode = "N"; + case "--mode=duckgroup", "-m=d" -> mode = "D"; + case "--mode=TEST", "-m=t" -> mode = "TEST"; + } + } + + if (mode.equals("TEST")) { + while (true) { + System.out.print("Enter an expression (or 'exit' to exit): "); + String userInput = scanner.next(); + + if (userInput.equals("exit")) { + System.exit(0); + } + + try { + double result = eval(userInput); + System.out.println("Result: " + result); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + } } } @@ -37,17 +84,33 @@ public class Main { if (scanner.hasNextInt()) { int target = scanner.nextInt(); Timer obfTimer = Timer.start(); - String expression = Obf.obfInt(target, deep); + String expression = null; + switch (mode) { + case "N" -> expression = Obf.obfIntN(target, deep); + case "D" -> expression = Obf.obfIntD(target, deep); + } long obfTime = obfTimer.end().timePassed(); double output = eval(removeColors(expression)); - System.out.println("\nTarget Integer: " + target); + System.out.println("\nStatistics" + + "\nExponents: " + expCount + + "\nFactors: " + factorCount + + "\nAdditions: " + addCount + + "\nSubtractions: " + subCount + + "\nDivisors: " + divideCount + + "\nPowers: " + powerCount + + "\nmRootDividends: " + rDividendCount + + "\nmRootDivisors: " + rDivisorCount + + "\nRoots Taken: " + rootCount + + "\nPerfect Squares Found: " + perfectCount + + "\nTotal steps taken: " + total); System.out.println("\nElapsed Time: " + obfTime + "ms"); - + System.out.println("\nTarget Integer: " + target); if (output == target) { System.out.println(Utils.activateColors("<&2h><&f>Expression Correct<&r>\n\n" + ((color) ? expression : removeColors(expression)))); if (doCopy) Utils.copyToClip(removeColors(expression)); + clearStats(); } else { System.out.println(Utils.activateColors("<&ch><&0>!!!! INCORRECT !!!!<&r>\n\n" + ((color) ? expression : removeColors(expression)))); } @@ -59,4 +122,5 @@ public class Main { scanner.close(); } + } diff --git a/src/main/java/me/trouper/Utils/Utils.java b/src/main/java/me/trouper/Utils/Utils.java index e1e7745..b0dc8f3 100644 --- a/src/main/java/me/trouper/Utils/Utils.java +++ b/src/main/java/me/trouper/Utils/Utils.java @@ -15,7 +15,7 @@ public class Utils { clipboard.setContents(parsed,null); } public static void verbose(String text) { - if (Main.verbose) System.out.println(text); + if (Main.verbose) System.out.println(activateColors(text)); } public static String removeColors(String input) { return input.replaceAll("<&[0-9a-fr]>|<&[0-9a-frh]h>", ""); @@ -58,49 +58,37 @@ public class Utils { "\n<&e>Yellow:<&r> Complexer"; System.out.println(activateColors(colorKey)); } - /* - public static String highlightReg(String exp) { - final String result = exp - .replaceAll("\\(", ANSI.WHITE + "(" + ANSI.RESET) - .replaceAll("\\)", ANSI.WHITE + ")" + ANSI.RESET) - .replaceAll("\\*", ANSI.BLUE + "*" + ANSI.RESET) - .replaceAll("/", ANSI.BLUE + "/" + ANSI.RESET) - .replaceAll("\\+", ANSI.BLUE + "+" + ANSI.RESET) - .replaceAll("-", ANSI.BLUE + "-" + ANSI.RESET) - .replaceAll("\\^", ANSI.BLUE + "^" + ANSI.RESET) - .replaceAll("\\d+", ANSI.GREEN + "$0" + ANSI.RESET); - verbose("Attempting Ansi Highlight: " + result); - return result; + + /** + * Returns the divisor of a mod equation given the modulus and dividend + * 5%x=2 -> x=3 + * @param modulus Remainder + * @param dividend The number that is getting divided + * @return The divisor + */ + public static int moduRootDivisor(int dividend, int modulus) { + int divisor = dividend - modulus; + verbose("<&1h><&e>Finding mrDivisor:<&r> " + + "\nDividend (Given): " + dividend + + "\nDivisor (Unknown): " + divisor + + "\nModulus (Given): " + modulus); + return divisor; } - public static String highlightDeep(String exp) { - final String result = exp - .replaceAll("\\(", ANSI.CYAN + "*" + ANSI.RESET) - .replaceAll("\\)", ANSI.CYAN + "*" + ANSI.RESET) - .replaceAll("\\*", ANSI.BLUE + "*" + ANSI.RESET) - .replaceAll("/", ANSI.BLUE + "/" + ANSI.RESET) - .replaceAll("\\+", ANSI.BLUE + "+" + ANSI.RESET) - .replaceAll("-", ANSI.BLUE + "-" + ANSI.RESET) - .replaceAll("\\^", ANSI.BLUE + "^" + ANSI.RESET) - .replaceAll("\\d+", ANSI.PURPLE + "$0" + ANSI.RESET); - verbose("Attempting Ansi Highlight (Deep): " + result); - return result; + /** + * Returns the dividend of a mod equation given the modulus and divisor + * x%3=2 -> x=5 + * @param modulus Remainder + * @param divisor The number that does the dividing + * @return The dividend + */ + public static int moduRootDividend(int divisor, int modulus) { + int dividend = modulus + divisor; + verbose("<&1h><&e>Finding mrDivisor:<&r> " + + "\nDividend (Unknown): " + dividend + + "\nDivisor (Given): " + divisor + + "\nModulus (Given): " + modulus); + return dividend; } - public static String fixAnsi(String input) { - Pattern pattern = Pattern.compile("(\\[\\d+m)"); - Matcher matcher = pattern.matcher(input); - StringBuffer sb = new StringBuffer(); - while (matcher.find()) { - // Check if the escape code was not properly closed (e.g., missing reset code) - if (input.substring(matcher.start()).indexOf(ANSI.RESET) < 0) { - String escapeCode = matcher.group(1); - // Re-escape the ANSI escape code - matcher.appendReplacement(sb, escapeCode); - } - } - matcher.appendTail(sb); - - return sb.toString(); - }*/ }