Skip to content

Commit

Permalink
Add item/stack count calculations (part of next master branch update)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tisawesomeness committed Sep 18, 2023
1 parent 3aa8fce commit 21c8bf4
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.tisawesomeness.minecord.mc.item;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
* A container that can hold one or more stacks of Minecraft items.
*/
@Getter
@RequiredArgsConstructor
public enum Container {
STACK(1),
CHEST(27),
DOUBLE_CHEST(2 * 27),
CHEST_SHULKER(27 * 27),
DOUBLE_CHEST_SHULKER(2 * 27 * 27);

private final int slots;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.tisawesomeness.minecord.mc.item;

import lombok.Getter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* A specific number of Minecraft items. Item count may be negative.
*/
public class ItemCount {

private final long itemCount;
@Getter private final int stackSize;

/**
* Creates a new item count.
* @param itemCount number of starting items
* @param stackSize stack size of the item
* @throws IllegalArgumentException if the stack size is not within 1-64
*/
public ItemCount(long itemCount, int stackSize) {
this.itemCount = itemCount;
if (stackSize < 1 || 64 < stackSize) {
throw new IllegalArgumentException("stackSize must be between 1 and 64 but was " + stackSize);
}
this.stackSize = stackSize;

}

/**
* Creates a new item count with the added items and same stack size.
* @param items number of items to add
* @return new item count
*/
public ItemCount addItems(long items) {
return new ItemCount(itemCount + items, stackSize);
}
/**
* Creates a new item count with the added stacks and same stack size.
* @param stacks number of stacks to add
* @return new item count
*/
public ItemCount addStacks(long stacks) {
return addItems(stackSize * stacks);
}
/**
* Creates a new item count, adding the given number of containers, keeping the same stack size.
* @param container container holding the items
* @param count number of containers to add
* @return new item count
*/
public ItemCount addContainers(Container container, long count) {
return addStacks(container.getSlots() * count);
}

/**
* @return item count
*/
public long getCount() {
return itemCount;
}

/**
* Gets the exact number of containers needed to hold this item count.
* @param container container holding the items
* @return number of containers, possibly fractional
*/
public double getExact(Container container) {
return (double) itemCount / (stackSize * container.getSlots());
}

/**
* Computes a combination of containers that holds this item count.
* Containers with higher capacities are prioritized.
* <br>Example: 1863 items is equal to 1 chest, 2 stacks, 7 items.
* @param containers containers allowed to be used
* @return list of length {@code containers.size() + 1}, each element is the amount of containers necessary in
* descending order, and one extra element at the end for leftover items (above example would return
* {@code [1, 2, 7]})
*/
public List<Long> distribute(Collection<Container> containers) {
long stacks = itemCount / stackSize;
long items = itemCount % stackSize;

List<Long> list = new ArrayList<>();
for (int i = Container.values().length - 1; i >= 0; i--) {
Container container = Container.values()[i];
if (containers.contains(container)) {

list.add(stacks / container.getSlots());
stacks %= container.getSlots();

}
}

list.add(items);
return list;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.tisawesomeness.minecord.mc.item;

import com.tisawesomeness.minecord.util.Mth;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.EnumSet;
import java.util.Set;

import static org.assertj.core.api.Assertions.*;

public class ItemCountTest {

@ParameterizedTest
@ValueSource(longs = {0, 1, 5, 65})
public void testNew(long count) {
assertThat(new ItemCount(count, 64).getCount())
.isEqualTo(count);
}
@ParameterizedTest
@ValueSource(ints = {0, 65})
public void testNewInvalid(int stackSize) {
assertThatThrownBy(() -> new ItemCount(0, stackSize))
.isInstanceOf(IllegalArgumentException.class);
}

@ParameterizedTest
@ValueSource(longs = {-1, 0, 1, 65})
public void testAddItems(long count) {
assertThat(new ItemCount(5, 64).addItems(count).getCount())
.isEqualTo(5 + count);
}
@ParameterizedTest
@CsvSource({
"0, 64, 1, 64",
"2, 1, 5, 7",
"37, 16, 5, 117",
"15, 64, -2, -113"
})
public void testAddStacks(long initialCount, int stackSize, long stacks, long expectedCount) {
assertThat(new ItemCount(initialCount, stackSize).addStacks(stacks).getCount())
.isEqualTo(expectedCount);
}
@ParameterizedTest
@CsvSource({
"0, 64, STACK, 1, 64",
"0, 64, CHEST, -2, -3456",
"7, 16, DOUBLE_CHEST, 5, 4327",
"-165, 64, CHEST_SHULKER, 1, 46491",
"9164, 64, DOUBLE_CHEST_SHULKER, 3, 289100"
})
public void testAddContainers(long initialCount, int stackSize, Container container, long count, long expectedCount) {
assertThat(new ItemCount(initialCount, stackSize).addContainers(container, count).getCount())
.isEqualTo(expectedCount);
}

@ParameterizedTest
@CsvSource({
"0, 64, STACK, 0.0",
"32, 64, STACK, 0.5",
"63, 64, STACK, 0.984375",
"64, 64, STACK, 1.0",
"128, 64, STACK, 2.0",
"-63, 64, STACK, -0.984375",
"2, 16, STACK, 0.125",
"83, 1, STACK, 83.0",
"27000, 64, CHEST, 15.625",
"27000, 64, DOUBLE_CHEST, 7.8125",
"139968, 64, CHEST_SHULKER, 3.0",
"93312, 64, DOUBLE_CHEST_SHULKER, 1.0"
})
public void testExact(long count, int stackSize, Container container, double expected) {
assertThat(new ItemCount(count, stackSize).getExact(container))
.isCloseTo(expected, within(Mth.EPSILON));
}

@ParameterizedTest
@CsvSource({
"0, 64, 0, 0",
"2, 64, 0, 2",
"2, 1, 2, 0",
"69, 64, 1, 5",
"1863, 64, 29, 7",
"-1863, 64, -29, -7"
})
public void testDistributeStack(long count, int stackSize, long stacks, long items) {
assertThat(new ItemCount(count, stackSize).distribute(EnumSet.of(Container.STACK)))
.containsExactly(stacks, items);
}
@ParameterizedTest
@CsvSource({
"0, 64, 0, 0, 0",
"27, 1, 1, 0, 0",
"1863, 64, 1, 2, 7",
"-1863, 64, -1, -2, -7"
})
public void testDistributeChest(long count, int stackSize, long chests, long stacks, long items) {
assertThat(new ItemCount(count, stackSize).distribute(EnumSet.of(Container.STACK, Container.CHEST)))
.containsExactly(chests, stacks, items);
}
@ParameterizedTest
@CsvSource({
"0, 64, 0, 0, 0, 0, 0, 0",
"99999, 64, 1, 0, 1, 1, 23, 31",
"-99999, 64, -1, 0, -1, -1, -23, -31"
})
public void testDistributeAll(long count, int stackSize, long doubleChestShulkers, long chestShulkers,
long doubleChests, long chests, long stacks, long items) {
Set<Container> containers = EnumSet.of(Container.STACK, Container.CHEST, Container.DOUBLE_CHEST,
Container.CHEST_SHULKER, Container.DOUBLE_CHEST_SHULKER);
assertThat(new ItemCount(count, stackSize).distribute(containers))
.containsExactly(doubleChestShulkers, chestShulkers, doubleChests, chests, stacks, items);
}

}

0 comments on commit 21c8bf4

Please sign in to comment.