Reimplemented divide by 0 mishaps in DoubleArithmetic, fixed mishaps not being able to alter the stack (accepting mutable copy of immutable list, changes to copy not changing original)
This commit is contained in:
parent
7c6b6e530d
commit
d51fe053e3
|
@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.casting.arithmetic.operator;
|
|||
import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaMultiPredicate;
|
||||
import at.petrak.hexcasting.api.casting.iota.Iota;
|
||||
import at.petrak.hexcasting.api.casting.iota.IotaType;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
|
@ -32,11 +33,13 @@ public abstract class Operator {
|
|||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* The method called when this Operator is actually acting on the stack, for real.
|
||||
* @param iotas An iterable of iotas with {@link Operator#arity} elements that satisfied {@link Operator#accepts}.
|
||||
* @return the iotas that this operator will return to the stack (with the first element of the returned iterable being placed deepest into the stack, and the last element on top of the stack).
|
||||
* @throws Mishap if the Operator mishaps for any reason it will be passed up the chain.
|
||||
*/
|
||||
public abstract @NotNull Iterable<Iota> apply(@NotNull Iterable<Iota> iotas);
|
||||
public abstract @NotNull Iterable<Iota> apply(@NotNull Iterable<Iota> iotas) throws Mishap;
|
||||
|
||||
/**
|
||||
* A helper method to take an iota that you know is of iotaType and returning it as an iota of that type.
|
||||
|
|
|
@ -76,7 +76,7 @@ sealed class OperatorSideEffect {
|
|||
)
|
||||
)
|
||||
|
||||
mishap.execute(harness.env, errorCtx, harness.image.stack.toMutableList())
|
||||
harness.image = harness.image.copy(stack = mishap.executeReturnStack(harness.env, errorCtx, harness.image.stack.toMutableList()))
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -39,12 +39,17 @@ abstract class Mishap : Throwable() {
|
|||
*/
|
||||
abstract fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>)
|
||||
|
||||
fun executeReturnStack(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>): List<Iota> {
|
||||
execute(ctx, errorCtx, stack)
|
||||
return stack
|
||||
}
|
||||
|
||||
protected abstract fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component
|
||||
|
||||
/**
|
||||
* Every error message should be prefixed with the name of the action...
|
||||
*/
|
||||
public fun errorMessageWithName(ctx: CastingEnvironment, errorCtx: Context): Component {
|
||||
fun errorMessageWithName(ctx: CastingEnvironment, errorCtx: Context): Component {
|
||||
return if (errorCtx.name != null) {
|
||||
"hexcasting.mishap".asTranslatedComponent(errorCtx.name, this.errorMessage(ctx, errorCtx))
|
||||
} else {
|
||||
|
|
|
@ -27,6 +27,13 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s
|
|||
companion object {
|
||||
private const val PREFIX = "hexcasting.mishap.divide_by_zero"
|
||||
|
||||
@JvmStatic
|
||||
fun of(operand1: Double, operand2: Double, suffix: String = "divide"): MishapDivideByZero {
|
||||
if (suffix == "exponent")
|
||||
return MishapDivideByZero(translate(DoubleIota(operand1)), powerOf(DoubleIota(operand2)), suffix)
|
||||
return MishapDivideByZero(translate(DoubleIota(operand1)), translate(DoubleIota(operand2)), suffix)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun of(operand1: Iota, operand2: Iota, suffix: String = "divide"): MishapDivideByZero {
|
||||
if (suffix == "exponent")
|
||||
|
@ -34,6 +41,15 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s
|
|||
return MishapDivideByZero(translate(operand1), translate(operand2), suffix)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun tan(angle: Double): MishapDivideByZero {
|
||||
val translatedAngle = translate(DoubleIota(angle))
|
||||
return MishapDivideByZero(
|
||||
"$PREFIX.sin".asTranslatedComponent(translatedAngle),
|
||||
"$PREFIX.cos".asTranslatedComponent(translatedAngle)
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun tan(angle: DoubleIota): MishapDivideByZero {
|
||||
val translatedAngle = translate(angle)
|
||||
|
|
|
@ -1,104 +1,80 @@
|
|||
package at.petrak.hexcasting.common.casting.arithmetic;
|
||||
package at.petrak.hexcasting.common.casting.arithmetic
|
||||
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaMultiPredicate;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaPredicate;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorBinary;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorUnary;
|
||||
import at.petrak.hexcasting.api.casting.iota.DoubleIota;
|
||||
import at.petrak.hexcasting.api.casting.math.HexPattern;
|
||||
import at.petrak.hexcasting.common.casting.arithmetic.operator.OperatorLog;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic.*
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.engine.InvalidOperatorException
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorBinary
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorUnary
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaMultiPredicate
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaPredicate
|
||||
import at.petrak.hexcasting.api.casting.iota.DoubleIota
|
||||
import at.petrak.hexcasting.api.casting.iota.Iota
|
||||
import at.petrak.hexcasting.api.casting.math.HexPattern
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapDivideByZero
|
||||
import at.petrak.hexcasting.common.casting.arithmetic.operator.OperatorLog
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
|
||||
import java.util.function.DoubleBinaryOperator
|
||||
import java.util.function.DoubleUnaryOperator
|
||||
import kotlin.math.*
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.DoubleBinaryOperator;
|
||||
import java.util.function.DoubleUnaryOperator;
|
||||
object DoubleArithmetic : Arithmetic {
|
||||
@JvmField
|
||||
val OPS = listOf(
|
||||
ADD,
|
||||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
ABS,
|
||||
POW,
|
||||
FLOOR,
|
||||
CEIL,
|
||||
SIN,
|
||||
COS,
|
||||
TAN,
|
||||
ARCSIN,
|
||||
ARCCOS,
|
||||
ARCTAN,
|
||||
ARCTAN2,
|
||||
LOG,
|
||||
MOD
|
||||
)
|
||||
|
||||
import static at.petrak.hexcasting.api.casting.arithmetic.operator.Operator.downcast;
|
||||
import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.DOUBLE;
|
||||
/**
|
||||
* An example of an IotaMultiPredicate, which returns true only if all arguments to the Operator are DoubleIotas.
|
||||
*/
|
||||
val ACCEPTS: IotaMultiPredicate = IotaMultiPredicate.all(IotaPredicate.ofType(HexIotaTypes.DOUBLE))
|
||||
|
||||
public enum DoubleArithmetic implements Arithmetic {
|
||||
INSTANCE;
|
||||
override fun arithName() = "double_math"
|
||||
|
||||
public static final List<HexPattern> OPS = List.of(
|
||||
ADD,
|
||||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
ABS,
|
||||
POW,
|
||||
FLOOR,
|
||||
CEIL,
|
||||
SIN,
|
||||
COS,
|
||||
TAN,
|
||||
ARCSIN,
|
||||
ARCCOS,
|
||||
ARCTAN,
|
||||
ARCTAN2,
|
||||
LOG,
|
||||
MOD
|
||||
);
|
||||
override fun opTypes() = OPS
|
||||
|
||||
/**
|
||||
* An example of an IotaMultiPredicate, which returns true only if all arguments to the Operator are DoubleIotas.
|
||||
*/
|
||||
public static final IotaMultiPredicate ACCEPTS = IotaMultiPredicate.all(IotaPredicate.ofType(DOUBLE));
|
||||
override fun getOperator(pattern: HexPattern): Operator {
|
||||
return when (pattern) {
|
||||
ADD -> make2 { a, b -> java.lang.Double.sum(a, b) }
|
||||
SUB -> make2 { a, b -> a - b }
|
||||
MUL -> make2 { a, b -> a * b }
|
||||
DIV -> make2 { a, b -> if (b == 0.0) throw MishapDivideByZero.of(a, b) else a / b }
|
||||
ABS -> make1 { a -> abs(a) }
|
||||
POW -> make2 { a, b -> a.pow(b) }
|
||||
FLOOR -> make1 { a -> floor(a) }
|
||||
CEIL -> make1 { a -> ceil(a) }
|
||||
SIN -> make1 { a -> sin(a) }
|
||||
COS -> make1 { a -> cos(a) }
|
||||
TAN -> make1 { a -> if (cos(a) == 0.0) throw MishapDivideByZero.tan(a) else tan(a) }
|
||||
ARCSIN -> make1 { a -> asin(a) }
|
||||
ARCCOS -> make1 { a -> acos(a) }
|
||||
ARCTAN -> make1 { a -> atan(a) }
|
||||
ARCTAN2 -> make2 { a, b -> atan2(a, b) }
|
||||
LOG -> OperatorLog
|
||||
MOD -> make2 { a, b -> if (b == 0.0) throw MishapDivideByZero.of(a, b) else a % b }
|
||||
else -> throw InvalidOperatorException("$pattern is not a valid operator in Arithmetic $this.")
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String arithName() {
|
||||
return "double_math";
|
||||
}
|
||||
fun make1(op: DoubleUnaryOperator) = OperatorUnary(ACCEPTS)
|
||||
{ i: Iota -> DoubleIota(op.applyAsDouble(Operator.downcast(i, HexIotaTypes.DOUBLE).double)) }
|
||||
|
||||
@Override
|
||||
public Iterable<HexPattern> opTypes() {
|
||||
return OPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operator getOperator(HexPattern pattern) {
|
||||
if (pattern.equals(ADD)) {
|
||||
return make2(Double::sum);
|
||||
} else if (pattern.equals(SUB)) {
|
||||
return make2((p, q) -> p - q);
|
||||
} else if (pattern.equals(MUL)) {
|
||||
return make2((p, q) -> p * q);
|
||||
} else if (pattern.equals(DIV)) {
|
||||
return make2((p, q) -> p / q);
|
||||
} else if (pattern.equals(ABS)) {
|
||||
return make1(Math::abs);
|
||||
} else if (pattern.equals(POW)) {
|
||||
return make2(Math::pow);
|
||||
} else if (pattern.equals(FLOOR)) {
|
||||
return make1(Math::floor);
|
||||
} else if (pattern.equals(CEIL)) {
|
||||
return make1(Math::ceil);
|
||||
} else if (pattern.equals(SIN)) {
|
||||
return make1(Math::sin);
|
||||
} else if (pattern.equals(COS)) {
|
||||
return make1(Math::cos);
|
||||
} else if (pattern.equals(TAN)) {
|
||||
return make1(Math::tan);
|
||||
} else if (pattern.equals(ARCSIN)) {
|
||||
return make1(Math::asin);
|
||||
} else if (pattern.equals(ARCCOS)) {
|
||||
return make1(Math::acos);
|
||||
} else if (pattern.equals(ARCTAN)) {
|
||||
return make1(Math::atan);
|
||||
} else if (pattern.equals(ARCTAN2)) {
|
||||
return make2(Math::atan2);
|
||||
} else if (pattern.equals(LOG)) {
|
||||
return OperatorLog.INSTANCE;
|
||||
} else if (pattern.equals(MOD)) {
|
||||
return make2((p, q) -> p % q);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static OperatorUnary make1(DoubleUnaryOperator op) {
|
||||
return new OperatorUnary(ACCEPTS, i -> new DoubleIota(op.applyAsDouble(downcast(i, DOUBLE).getDouble())));
|
||||
}
|
||||
public static OperatorBinary make2(DoubleBinaryOperator op) {
|
||||
return new OperatorBinary(ACCEPTS, (i, j) -> new DoubleIota(op.applyAsDouble(downcast(i, DOUBLE).getDouble(), downcast(j, DOUBLE).getDouble())));
|
||||
}
|
||||
fun make2(op: DoubleBinaryOperator) = OperatorBinary(ACCEPTS)
|
||||
{ i: Iota, j: Iota -> DoubleIota(op.applyAsDouble(Operator.downcast(i, HexIotaTypes.DOUBLE).double, Operator.downcast(j, HexIotaTypes.DOUBLE).double)) }
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import at.petrak.hexcasting.common.casting.arithmetic.operator.vec.OperatorUnpac
|
|||
import at.petrak.hexcasting.common.casting.arithmetic.operator.vec.OperatorVec3Delegating;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
@ -24,15 +23,17 @@ import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.*;
|
|||
public enum Vec3Arithmetic implements Arithmetic {
|
||||
INSTANCE;
|
||||
|
||||
public static final List<HexPattern> OPS;
|
||||
static {
|
||||
var ops = new ArrayList<>(DoubleArithmetic.OPS);
|
||||
ops.add(PACK);
|
||||
ops.add(UNPACK);
|
||||
ops.remove(FLOOR);
|
||||
ops.remove(CEIL);
|
||||
OPS = ops;
|
||||
}
|
||||
public static final List<HexPattern> OPS = List.of(
|
||||
PACK,
|
||||
UNPACK,
|
||||
ADD,
|
||||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
ABS,
|
||||
POW,
|
||||
MOD
|
||||
);
|
||||
|
||||
public static final IotaMultiPredicate ACCEPTS = IotaMultiPredicate.any(IotaPredicate.ofType(VEC3), IotaPredicate.ofType(DOUBLE));
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import at.petrak.hexcasting.api.casting.arithmetic.predicates.IotaPredicate;
|
|||
import at.petrak.hexcasting.api.casting.arithmetic.IterPair;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.TripleIterable;
|
||||
import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapDivideByZero;
|
||||
import at.petrak.hexcasting.common.casting.arithmetic.DoubleArithmetic;
|
||||
import at.petrak.hexcasting.api.casting.iota.DoubleIota;
|
||||
import at.petrak.hexcasting.api.casting.iota.Iota;
|
||||
|
@ -30,21 +32,25 @@ public class OperatorVec3Delegating extends Operator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<Iota> apply(@NotNull Iterable<Iota> iotas) {
|
||||
public @NotNull Iterable<Iota> apply(@NotNull Iterable<Iota> iotas) throws Mishap {
|
||||
var it = iotas.iterator();
|
||||
var left = it.next();
|
||||
var right = it.next();
|
||||
if (op != null && left instanceof Vec3Iota lh && right instanceof Vec3Iota rh) {
|
||||
return List.of(op.apply(lh.getVec3(), rh.getVec3()));
|
||||
try {
|
||||
if (op != null && left instanceof Vec3Iota lh && right instanceof Vec3Iota rh) {
|
||||
return List.of(op.apply(lh.getVec3(), rh.getVec3()));
|
||||
}
|
||||
var lh = left instanceof Vec3Iota l ? l.getVec3() : triplicate(downcast(left, DOUBLE).getDouble());
|
||||
var rh = right instanceof Vec3Iota r ? r.getVec3() : triplicate(downcast(right, DOUBLE).getDouble());
|
||||
return new TripleIterable<>(
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.x()), new DoubleIota(rh.x()))),
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.y()), new DoubleIota(rh.y()))),
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.z()), new DoubleIota(rh.z()))),
|
||||
(x, y, z) -> new Vec3Iota(new Vec3(downcast(x, DOUBLE).getDouble(), downcast(y, DOUBLE).getDouble(), downcast(z, DOUBLE).getDouble()))
|
||||
);
|
||||
} catch (MishapDivideByZero e) {
|
||||
throw MishapDivideByZero.of(left, right, e.getSuffix());
|
||||
}
|
||||
var lh = left instanceof Vec3Iota l ? l.getVec3() : triplicate(downcast(left, DOUBLE).getDouble());
|
||||
var rh = right instanceof Vec3Iota r ? r.getVec3() : triplicate(downcast(right, DOUBLE).getDouble());
|
||||
return new TripleIterable<>(
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.x()), new DoubleIota(rh.x()))),
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.y()), new DoubleIota(rh.y()))),
|
||||
fb.apply(new IterPair<>(new DoubleIota(lh.z()), new DoubleIota(rh.z()))),
|
||||
(x, y, z) -> new Vec3Iota(new Vec3(downcast(x, DOUBLE).getDouble(), downcast(y, DOUBLE).getDouble(), downcast(z, DOUBLE).getDouble()))
|
||||
);
|
||||
}
|
||||
|
||||
public static Vec3 triplicate(double in) {
|
||||
|
|
Loading…
Reference in a new issue