mbuzz13 Posted October 17, 2017 Share Posted October 17, 2017 Hey guys, I am just getting started with writing scripts for osbot, but I have a basic knowledge of java. I am trying to write code that will determine which axe to use for woodcutting depending on the players woodcutting level. I've created an array with all of the different axes, but now I am stuck on how to set a specific number value that corresponds with each axe (for example rune axe = lvl 41, dragon axe = lvl 61). String[] axes = {"Bronze axe", "Iron axe", "Steel axe", "Mithril axe", "Adamant axe", "Rune axe", "Dragon axe"}; I was thinking about using a for loop to cycle through the array until it finds the highest possible axe that can be used, but like I said, I'm not sure how to create a connection between the two values. Any help would be appreciated. Thanks! Quote Link to comment Share on other sites More sharing options...
Runnwith Posted October 17, 2017 Share Posted October 17, 2017 This could help you and your goals of making a simple script so far Quote Link to comment Share on other sites More sharing options...
k9thebeast Posted October 17, 2017 Share Posted October 17, 2017 Make a function with this in the body, for each axe getSkills().getStaticSkill(Skill.WOODCUTTING) > (level for axe) return axe; Quote Link to comment Share on other sites More sharing options...
Apaec Posted October 17, 2017 Share Posted October 17, 2017 (edited) You could use a Map for this, however if you wanted to store more information, you would need something else. Probably your best bet is to store the information in an enum, as below (I wrote the code in the reply box so apologies if I made any mistakes, fingers crossed they should be easy enough to correct!). I included an additional parameter, 'colour', which is just the colour of the axe. In practice this is useless, but I included it to illustrate how to add a second parameter. public enum Axe { BRONZE(1, Color.BROWN), IRON(1, Color.DARK_GRAY), RUNE(41, Color.CYAN); // Add all axes here private final int levelRequirement; private final Color colour; Axe (int levelRequirement, Color colour) { this.levelRequirement = levelRequirement; this.colour = colour; } // Returns whether the current level is sufficient for the axe public boolean hasRequiredLevel(int currentLevel) { return currentLevel >= levelRequirement; } // Returns the associated level requirement public int getRequiredLevel() { return levelRequirement; } // Returns the colour of the axe public Color getColour() { return colour; } // Make it return a cleanly formatted String, e.g 'Rune' public String getTier() { String lower = super.toString().toLowerCase().replace("_", " "); return Character.toUpperCase(lower.charAt(0)) + lower.substring(1, lower.length()); } // Make it return a cleanly formatted String for whole axe, e.g 'Rune axe' public String getName() { return getTier() + "axe"; } @Override public String toString() { return getName(); } } Usage: Axe toUse = Arrays.stream(Axe.values()).filter(a -> a.hasLevelRequirement(getSkills().getStatic(Skill.WOODCUTTING))).reduce(Axe.BRONZE, (a, b) -> b); It is untested but it should hopefully work !! Good luck! Apa Edited October 17, 2017 by Apaec Quote Link to comment Share on other sites More sharing options...
liverare Posted October 17, 2017 Share Posted October 17, 2017 (edited) 3 hours ago, Apaec said: You could use a Map for this, however if you wanted to store more information, you would need something else. Probably your best bet is to store the information in an enum, as below (I wrote the code in the reply box so apologies if I made any mistakes, fingers crossed they should be easy enough to correct!). I included an additional parameter, 'colour', which is just the colour of the axe. In practice this is useless, but I included it to illustrate how to add a second parameter. public enum Axe { BRONZE(1, Color.BROWN), IRON(1, Color.DARK_GRAY), RUNE(41, Color.CYAN); // Add all axes here private final int levelRequirement; private final Color colour; Axe (int levelRequirement, Color colour) { this.levelRequirement = levelRequirement; this.colour = colour; } // Returns whether the current level is sufficient for the axe public boolean hasRequiredLevel(int currentLevel) { return currentLevel >= levelRequirement; } // Returns the associated level requirement public int getRequiredLevel() { return levelRequirement; } // Returns the colour of the axe public Color getColour() { return colour; } // Make it return a cleanly formatted String, e.g 'Rune' public String getTier() { String lower = super.toString().toLowerCase().replace("_", " "); return Character.toUpperCase(lower.charAt(0)) + lower.substring(1, lower.length()); } // Make it return a cleanly formatted String for whole axe, e.g 'Rune axe' public String getName() { return getTier() + "axe"; } @Override public String toString() { return getName(); } } Usage: Axe toUse = Arrays.stream(Axe.values()).filter(a -> a.hasLevelRequirement(getSkills().getStatic(Skill.WOODCUTTING))).reduce(Axe.BRONZE, (a, b) -> b); It is untested but it should hopefully work !! Good luck! Apa You haven't made a mistake, but you have massively over-complicated such a simple procedure. Understand your audience, because @mbuzz13 will likely use your code not understanding how or why it's doing what it does, especially the Lambda stuff. Also, you've got a whole lot of post-processing happening at run time, such as your getTier and getName methods. This stuff should already be compiled and available in the memory. I've modified your code: public enum Axe implements Filter<Item> { BRONZE("Bronze axe", 1), IRON("Iron axe", 1), RUNE("Rune axe", 41); private final String name; private final int level; Axe(String name, int level) { this.name = name; this.level = level; } @Override public String toString() { return name; } public int getLevel() { return level; } @Override public boolean match(Item item) { return item.getName().equals(name); } public static Axe valueOf(Item item) { Axe axe = null; for (Axe next : values()) { if (next.match(item)) { axe = next; break; } } return axe; } } The only fancy function here is the implementation of the Filter<Item> and the static method valueOf(Item). You'll see why.. private static int sortByTier(Item item1, Item item2) { Axe axe1 = Axe.valueOf(item1); Axe axe2 = Axe.valueOf(item2); return axe2.compareTo(axe1); // reverse order (best to worst) } This is just a way for us to order the items. Notice how we're using Axe.valueOf(Item). Then you can chose to either use or not use Lambda to find the best item (that is an axe): private static Item getBestAxeUsingLambda(ItemContainer itemContainer) { return itemContainer.filter(Axe.values()) .stream() .sorted(Test::sortByTier) .findFirst() .orElse(null); } private static Item getBestAxe(ItemContainer itemContainer) { Item bestAxe = null; List<Item> axes = itemContainer.filter(Axe.values()); // Axe implements Filter<Item> if (axes != null && !axes.isEmpty()) { axes.sort(Test::sortByTier); bestAxe = axes.get(0); } return bestAxe; } Then you can get the best axes: @Override public int onLoop() throws InterruptedException { Item bestAxeInTheBank = getBestAxe(bank); Item bestAxeInTheInventory = getBestAxe(inventory); Item bestAxeEquipped = getBestAxe(equipment); return 0; } However, you'll need to compare and contrast the best axes found to figure out which of them is truly the best. Edited October 17, 2017 by liverare Quote Link to comment Share on other sites More sharing options...
mbuzz13 Posted October 17, 2017 Author Share Posted October 17, 2017 4 hours ago, Apaec said: You could use a Map for this, however if you wanted to store more information, you would need something else. Probably your best bet is to store the information in an enum, as below (I wrote the code in the reply box so apologies if I made any mistakes, fingers crossed they should be easy enough to correct!). I included an additional parameter, 'colour', which is just the colour of the axe. In practice this is useless, but I included it to illustrate how to add a second parameter. public enum Axe { BRONZE(1, Color.BROWN), IRON(1, Color.DARK_GRAY), RUNE(41, Color.CYAN); // Add all axes here private final int levelRequirement; private final Color colour; Axe (int levelRequirement, Color colour) { this.levelRequirement = levelRequirement; this.colour = colour; } // Returns whether the current level is sufficient for the axe public boolean hasRequiredLevel(int currentLevel) { return currentLevel >= levelRequirement; } // Returns the associated level requirement public int getRequiredLevel() { return levelRequirement; } // Returns the colour of the axe public Color getColour() { return colour; } // Make it return a cleanly formatted String, e.g 'Rune' public String getTier() { String lower = super.toString().toLowerCase().replace("_", " "); return Character.toUpperCase(lower.charAt(0)) + lower.substring(1, lower.length()); } // Make it return a cleanly formatted String for whole axe, e.g 'Rune axe' public String getName() { return getTier() + "axe"; } @Override public String toString() { return getName(); } } Usage: Axe toUse = Arrays.stream(Axe.values()).filter(a -> a.hasLevelRequirement(getSkills().getStatic(Skill.WOODCUTTING))).reduce(Axe.BRONZE, (a, b) -> b); It is untested but it should hopefully work !! Good luck! Apa Thank you! this was very helpful! Much appreciated. 49 minutes ago, liverare said: You haven't made a mistake, but you have massively over-complicated such a simple procedure. Understand your audience, because @mbuzz13 will likely use your code not understanding how or why it's doing what it does, especially the Lambda stuff. Also, you've got a whole lot of post-processing happening at run time, such as your getTier and getName methods. This stuff should already be compiled and available in the memory. I've modified your code: public enum Axe implements Filter<Item> { BRONZE("Bronze axe", 1), IRON("Iron axe", 1), RUNE("Rune axe", 41); private final String name; private final int level; Axe(String name, int level) { this.name = name; this.level = level; } @Override public String toString() { return name; } public int getLevel() { return level; } @Override public boolean match(Item item) { return item.getName().equals(name); } public static Axe valueOf(Item item) { Axe axe = null; for (Axe next : values()) { if (next.match(item)) { axe = next; break; } } return axe; } } The only fancy function here is the implementation of the Filter<Item> and the static method valueOf(Item). You'll see why.. private static int sortByTier(Item item1, Item item2) { Axe axe1 = Axe.valueOf(item1); Axe axe2 = Axe.valueOf(item2); return axe2.compareTo(axe1); // reverse order (best to worst) } This is just a way for us to order the items. Notice how we're using Axe.valueOf(Item). Then you can chose to either use or not use Lambda to find the best item (that is an axe): private static Item getBestAxeUsingLambda(ItemContainer itemContainer) { return itemContainer.filter(Axe.values()) .stream() .sorted(Test::sortByTier) .findFirst() .orElse(null); } private static Item getBestAxe(ItemContainer itemContainer) { Item bestAxe = null; List<Item> axes = itemContainer.filter(Axe.values()); // Axe implements Filter<Item> if (axes != null && !axes.isEmpty()) { axes.sort(Test::sortByTier); bestAxe = axes.get(0); } return bestAxe; } Then you can get the best axes: @Override public int onLoop() throws InterruptedException { Item bestAxeInTheBank = getBestAxe(bank); Item bestAxeInTheInventory = getBestAxe(inventory); Item bestAxeEquipped = getBestAxe(equipment); return 0; } However, you'll need to compare and contrast the best axes found to figure out which of them is truly the best. Thank you for this as well. As of right now, I am seeking help for this not just to create a script that will work, but also to learn so I will be able to do this in the future by myself, so thank you for a different approach to this. Both of you have helped a lot. Quote Link to comment Share on other sites More sharing options...
Juggles Posted October 17, 2017 Share Posted October 17, 2017 So overcomplicated lol Just check wc levels and if equipment has the axe. Should only be like 15 lines total 1 1 Quote Link to comment Share on other sites More sharing options...
liverare Posted October 17, 2017 Share Posted October 17, 2017 (edited) 2 hours ago, Juggles said: So overcomplicated lol Just check wc levels and if equipment has the axe. Should only be like 15 lines total Sure if your script finds what best tier axe you can use and then just assumes you have it. Because otherwise, you'll need a few more lines to find the best of the axes you have available to you. Edited October 17, 2017 by liverare Quote Link to comment Share on other sites More sharing options...
Juggles Posted October 17, 2017 Share Posted October 17, 2017 29 minutes ago, liverare said: Sure if your script finds what best tier axe you can use and then just assumes you have it. Because otherwise, you'll need a few more lines to find the best of the axes you have available to you. Assuming he has the axes in inventory, its as simple as detecting current level and checking if equipped. If not equipped then equip it. If he has to get it from the bank, of course the code will be longer but still can be accomplished with a simple check if in bank else walk to bank, open bank, withdraw and then equip. I just dont understand the need to overcomplicate the script and use advanced java when the API Alek has created basically does it all for you and makes coding scripts on here so simple 1 Quote Link to comment Share on other sites More sharing options...