diff options
author | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-05-14 10:08:16 +0300 |
---|---|---|
committer | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-05-23 13:31:48 +0300 |
commit | 5ea7ccf01559a12f79bb06f4cf8f762895620038 (patch) | |
tree | f5e769e08414fcaf18253f6556f8592d23eb6faf /src/main | |
parent | 87c382b7ea32467d99f919ed8bdcbd2e7355e437 (diff) | |
download | Skyblocker-5ea7ccf01559a12f79bb06f4cf8f762895620038.tar.gz Skyblocker-5ea7ccf01559a12f79bb06f4cf8f762895620038.tar.bz2 Skyblocker-5ea7ccf01559a12f79bb06f4cf8f762895620038.zip |
Refactor code, fix coach calculation and attempt to highlight the best affordable pick
I tried to make the best pick still have yellow highlight while keeping the best affordable pick green but it's not working for some reason and I have no idea what's causing it'.
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 120 |
1 files changed, 61 insertions, 59 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java index 5c809a98..ed4d0f5e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -5,23 +5,25 @@ import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; import it.unimi.dsi.fastutil.ints.*; -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; +import org.apache.commons.math3.analysis.function.Min; import java.util.*; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern CPS_PATTERN = Pattern.compile("([\\d,.]+) Chocolate per second"); private static final Pattern CPS_INCREASE_PATTERN = Pattern.compile("\\+([\\d,]+) Chocolate per second"); private static final Pattern COST_PATTERN = Pattern.compile("Cost ([\\d,]+) Chocolate"); - private static final Pattern HIRE_PATTERN = Pattern.compile("(HIRE|PROMOTE) ➜ \\[\\d+] \\S+ *"); private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); + private static final Pattern TOTAL_CHOCOLATE_PATTERN = Pattern.compile("([\\d,]+) Chocolate"); public ChocolateFactorySolver() { super("^Chocolate Factory$"); @@ -33,31 +35,36 @@ public class ChocolateFactorySolver extends ContainerSolver { } @Override - protected void start(GenericContainerScreen screen) { - markHighlightsDirty(); //Recalculate highlights when the screen is opened, which happens when upgrading rabbits - } - - @Override protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { - final Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(6); //There are only 5 rabbits on the screen + 1 for the coach + final Int2ObjectMap<Rabbit> cpsIncreaseFactors = new Int2ObjectLinkedOpenHashMap<>(6); for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. ItemStack item = slots.get(i); if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; - String lore = getConcattedLore(item); - if (lore.isBlank()) continue; - - OptionalDouble cpsIncreaseFactor = getRabbitCPSIncreaseFactor(lore); // The 5 usual rabbits - if (cpsIncreaseFactor.isEmpty()) continue; //Something went wrong, skip this item - cpsIncreaseFactors.put(i, cpsIncreaseFactor.getAsDouble()); + int finalI = i; //Java, pfft. + getRabbit(item).ifPresent(rabbit -> cpsIncreaseFactors.put(finalI, rabbit)); } - OptionalDouble coachCpsIncreaseFactor = getCoachCPSIncreaseFactor(slots.get(45), slots.get(42)); // The coach - if (!coachCpsIncreaseFactor.isEmpty()) cpsIncreaseFactors.put(42, coachCpsIncreaseFactor.getAsDouble()); + //Coach is in slot 42 while the factory info item is in slot 45. + getCoach(slots.get(45), slots.get(42)).ifPresent(coach -> cpsIncreaseFactors.put(42, coach)); + if (cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong. + + OptionalLong totalChocolate = getTotalChocolate(slots.get(13)); - Optional<Int2DoubleMap.Entry> bestSlot = cpsIncreaseFactors.int2DoubleEntrySet().stream().max(Map.Entry.comparingByValue()); - if (bestSlot.isEmpty()) return List.of(); //No valid slots found, somehow. This means something went wrong, despite all the checks thus far. - return List.of(ColorHighlight.green(bestSlot.get().getIntKey())); + List<Int2ObjectMap.Entry<Rabbit>> sorted = cpsIncreaseFactors.int2ObjectEntrySet() + .stream() //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. + .sorted(Comparator.comparingDouble(entry -> entry.getValue().cost() / entry.getValue().cpsIncrease())) //Ascending order, lower = better + .dropWhile(entry -> entry.getValue().cost == 0) + .collect(Collectors.toCollection(LinkedList::new)); + + Int2ObjectMap.Entry<Rabbit> bestEntry = sorted.removeFirst(); + if (totalChocolate.isEmpty() || bestEntry.getValue().cost < totalChocolate.getAsLong()) return List.of(ColorHighlight.green(bestEntry.getIntKey())); + + for (Int2ObjectMap.Entry<Rabbit> entry : sorted) { + if (entry.getValue().cost > totalChocolate.getAsLong()) continue; + return List.of(ColorHighlight.green(entry.getIntKey()), ColorHighlight.yellow(bestEntry.getIntKey())); + } + return List.of(ColorHighlight.green(bestEntry.getIntKey())); } /** @@ -80,67 +87,59 @@ public class ChocolateFactorySolver extends ContainerSolver { return stringBuilder.toString(); } - private OptionalDouble getCoachCPSIncreaseFactor(ItemStack cpsItem, ItemStack coachItem) { + private Optional<Rabbit> getCoach(ItemStack cpsItem, ItemStack coachItem) { + if (coachItem.isEmpty() || cpsItem.isEmpty() || coachItem.getItem() != Items.PLAYER_HEAD || cpsItem.getItem() != Items.COCOA_BEANS) return Optional.empty(); String cpsItemLore = getConcattedLore(cpsItem); Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); OptionalDouble currentCps = getDoubleFromMatcher(cpsMatcher); - if (currentCps.isEmpty()) return OptionalDouble.empty(); + if (currentCps.isEmpty()) return Optional.empty(); Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); OptionalDouble totalMultiplier = getDoubleFromMatcher(multiplierMatcher, cpsMatcher.end()); - if (totalMultiplier.isEmpty()) return OptionalDouble.empty(); + if (totalMultiplier.isEmpty()) return Optional.empty(); String coachLore = getConcattedLore(coachItem); Matcher multiplierIncreaseMatcher = MULTIPLIER_INCREASE_PATTERN.matcher(coachLore); OptionalDouble currentCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); - if (currentCpsMultiplier.isEmpty()) return OptionalDouble.empty(); + if (currentCpsMultiplier.isEmpty()) return Optional.empty(); + OptionalDouble nextCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); if (nextCpsMultiplier.isEmpty()) { //This means that the coach isn't hired yet. nextCpsMultiplier = currentCpsMultiplier; //So the first instance of the multiplier is actually the amount we'll get upon upgrading. currentCpsMultiplier = OptionalDouble.of(0.0); //And so, we can re-assign values to the variables to make the calculation more readable. } - return OptionalDouble.of((currentCps.getAsDouble()/totalMultiplier.getAsDouble()) * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble())); + Matcher costMatcher = COST_PATTERN.matcher(coachLore); + OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.end()); //Cost comes after the multiplier line + if (cost.isEmpty()) return Optional.empty(); + + return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt())); } - /** - * The "CPS increase factor" here is the increase in CPS per chocolate spent. - * The highest value among the choices is the best one to pick. - * - * @param lore The lore of the item - * @return The CPS increase factor of the item, or an empty optional if it couldn't be found - */ - private OptionalDouble getRabbitCPSIncreaseFactor(String lore) { - Matcher hireMatcher = HIRE_PATTERN.matcher(lore); - if (!hireMatcher.find()) return OptionalDouble.empty(); //Not a hireable/promotable rabbit. Could be a locked or maxed rabbit. - - switch (hireMatcher.group(1)) { - case "HIRE" -> { - Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); - OptionalInt cps = getIntFromMatcher(cpsMatcher, hireMatcher.end()); //Cps line is right after the hire line - if (cps.isEmpty()) return OptionalDouble.empty(); - - Matcher costMatcher = COST_PATTERN.matcher(lore); - OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line - if (cost.isEmpty()) return OptionalDouble.empty(); - return OptionalDouble.of(cps.getAsInt() / (double) cost.getAsInt()); - } - case "PROMOTE" -> { - Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); - OptionalInt currentCps = getIntFromMatcher(cpsMatcher); //Current cps is before the hire line - if (currentCps.isEmpty()) return OptionalDouble.empty(); - OptionalInt nextCps = getIntFromMatcher(cpsMatcher, hireMatcher.end()); //Next cps is right after the hire line - if (nextCps.isEmpty()) return OptionalDouble.empty(); - - Matcher costMatcher = COST_PATTERN.matcher(lore); - OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line - if (cost.isEmpty()) return OptionalDouble.empty(); - return OptionalDouble.of((nextCps.getAsInt() - currentCps.getAsInt()) / (double) cost.getAsInt()); - } - default -> { return OptionalDouble.empty(); } + private Optional<Rabbit> getRabbit(ItemStack item) { + String lore = getConcattedLore(item); + Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); + OptionalInt currentCps = getIntFromMatcher(cpsMatcher); + if (currentCps.isEmpty()) return Optional.empty(); + OptionalInt nextCps = getIntFromMatcher(cpsMatcher); + if (nextCps.isEmpty()) { + nextCps = currentCps; //This means that the rabbit isn't hired yet. + currentCps = OptionalInt.of(0); //So the first instance of the cps is actually the amount we'll get upon hiring. } + + Matcher costMatcher = COST_PATTERN.matcher(lore); + OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line + if (cost.isEmpty()) return Optional.empty(); + return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt())); + } + + private OptionalLong getTotalChocolate(ItemStack item) { + if (item.isEmpty() || item.getItem() != Items.PLAYER_HEAD) return OptionalLong.empty(); + Matcher matcher = TOTAL_CHOCOLATE_PATTERN.matcher(item.getName().getString()); + if (!matcher.find()) return OptionalLong.empty(); + return OptionalLong.of(Long.parseLong(matcher.group(1).replace(",", ""))); } private OptionalInt getIntFromMatcher(Matcher matcher) { @@ -160,4 +159,7 @@ public class ChocolateFactorySolver extends ContainerSolver { if (!matcher.find(startingIndex)) return OptionalDouble.empty(); return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); } + + private record Rabbit(double cpsIncrease, int cost) { + } } |