I'm creating a simple RPG console game, I'm at the stage of creating an inventory and loot system. Present in the program, both class Player
and class Monster
have the arrayList Backpack
properties, when the program creates an object of the monster class, items in the monster's backpack are also automatically created, after killing the monster, you can take them to your backpack, and this is where my problem begins how to elegantly prevent duplication of items in the backpack, each item is a class too
, now this function works by checking in a nested loop each item one by one to see if it is already in the backpack if it is instead of adding it once moreover, it increases its amount property, if I don't have this item in my backpack, it just adds to the list, the solution works, but definitely it is not the right solution, because with many of items this checking mechanism will grow a lot, if anyone has any valuable tips I will be grateful.
I also have a second idea to create a boolean Is_it_in_Backpack
variable, and somehow connect it with the loot collecting mechanism
Below some code sample
public class Player {
public static ArrayList<Item> Backpack = new ArrayList<>()
}
and the class Skieleton:
public class Skieleton extends Monsters {
public static ArrayList<Item> Backpack;
public Skieleton() {
Backpack = new ArrayList<>();
Backpack.add(new Weapon("Rusty sword", "Just a rusty sword", 3, 2 ));
Backpack.add(new Armor("Leather Armor", "Old leather armor", 6, 3));
}
class item:
public class Item {
public String ItemName;
public String Description;
public int ItemSize;
public int ItemWeight;
public int Amount;
public Item(String ItemName, String Description, int ItemSize, int ItemWeight)
{
this.ItemName = ItemName;
this.Description = Description;
this.ItemSize = ItemSize;
this.ItemWeight = ItemWeight;
}
public Item() {
}
}
CodePudding user response:
I recommend you use a class that extends java.util.Set
:
- If order is not important for you, you can use
HashSet
; - If order of insertion is important, you can use
LinkedHashSet
; - If natural order is important (alphabetical by name or other property), you can use
TreeSet
and implement the interfaceComparable
onto the class inserted in the collection.
However, regardless of your choice, it's recommended you implement hashCode()
(for optimization) and equals()
(to let collection identify which item is equal to other and avoid duplication).
CodePudding user response:
If you can use third party libraries, I'd recommend using a Bag
from Eclipse Collections.
With your Item
class implementing equals
and hashCode
on ItemName
field, your example usage could look like:
final MutableBag<Item> backPack = new HashBag<>();
final Item rustySword = new Item("Rusty sword", "Just a rusty sword", 3, 2);
final Item leatherArmour = new Item("Leather Armor", "Old leather armor", 6, 3);
backPack.add(rustySword);
backPack.add(leatherArmour);
backPack.add(rustySword);
System.out.println(backPack.toMapOfItemToCount()); // prints {Item[ItemName='Rusty sword']=2, Item[ItemName='Leather Armor']=1}
System.out.println(backPack.occurrencesOf(rustySword)); // prints 2
The API is rich, and provides a lot more: https://www.eclipse.org/collections/javadoc/11.0.0/org/eclipse/collections/api/bag/Bag.html
CodePudding user response:
I would use a Map.
Here's my suggestion:
import java.util.*;
class Player {
public Backpack backpack= new Backpack();
}
class Monster { }
class Skieleton extends Monster {
public Backpack backpack= new Backpack();
public Skieleton() {
backpack.add(new Weapon("Rusty sword", "Just a rusty sword", 3, 2 ));
backpack.add(new Armor("Leather Armor", "Old leather armor", 6, 3));
}
}
class Backpack {
private HashMap<Item,Item> items = new HashMap<>();
public Item add(Item item){
if (items.containsKey(item)){
items.get(item).Amount= item.Amount;
return items.get(item);
} else {
items.put(item,item);
return item;
}
}
public Item get(Item item){
return items.getOrDefault(item, null);
}
}
class Item {
public String ItemName;
public String Description;
public int ItemSize;
public int ItemWeight;
public int Amount;
public Item(String ItemName, String Description, int ItemSize, int ItemWeight)
{
this.ItemName = ItemName;
this.Description = Description;
this.ItemSize = ItemSize;
this.ItemWeight = ItemWeight;
}
public Item() {
}
public boolean equals(Object o){
if (o instanceof Item){
return ItemName.equals( ((Item)o).ItemName);
}
return false;
}
}
CodePudding user response:
You can use a HashMap for storing the items. First, I would like to change the Item
class to not have amount field in it. Let an item denote what an item is (name, description, size and weight).
Here's the updated backpack:
Map<Item, Integer> backpack = new HashMap<>();
To add an item, you can use Map#merge method.
public void addItemToBackpack(Item item, int quantity) {
backpack.merge(item, quantity, (oldQuantity, newQuantity) -> oldQuantity newQuantity);
}
We insert the item and its quantity. If the item is not already present, it will be inserted with the passed quantity.
If it is already present, then the BiFunction
which is a mapping function will be called with the existing value (oldQuantity
) and the new value which we tried to insert (newQuantity
). We sum them both, return it and the item's value (quantity) will be updated with this value.
Using method references, we can write the above as,
backpack.merge(item, quantity, Integer::sum);