diff --git a/src/main/java/tenor/TaskSerial.java b/src/main/java/tenor/ActuallyCraftTask.java similarity index 94% rename from src/main/java/tenor/TaskSerial.java rename to src/main/java/tenor/ActuallyCraftTask.java index 67b5d0756..ccdce42dc 100644 --- a/src/main/java/tenor/TaskSerial.java +++ b/src/main/java/tenor/ActuallyCraftTask.java @@ -17,6 +17,5 @@ package tenor; -public class TaskSerial extends TaskNode { - +public class ActuallyCraftTask { } diff --git a/src/main/java/tenor/AquireCraftingItems.java b/src/main/java/tenor/AquireCraftingItems.java index f992fe332..56b310468 100644 --- a/src/main/java/tenor/AquireCraftingItems.java +++ b/src/main/java/tenor/AquireCraftingItems.java @@ -17,6 +17,52 @@ package tenor; -public class AquireCraftingItems extends Task{ +import java.util.List; +public class AquireCraftingItems extends QuantizedTaskNode implements ClaimProvider { + CraftingTask output; + + public AquireCraftingItems() { + super(DependencyType.PARALLEL_ALL); + } + + @Override + public double priorityAllocatedTo(IQuantizedParentTaskRelationship child, int quantity) { + AquireItemTask resource = (AquireItemTask) child.childTask(); // all our dependents are aquire item tasks + int amount = output.inputSizeFor(resource); + + // they could provide us with quantity + int actualQuantity = (int) Math.ceil(quantity * 1.0D / amount); + // so we could do the crafting recipe this many times + // how good would that be? + return priority().value(actualQuantity); + } + + @Override + public QuantityRelationship priority() { + return parents().get(0)::allocatedPriority; // gamer style + } + + @Override + public QuantityRelationship cost() { + return null; + } + + @Override + public int quantityCompletedForParent(IQuantizedChildTaskRelationship relationship) { + // our only parent is the crafting task + int minCompletion = Integer.MAX_VALUE; + for (IQuantizedChildTaskRelationship resource : (List) (Object) children()) { + int amountForUs = resource.quantityCompleted(); + + int amountPerCraft = output.inputSizeFor((AquireItemTask) resource.child()); + + int actualQuantity = (int) Math.ceil(amountForUs * 1.0D / amountPerCraft); + + if (actualQuantity < minCompletion || minCompletion == Integer.MAX_VALUE) { + minCompletion = actualQuantity; // any missing ingredient and we aren't really done + } + } + return minCompletion; + } } diff --git a/src/main/java/tenor/AquireItemTask.java b/src/main/java/tenor/AquireItemTask.java index 14f5dbb9b..2b3b8ef98 100644 --- a/src/main/java/tenor/AquireItemTask.java +++ b/src/main/java/tenor/AquireItemTask.java @@ -18,12 +18,57 @@ package tenor; import java.util.HashMap; +import java.util.Map; -public class AquireItemTask extends Task implements ClaimProvider { - HashMap allocation; +public class AquireItemTask extends QuantizedTaskNode implements ClaimProvider, QuantizedDependentCostCalculator { + + HashMap allocation; // allocation of what tasks have claim over what items in our inventory i guess + + public AquireItemTask() { + super(DependencyType.ANY_ONE_OF); + } @Override - public boolean provided(TaskRelationship parent, int quantity) { - return allocation.get(parent) >= quantity; + public int quantityCompletedForParent(IQuantizedChildTaskRelationship relationship) { + return allocation.get(relationship); + } + + public void reallocate() { + allocation.clear(); + int amountToAllocate = getCurrentQuantityInInventory(); + int[] newAmounts = ScarceParentPriorityAllocator.priorityAllocation(amountToAllocate, parents()); + for (int i = 0; i < parents().size(); i++) { + allocation.put(parents().get(i), newAmounts[i]); + } + } + + public int getCurrentQuantityInInventory() { + throw new UnsupportedOperationException("oppa"); + } + + @Override + public QuantityRelationship priority() { + return x -> { + double sum = 0; + for (Map.Entry entry : allocation.entrySet()) { + + IQuantizedChildTaskRelationship parentRelationship = entry.getKey(); + int quantityAssigned = entry.getValue(); + + sum += parentRelationship.allocatedPriority(quantityAssigned); + } + return sum; + }; + } + + @Override + public QuantityRelationship cost() { + return QuantizedDependentCostCalculator.super.cost(); // oppa + } + + @Override + public double priorityAllocatedTo(IQuantizedParentTaskRelationship child, int quantity) { + // how much of our priority would go to this child if it could provide us with quantity of the item we need + return priority().value(quantity); } } diff --git a/src/main/java/tenor/ClaimProvider.java b/src/main/java/tenor/ClaimProvider.java index 7641111d2..24172adf1 100644 --- a/src/main/java/tenor/ClaimProvider.java +++ b/src/main/java/tenor/ClaimProvider.java @@ -18,5 +18,5 @@ package tenor; public interface ClaimProvider { - boolean provided(TaskRelationship parent, int quantity); + int quantityCompletedForParent(IQuantizedChildTaskRelationship relationship); } diff --git a/src/main/java/tenor/CraftingTask.java b/src/main/java/tenor/CraftingTask.java index a14b2cbda..4c8138aca 100644 --- a/src/main/java/tenor/CraftingTask.java +++ b/src/main/java/tenor/CraftingTask.java @@ -17,7 +17,50 @@ package tenor; -public class CraftingTask { - int outputQuantity; +import net.minecraft.util.Tuple; +import java.util.List; + +public class CraftingTask extends QuantizedTaskNode { + int outputQuantity; + List> recipe; + AquireCraftingItems inputs; + + + public CraftingTask() { + super(DependencyType.SERIAL); + } + + @Override + public QuantityRelationship cost() { + return x -> { + int actualQuantity = (int) Math.ceil(x * 1.0D / outputQuantity); + return inputs.cost().value(actualQuantity); + }; + } + + public QuantityRelationship priority() { + if (parents().size() != 1) { + throw new IllegalStateException(); + } + // TODO this is a short circuit + return ((QuantizedTask) (parents().get(0).parentTask())).priority(); + } + + @Override + public double priorityAllocatedTo(IQuantizedParentTaskRelationship child, int quantity) { + // how much priority would we give this child if they could provide us this quantity? + int amountWeWouldProvide = quantity * outputQuantity; + double desirability = priority().value(amountWeWouldProvide); + return desirability; + } + + public int inputSizeFor(AquireItemTask task) { + for (Tuple tup : recipe) { + if (tup.getFirst().equals(task)) { + return tup.getSecond(); + } + } + throw new IllegalStateException(); + } } diff --git a/src/main/java/tenor/IQuantizedChildTaskRelationship.java b/src/main/java/tenor/IQuantizedChildTaskRelationship.java index 5894ebf02..d64c9694d 100644 --- a/src/main/java/tenor/IQuantizedChildTaskRelationship.java +++ b/src/main/java/tenor/IQuantizedChildTaskRelationship.java @@ -23,4 +23,12 @@ public interface IQuantizedChildTaskRelationship extends ITaskRelationshipBase { } double allocatedPriority(int quantity); + + default boolean childProvidesClaimTo(int quantity) { + return quantityCompleted() >= quantity; + } + + default int quantityCompleted() { + return ((ClaimProvider) child()).quantityCompletedForParent(this); + } } diff --git a/src/main/java/tenor/IQuantizedParentTaskRelationship.java b/src/main/java/tenor/IQuantizedParentTaskRelationship.java index e6a36767e..9c112905a 100644 --- a/src/main/java/tenor/IQuantizedParentTaskRelationship.java +++ b/src/main/java/tenor/IQuantizedParentTaskRelationship.java @@ -21,4 +21,6 @@ public interface IQuantizedParentTaskRelationship extends ITaskRelationshipBase default QuantizedTaskNode parent() { return (QuantizedTaskNode) parentTask(); } + + QuantityRelationship cost(); } diff --git a/src/main/java/tenor/ISingularChildTaskRelationship.java b/src/main/java/tenor/ISingularChildTaskRelationship.java index 4ff040dba..b2eb727c6 100644 --- a/src/main/java/tenor/ISingularChildTaskRelationship.java +++ b/src/main/java/tenor/ISingularChildTaskRelationship.java @@ -21,4 +21,6 @@ public interface ISingularChildTaskRelationship extends ITaskRelationshipBase { default SingularTask child() { return (SingularTask) childTask(); } + + double allocatedPriority(); } diff --git a/src/main/java/tenor/ISingularParentTaskRelationship.java b/src/main/java/tenor/ISingularParentTaskRelationship.java index 566da989f..0dc263a5a 100644 --- a/src/main/java/tenor/ISingularParentTaskRelationship.java +++ b/src/main/java/tenor/ISingularParentTaskRelationship.java @@ -21,4 +21,6 @@ public interface ISingularParentTaskRelationship extends ITaskRelationshipBase { default SingularTask parent() { return (SingularTask) parentTask(); } + + double cost(); } diff --git a/src/main/java/tenor/ITaskNodeBase.java b/src/main/java/tenor/ITaskNodeBase.java new file mode 100644 index 000000000..6075d24b3 --- /dev/null +++ b/src/main/java/tenor/ITaskNodeBase.java @@ -0,0 +1,26 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package tenor; + +import java.util.List; + +public interface ITaskNodeBase extends ITask { + List childTasks(); + + DependencyType type(); +} diff --git a/src/main/java/tenor/MineTask.java b/src/main/java/tenor/MineTask.java index c1a3216c3..69d92f04a 100644 --- a/src/main/java/tenor/MineTask.java +++ b/src/main/java/tenor/MineTask.java @@ -18,6 +18,11 @@ package tenor; public class MineTask extends TaskLeaf implements QuantizedTask { + @Override + public QuantityRelationship priority() { + return null; + } + @Override public QuantityRelationship cost() { return null; diff --git a/src/main/java/tenor/QuantizedDependentCostCalculator.java b/src/main/java/tenor/QuantizedDependentCostCalculator.java new file mode 100644 index 000000000..ed6b21a2e --- /dev/null +++ b/src/main/java/tenor/QuantizedDependentCostCalculator.java @@ -0,0 +1,48 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package tenor; + +public interface QuantizedDependentCostCalculator extends ITaskNodeBase { + default QuantityRelationship cost() { + switch (type()) { + case SERIAL: + case PARALLEL_ALL: + return q -> { + double sum = 0; + for (TaskRelationship relationship : childTasks()) { + sum += ((IQuantizedParentTaskRelationship) relationship).cost().value(q); + } + return sum; + }; + case ANY_ONE_OF: // TODO this could be smarter about allocating + return q -> { + double min = -1; + for (TaskRelationship relationship : childTasks()) { + double cost = ((IQuantizedParentTaskRelationship) relationship).cost().value(q); + if (min == -1 || cost < min) { + min = cost; + } + } + return min; + }; + default: + throw new UnsupportedOperationException(); + + } + } +} diff --git a/src/main/java/tenor/QuantizedTask.java b/src/main/java/tenor/QuantizedTask.java index 86b46a3f4..7a5742444 100644 --- a/src/main/java/tenor/QuantizedTask.java +++ b/src/main/java/tenor/QuantizedTask.java @@ -25,7 +25,7 @@ public interface QuantizedTask extends ITask { return (List) (Object) parentTasks(); } - default QuantityRelationship priority() { + /*default QuantityRelationship priority() { return q -> { double sum = 0; for (IQuantizedChildTaskRelationship parent : parents()) { @@ -33,7 +33,8 @@ public interface QuantizedTask extends ITask { } return sum; }; - } + }*/ + QuantityRelationship priority(); QuantityRelationship cost(); } diff --git a/src/main/java/tenor/QuantizedTaskNode.java b/src/main/java/tenor/QuantizedTaskNode.java index 5f54f4d76..4db322528 100644 --- a/src/main/java/tenor/QuantizedTaskNode.java +++ b/src/main/java/tenor/QuantizedTaskNode.java @@ -17,6 +17,16 @@ package tenor; +import java.util.List; + public abstract class QuantizedTaskNode extends TaskNode implements QuantizedTask { - public abstract double allocatedPriority(int quantity, TaskRelationship child); + public QuantizedTaskNode(DependencyType type) { + super(type); + } + + public List children() { + return (List) (Object) childTasks(); + } + + public abstract double priorityAllocatedTo(IQuantizedParentTaskRelationship child, int quantity); } diff --git a/src/main/java/tenor/QuantizedToQuantizedTaskRelationship.java b/src/main/java/tenor/QuantizedToQuantizedTaskRelationship.java index 9fe571efd..cf8d23db0 100644 --- a/src/main/java/tenor/QuantizedToQuantizedTaskRelationship.java +++ b/src/main/java/tenor/QuantizedToQuantizedTaskRelationship.java @@ -20,6 +20,11 @@ package tenor; public class QuantizedToQuantizedTaskRelationship extends TaskRelationship implements IQuantizedChildTaskRelationship, IQuantizedParentTaskRelationship { @Override public double allocatedPriority(int quantity) { - return parent().allocatedPriority(quantity, this); + return parent().priorityAllocatedTo(this, quantity); + } + + @Override + public QuantityRelationship cost() { + return child().cost(); } } diff --git a/src/main/java/tenor/QuantizedToSingularTaskRelationship.java b/src/main/java/tenor/QuantizedToSingularTaskRelationship.java index 422a5a2a7..042a21f7b 100644 --- a/src/main/java/tenor/QuantizedToSingularTaskRelationship.java +++ b/src/main/java/tenor/QuantizedToSingularTaskRelationship.java @@ -18,4 +18,14 @@ package tenor; public class QuantizedToSingularTaskRelationship extends TaskRelationship implements ISingularChildTaskRelationship, IQuantizedParentTaskRelationship { + + @Override + public QuantityRelationship cost() { + return x -> child().cost(); + } + + @Override + public double allocatedPriority() { + throw new UnsupportedOperationException("Cannot allocate priority from quantized parent to singular child"); + } } diff --git a/src/main/java/tenor/ScarceParentPriorityAllocator.java b/src/main/java/tenor/ScarceParentPriorityAllocator.java new file mode 100644 index 000000000..22be4779f --- /dev/null +++ b/src/main/java/tenor/ScarceParentPriorityAllocator.java @@ -0,0 +1,68 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package tenor; + +import java.util.List; + +public class ScarceParentPriorityAllocator { + public static int[] priorityAllocation(int quantity, List parents) { + if (quantity == 0) { + return new int[parents.size()]; + } + double[][] priorities = new double[parents.size()][quantity]; + for (int i = 0; i < parents.size(); i++) { + for (int j = 1; j < quantity; j++) { + priorities[i][j] = parents.get(i).allocatedPriority(j); + } + } + + int filled = 0; + double totalPriority = 0; + int[] taken = new int[parents.size()]; + while (true) { + + double bestRatio = Double.MIN_VALUE; + int bestParent = -1; + int bestQuantity = -1; + for (int i = 0; i < priorities.length; i++) { + for (int j = 1; j < quantity - filled; j++) { + double ratio = priorities[i][j] / j; + if (ratio > bestRatio || bestRatio == Double.MIN_VALUE) { + bestRatio = ratio; + bestParent = i; + bestQuantity = j; + } + } + } + + if (bestParent == -1) { + return taken; + } + taken[bestParent] += bestQuantity; + filled += bestQuantity; + double priorityTaken = priorities[bestParent][bestQuantity]; + totalPriority += priorityTaken; + + double[] repl = new double[priorities[bestParent].length - bestQuantity]; + for (int i = 0; i < repl.length; i++) { + repl[i] = priorities[bestParent][i + bestQuantity] - priorityTaken; + } + priorities[bestParent] = repl; + } + } +} diff --git a/src/main/java/tenor/SingularTask.java b/src/main/java/tenor/SingularTask.java index 47a1cf2eb..266832b9b 100644 --- a/src/main/java/tenor/SingularTask.java +++ b/src/main/java/tenor/SingularTask.java @@ -17,8 +17,14 @@ package tenor; +import java.util.List; + public interface SingularTask extends ITask { - double priority(); + default List parents() { + return (List) (Object) parentTasks(); + } + + double priorityAllocatedToChild(ISingularParentTaskRelationship relationship); double cost(); } diff --git a/src/main/java/tenor/SingularTaskNode.java b/src/main/java/tenor/SingularTaskNode.java new file mode 100644 index 000000000..90a39fda4 --- /dev/null +++ b/src/main/java/tenor/SingularTaskNode.java @@ -0,0 +1,21 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package tenor; + +public class SingularTaskNode { +} diff --git a/src/main/java/tenor/SingularToQuantizedTaskRelationship.java b/src/main/java/tenor/SingularToQuantizedTaskRelationship.java index 275ff53c2..87759f6be 100644 --- a/src/main/java/tenor/SingularToQuantizedTaskRelationship.java +++ b/src/main/java/tenor/SingularToQuantizedTaskRelationship.java @@ -22,6 +22,11 @@ public class SingularToQuantizedTaskRelationship extends TaskRelationship implem @Override public double allocatedPriority(int quantity) { - return quantity >= quantityRequired ? parent().priority() : 0; + return quantity >= quantityRequired ? parent().priorityAllocatedToChild(this) : 0; + } + + @Override + public double cost() { + return child().cost().value(quantityRequired); } } diff --git a/src/main/java/tenor/SingularToSingularTaskRelationship.java b/src/main/java/tenor/SingularToSingularTaskRelationship.java index 648bcc599..6552f9232 100644 --- a/src/main/java/tenor/SingularToSingularTaskRelationship.java +++ b/src/main/java/tenor/SingularToSingularTaskRelationship.java @@ -18,4 +18,13 @@ package tenor; public class SingularToSingularTaskRelationship extends TaskRelationship implements ISingularChildTaskRelationship, ISingularParentTaskRelationship { + @Override + public double allocatedPriority() { + return parent().priorityAllocatedToChild(this); + } + + @Override + public double cost() { + return child().cost(); + } } diff --git a/src/main/java/tenor/Task.java b/src/main/java/tenor/Task.java index c99a2b6d9..0f3d0fd8a 100644 --- a/src/main/java/tenor/Task.java +++ b/src/main/java/tenor/Task.java @@ -17,11 +17,10 @@ package tenor; -import java.util.ArrayList; import java.util.List; public abstract class Task implements ITask { - ArrayList parentRelationships; + List parentRelationships; public List parentTasks() { return parentRelationships; diff --git a/src/main/java/tenor/TaskNode.java b/src/main/java/tenor/TaskNode.java index 1d2694169..0db25a234 100644 --- a/src/main/java/tenor/TaskNode.java +++ b/src/main/java/tenor/TaskNode.java @@ -17,9 +17,21 @@ package tenor; -import java.util.ArrayList; +import java.util.List; -public abstract class TaskNode extends Task { - ArrayList childRelationships; +public abstract class TaskNode extends Task implements ITaskNodeBase { + List childRelationships; DependencyType type; + + public TaskNode(DependencyType type) { + this.type = type; + } + + public List childTasks() { + return childRelationships; + } + + public DependencyType type() { + return type; + } } diff --git a/src/main/java/tenor/TaskRelationship.java b/src/main/java/tenor/TaskRelationship.java index 356536135..c834d3bfd 100644 --- a/src/main/java/tenor/TaskRelationship.java +++ b/src/main/java/tenor/TaskRelationship.java @@ -22,10 +22,6 @@ public class TaskRelationship implements ITaskRelationshipBase { Task child; DependencyType type; - public boolean childProvidesClaimTo(int quantity) { - return ((ClaimProvider) child).provided(this, quantity); - } - @Override public TaskNode parentTask() { return parent;