Jump to content

How to Determine Which Axe to Use?


mbuzz13

Recommended Posts

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!

 

Link to comment
Share on other sites

  • mbuzz13 changed the title to How to Determine Which Axe to Use?

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 by Apaec
Link to comment
Share on other sites

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 by liverare
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 by liverare
Link to comment
Share on other sites

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 

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...