package com.infinityraider.agricraft.apiimpl; import com.agricraft.agricore.core.AgriCore; import com.infinityraider.agricraft.api.mutation.IAgriCrossStrategy; import com.infinityraider.agricraft.api.mutation.IAgriMutationEngine; import com.infinityraider.agricraft.farming.mutation.MutateStrategy; import com.infinityraider.agricraft.farming.mutation.SpreadStrategy; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Random; import java.util.stream.Collectors; import net.minecraft.util.Tuple; /** * This class decides whether a plant is spreading or mutating and also * calculates the new stats (growth, gain, strength) of the new plant based on * the 4 neighbours. */ public final class MutationEngine implements IAgriMutationEngine { private static final MutationEngine INSTANCE = new MutationEngine(); private final List<Tuple<Double, IAgriCrossStrategy>> strategies = new ArrayList<>(); private double sigma = 0; private MutationEngine() { registerStrategy(new MutateStrategy()); registerStrategy(new SpreadStrategy()); } public static MutationEngine getInstance() { return INSTANCE; } @Override public boolean registerStrategy(IAgriCrossStrategy strategy) { if (strategy.getRollChance() > 1f || strategy.getRollChance() < 0f) { throw new IndexOutOfBoundsException( "Invalid roll chance of " + strategy.getRollChance() + "!\n" + "The roll chance must be in the range 0.0 (inclusive) to 1.0 (exclusive)!" ); } else if (strategy.getRollChance() == 0) { AgriCore.getLogger("agricraft").debug("Skipping mutation strategy with zero chance!"); return false; } else if (hasStrategy(strategy)) { AgriCore.getLogger("agricraft").debug("Skipping duplicate mutation strategy!"); return false; } else { this.sigma += strategy.getRollChance(); this.strategies.add(new Tuple<>(sigma, strategy)); return true; } } @Override public boolean hasStrategy(IAgriCrossStrategy strategy) { return this.strategies.stream().anyMatch(t -> t.getSecond().equals(strategy)); } @Override public List<IAgriCrossStrategy> getStrategies() { return this.strategies.stream() .map(t -> t.getSecond()) .collect(Collectors.toList()); } @Override public Optional<IAgriCrossStrategy> rollStrategy(Random rand) { final double value = rand.nextDouble() * sigma; return this.strategies.stream() // Value looks very important here... lol. .filter(t -> value <= t.getFirst()) .map(t -> t.getSecond()) .findFirst(); } }