mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-08-10 17:55:44 +00:00
i spent all afternoon in a hole
This commit is contained in:
parent
e42bb12984
commit
0074c20f91
@ -12,6 +12,10 @@
|
||||
* When cutting down hemp, willows, and other NTM double plants, only the top part will be cut off, no matter where the thresher touches it
|
||||
* Can also harvest items from sunflowers and tall grass without breaking the blocks
|
||||
* Can also handle tall plants like cacti and sugar cane
|
||||
* New big-ass tank
|
||||
* Successor to the BAT9k
|
||||
* Larger footprint, way more storage space
|
||||
* Needs to be placed on a proper foundation or else it'll sink into the ground
|
||||
|
||||
## Changed
|
||||
* RoR graphs can now have their min and max bounds set to a fixed number
|
||||
@ -29,7 +33,7 @@
|
||||
* Increased the yield of lye from wood ash
|
||||
* All fluid tanks larger than barrels now have dynamic IO speed instead of providing their entire contents instantly
|
||||
* Tank fill will slow down the fuller the tank becomes, tank drain also slow downs as it gets emptier
|
||||
* This means that multiple tanks in IO mode in the same network will still ping pong, but instead of firing their entire contents over the network, they will even out
|
||||
* This means that multiple tanks in IO mode in the same network will still ping pong, but only a small portion of fluid will be "lost" (i.e. invisible due to subtick transfer operations)
|
||||
* The stinger is now classified as a special weapon
|
||||
* The carbine can now take a scope
|
||||
* The battery socket now renders supports when a block is placed on top of it, allowing somewhat aesthetic stacking of sockets
|
||||
|
||||
@ -778,6 +778,7 @@ public class ModBlocks {
|
||||
public static Block radio_torch_reader;
|
||||
public static Block radio_torch_controller;
|
||||
public static Block radio_telex;
|
||||
public static Block radio_autocal;
|
||||
public static Block oc_cable_paintable;
|
||||
|
||||
public static Block conveyor;
|
||||
@ -1894,6 +1895,7 @@ public class ModBlocks {
|
||||
radio_torch_reader = new RadioTorchReader().setBlockName("radio_torch_reader").setHardness(0.1F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":rtty_reader");
|
||||
radio_torch_controller = new RadioTorchController().setBlockName("radio_torch_controller").setHardness(0.1F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":rtty_controller");
|
||||
radio_telex = new RadioTelex().setBlockName("radio_telex").setHardness(3F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":radio_telex");
|
||||
radio_autocal = new RadioAUTOCAL().setBlockName("radio_autocal").setHardness(3F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":block_steel");
|
||||
|
||||
conveyor = new BlockConveyor().setBlockName("conveyor").setHardness(2.0F).setResistance(2.0F).setCreativeTab(null).setBlockTextureName(RefStrings.MODID + ":conveyor");
|
||||
conveyor_express = new BlockConveyorExpress().setBlockName("conveyor_express").setHardness(2.0F).setResistance(2.0F).setCreativeTab(null).setBlockTextureName(RefStrings.MODID + ":conveyor_express");
|
||||
@ -3175,6 +3177,7 @@ public class ModBlocks {
|
||||
register(radio_torch_reader);
|
||||
register(radio_torch_controller);
|
||||
register(radio_telex);
|
||||
register(radio_autocal);
|
||||
|
||||
register(crane_extractor);
|
||||
register(crane_inserter);
|
||||
|
||||
@ -27,6 +27,7 @@ import net.minecraftforge.common.util.ForgeDirection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class MachineBigAssTank9000 extends BlockDummyable implements IPersistentInfoProvider {
|
||||
|
||||
public MachineBigAssTank9000(Material mat) {
|
||||
|
||||
25
src/main/java/com/hbm/blocks/network/RadioAUTOCAL.java
Normal file
25
src/main/java/com/hbm/blocks/network/RadioAUTOCAL.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.hbm.blocks.network;
|
||||
|
||||
import com.hbm.blocks.machine.BlockMachineBase;
|
||||
import com.hbm.tileentity.network.TileEntityRadioAUTOCAL;
|
||||
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class RadioAUTOCAL extends BlockMachineBase {
|
||||
|
||||
public RadioAUTOCAL() {
|
||||
super(Material.iron, 0);
|
||||
this.rotatable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta) {
|
||||
return new TileEntityRadioAUTOCAL();
|
||||
}
|
||||
|
||||
@Override public int getRenderType(){ return -1; }
|
||||
@Override public boolean isOpaqueCube() { return false; }
|
||||
@Override public boolean renderAsNormalBlock() { return false; }
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class GeneralConfig {
|
||||
preferredOutputMod = CommonConfig.createConfigStringList(config,CATEGORY_GENERAL,"1.42_preferredOutputMod",
|
||||
"The mod which is preferred as output when certain machines autogenerate recipes. Currently used for the shredder", new String[] {RefStrings.MODID});
|
||||
enableLoadScreenReplacement = config.get(CATEGORY_GENERAL, "1.43_enableLoadScreenReplacement", true, "Tries to replace the vanilla load screen with the 'tip of the day' one, may clash with other mods trying to do the same.").getBoolean(true);
|
||||
enableMachineGravity = config.get(CATEGORY_GENERAL, "1.44_enableMachineGravity", true, "Requires large large machines to have a proper foundation, or else they tilt and break. Independent from the 528 version of this config, which does the same, but only works with 528 enabled.").getBoolean(false);
|
||||
enableMachineGravity = config.get(CATEGORY_GENERAL, "1.44_enableMachineGravity", false, "Requires large large machines to have a proper foundation, or else they tilt and break. Independent from the 528 version of this config, which does the same, but only works with 528 enabled.").getBoolean(false);
|
||||
enableExpensiveMode = config.get(CATEGORY_GENERAL, "1.99_enableExpensiveMode", false, "It does what the name implies.").getBoolean(false);
|
||||
|
||||
final String CATEGORY_528 = CommonConfig.CATEGORY_528;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.hbm.inventory.gui;
|
||||
|
||||
import com.hbm.util.Calculator;
|
||||
import com.hbm.util.Tuple;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
@ -12,8 +13,6 @@ import java.math.MathContext;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.Locale;
|
||||
import java.util.Stack;
|
||||
|
||||
public class GUICalculator extends GuiScreen {
|
||||
private int xSize = 220;
|
||||
@ -58,7 +57,7 @@ public class GUICalculator extends GuiScreen {
|
||||
selectedHist = -1;
|
||||
} else {
|
||||
try {
|
||||
double result = evaluateExpression(input);
|
||||
double result = Calculator.evaluateExpression(input);
|
||||
history.addFirst(new Tuple.Pair<String,Double>(input, result));
|
||||
if (history.size() > maxHistory) history.removeLast();
|
||||
String plainStringRepresentation = (new BigDecimal(result, MathContext.DECIMAL64)).toPlainString();
|
||||
@ -85,7 +84,7 @@ public class GUICalculator extends GuiScreen {
|
||||
}
|
||||
|
||||
try {
|
||||
latestResult = Double.toString(evaluateExpression(input));
|
||||
latestResult = Double.toString(Calculator.evaluateExpression(input));
|
||||
} catch (Exception e) { latestResult = e.toString(); }
|
||||
}
|
||||
|
||||
@ -116,203 +115,4 @@ public class GUICalculator extends GuiScreen {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mathematically evaluates user-inputted strings<br>
|
||||
* It is recommended to catch all exceptions when using this
|
||||
*/
|
||||
public static double evaluateExpression(String input) {
|
||||
if (input.contains("^")) input = preEvaluatePower(input);
|
||||
|
||||
char[] tokens = input.toCharArray();
|
||||
Stack<Double> values = new Stack<>();
|
||||
Stack<String> operators = new Stack<>();
|
||||
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i] == ' ') continue;
|
||||
|
||||
if (tokens[i] >= '0' && tokens[i] <= '9' || tokens[i] == '.' || (tokens[i] == '-' && (i == 0 || "+-*/^(".contains(String.valueOf(tokens[i - 1]))))) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
if (tokens[i] == '-') {
|
||||
buffer.append('-'); // for negative numbers
|
||||
i++;
|
||||
}
|
||||
while (i < tokens.length && (tokens[i] >= '0' && tokens[i] <= '9' || tokens[i] == '.')) buffer.append(tokens[i++]);
|
||||
values.push(Double.parseDouble(buffer.toString()));
|
||||
i--;
|
||||
} else if (tokens[i] == '(') operators.push(Character.toString(tokens[i]));
|
||||
else if (tokens[i] == ')') {
|
||||
while (!operators.isEmpty() && operators.peek().charAt(0) != '(')
|
||||
values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
operators.pop();
|
||||
if (!operators.isEmpty() && operators.peek().length() > 1)
|
||||
values.push(evaluateFunction(operators.pop(), values.pop()));
|
||||
} else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*' || tokens[i] == '/' || tokens[i] == '^') {
|
||||
while (!operators.isEmpty() && hasPrecedence(String.valueOf(tokens[i]), operators.peek()))
|
||||
values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
operators.push(Character.toString(tokens[i]));
|
||||
} else if (tokens[i] == '!') {
|
||||
values.push((double) factorial((int) Math.round(values.pop())));
|
||||
}else if (tokens[i] >= 'A' && tokens[i] <= 'Z' || tokens[i] >= 'a' && tokens[i] <= 'z') {
|
||||
StringBuilder charBuffer = new StringBuilder();
|
||||
while (i < tokens.length && (tokens[i] >= 'A' && tokens[i] <= 'Z' || tokens[i] >= 'a' && tokens[i] <= 'z'))
|
||||
charBuffer.append(tokens[i++]);
|
||||
String string = charBuffer.toString();
|
||||
if (string.equalsIgnoreCase("pi")) values.push(Math.PI);
|
||||
else if (string.equalsIgnoreCase("e")) values.push(Math.E);
|
||||
else operators.push(string.toLowerCase(Locale.ROOT));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// if the expression is correctly formatted, no function is remaining
|
||||
while (!operators.empty()) values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
|
||||
return values.pop();
|
||||
}
|
||||
|
||||
private static double evaluateOperator(char operator, double x, double y) {
|
||||
switch (operator) {
|
||||
case '+': return y + x;
|
||||
case '-': return y - x;
|
||||
case '*': return y * x;
|
||||
case '/': return y / x;
|
||||
|
||||
case '^': return Math.pow(y, x); // should not happen here, but oh well
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static double evaluateFunction(String function, double x) {
|
||||
switch (function) {
|
||||
case "sqrt": return Math.sqrt(x);
|
||||
|
||||
case "sin": return Math.sin(x);
|
||||
case "cos": return Math.cos(x);
|
||||
case "tan": return Math.tan(x);
|
||||
case "asin": return Math.asin(x);
|
||||
case "acos": return Math.acos(x);
|
||||
case "atan": return Math.atan(x);
|
||||
|
||||
case "log": return Math.log10(x);
|
||||
case "ln": return Math.log(x);
|
||||
|
||||
case "ceil": return Math.ceil(x);
|
||||
case "floor": return Math.floor(x);
|
||||
case "round": return Math.round(x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns whether {@code second} has precedence over {@code first} */
|
||||
private static boolean hasPrecedence(String first, String second) {
|
||||
if (second.length() > 1) return false;
|
||||
|
||||
char firstChar = first.charAt(0);
|
||||
char secondChar = second.charAt(0);
|
||||
|
||||
if (secondChar == '(' || secondChar == ')') return false;
|
||||
else return (firstChar != '*' && firstChar != '/' && firstChar != '^') || (secondChar != '+' && secondChar != '-');
|
||||
}
|
||||
|
||||
/** Returns the input with all powers evaluated */
|
||||
private static String preEvaluatePower(String input) {
|
||||
do {
|
||||
int powerOperatorIndex = input.lastIndexOf('^');
|
||||
|
||||
// find base
|
||||
boolean previousTokenIsParentheses = input.charAt(powerOperatorIndex - 1) == ')';
|
||||
int parenthesesDepth = previousTokenIsParentheses ? 1 : 0;
|
||||
int baseExpressionStart = previousTokenIsParentheses ? powerOperatorIndex - 2 : powerOperatorIndex - 1;
|
||||
baseLoop:
|
||||
for (; baseExpressionStart >= 0; baseExpressionStart--) { // search backwards
|
||||
switch (input.charAt(baseExpressionStart)) {
|
||||
case ')':
|
||||
if (previousTokenIsParentheses) parenthesesDepth++;
|
||||
else break baseLoop;
|
||||
break;
|
||||
case '(':
|
||||
if (previousTokenIsParentheses && parenthesesDepth > 0) parenthesesDepth--;
|
||||
else break baseLoop;
|
||||
break;
|
||||
case '+': case '-': case '*': case '/': case '^':
|
||||
if (parenthesesDepth == 0) break baseLoop;
|
||||
}
|
||||
}
|
||||
baseExpressionStart++; // go one token forward again
|
||||
if (parenthesesDepth > 0) throw new IllegalArgumentException("Incomplete parentheses");
|
||||
|
||||
// find exponent
|
||||
boolean nextTokenIsParentheses = input.charAt(powerOperatorIndex + 1) == '(';
|
||||
parenthesesDepth = nextTokenIsParentheses ? 1 : 0;
|
||||
int exponentExpressionEnd = nextTokenIsParentheses ? powerOperatorIndex + 2 : powerOperatorIndex + 1;
|
||||
exponentLoop:
|
||||
for (; exponentExpressionEnd < input.length(); exponentExpressionEnd++) {
|
||||
switch (input.charAt(exponentExpressionEnd)) {
|
||||
case '(':
|
||||
if (nextTokenIsParentheses) parenthesesDepth++;
|
||||
else break exponentLoop;
|
||||
break;
|
||||
case ')':
|
||||
if (nextTokenIsParentheses && parenthesesDepth > 0) parenthesesDepth--;
|
||||
else break exponentLoop;
|
||||
break;
|
||||
case '+': case '-': case '*': case '/': case '^':
|
||||
if (parenthesesDepth == 0) break exponentLoop;
|
||||
}
|
||||
}
|
||||
if (parenthesesDepth > 0) throw new IllegalArgumentException("Incomplete parentheses");
|
||||
|
||||
double base = evaluateExpression(input.substring(baseExpressionStart, powerOperatorIndex));
|
||||
double exponent = evaluateExpression(input.substring(powerOperatorIndex + 1, exponentExpressionEnd));
|
||||
double result = Math.pow(base, exponent);
|
||||
// use big decimal to avoid scientific notation messing with the calculation
|
||||
input = input.substring(0, baseExpressionStart) + (new BigDecimal(result, MathContext.DECIMAL64)).toPlainString() + input.substring(exponentExpressionEnd);
|
||||
} while (input.contains("^"));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
// TODO Maybe switch the whole calculator to using BigInteger/BigDecimal?
|
||||
// SplitRecursive algorithm
|
||||
private static int factorial(int in) {
|
||||
if (in < 0) throw new IllegalArgumentException("Factorial needs n >= 0");
|
||||
if (in < 2) return 1;
|
||||
int p = 1, r = 1;
|
||||
factorialCurrentN = 1;
|
||||
int h = 0, shift = 0, high = 1;
|
||||
int log2n = log2(in);
|
||||
while (h != in) {
|
||||
shift += h;
|
||||
h = in >> log2n--;
|
||||
int len = high;
|
||||
high = (h - 1) | 1;
|
||||
len = (high - len) / 2;
|
||||
|
||||
if (len > 0) {
|
||||
p *= factorialProduct(len);
|
||||
r *= p;
|
||||
}
|
||||
}
|
||||
|
||||
return r << shift;
|
||||
}
|
||||
|
||||
private static int factorialCurrentN;
|
||||
|
||||
private static int factorialProduct(int in) {
|
||||
int m = in / 2;
|
||||
if (m == 0) return factorialCurrentN += 2;
|
||||
if (in == 2) return (factorialCurrentN += 2) * (factorialCurrentN += 2);
|
||||
return factorialProduct(in - m) * factorialProduct(m);
|
||||
}
|
||||
|
||||
private static int log2(int in) {
|
||||
int log = 0;
|
||||
if((in & 0xffff0000) != 0) { in >>>= 16; log = 16; }
|
||||
if(in >= 256) { in >>>= 8; log += 8; }
|
||||
if(in >= 16) { in >>>= 4; log += 4; }
|
||||
if(in >= 4) { in >>>= 2; log += 2; }
|
||||
return log + (in >>> 1);
|
||||
}
|
||||
}
|
||||
|
||||
34
src/main/java/com/hbm/module/IParse.java
Normal file
34
src/main/java/com/hbm/module/IParse.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.hbm.module;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IParse {
|
||||
|
||||
public EnumStatementReturn eval(ParseContext ctx, String line);
|
||||
|
||||
public static class ParseContext {
|
||||
public World world;
|
||||
public NBTTagCompound variables;
|
||||
public HashMap<String, Integer> jmp;
|
||||
|
||||
public Object buffer;
|
||||
public int clockSpeed;
|
||||
|
||||
public ParseContext(World world, NBTTagCompound variables, HashMap<String, Integer> jmp) {
|
||||
this.world = world;
|
||||
this.variables = variables;
|
||||
this.jmp = jmp;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum EnumStatementReturn {
|
||||
OK,
|
||||
UNRECOGNIZED_COMMAND,
|
||||
PARAMETER_ERROR,
|
||||
END_TICK,
|
||||
UNDEFINED
|
||||
}
|
||||
}
|
||||
9
src/main/java/com/hbm/module/ParseMSES1.java
Normal file
9
src/main/java/com/hbm/module/ParseMSES1.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.hbm.module;
|
||||
|
||||
public class ParseMSES1 implements IParse {
|
||||
|
||||
@Override
|
||||
public EnumStatementReturn eval(ParseContext ctx, String line) {
|
||||
return EnumStatementReturn.OK;
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,11 @@
|
||||
package com.hbm.tileentity;
|
||||
|
||||
import net.minecraftforge.fluids.FluidTank;
|
||||
|
||||
public abstract class TileEntityTickingBase extends TileEntityLoadedBase {
|
||||
|
||||
public TileEntityTickingBase() { }
|
||||
|
||||
public abstract String getInventoryName();
|
||||
|
||||
public int getGaugeScaled(int i, FluidTank tank) {
|
||||
return tank.getFluidAmount() * i / tank.getCapacity();
|
||||
}
|
||||
|
||||
//abstracting this method forces child classes to implement it
|
||||
//so i don't have to remember the fucking method name
|
||||
//was it update? onUpdate? updateTile? did it have any args?
|
||||
|
||||
@ -7,6 +7,7 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
|
||||
@Deprecated
|
||||
public class TileEntityMachineBAT9000 extends TileEntityBarrel {
|
||||
|
||||
public TileEntityMachineBAT9000() {
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package com.hbm.tileentity.network;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.hbm.tileentity.TileEntityTickingBase;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class TileEntityRadioAUTOCAL extends TileEntityTickingBase {
|
||||
|
||||
public boolean isOn = false;
|
||||
|
||||
public Object buffer;
|
||||
public NBTTagCompound variables;
|
||||
public String[] script;
|
||||
public HashMap<String, Integer> jmp = new HashMap();
|
||||
|
||||
@Override
|
||||
public String getInventoryName() {
|
||||
return "container.autocal";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntity() {
|
||||
|
||||
if(!worldObj.isRemote) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ByteBuf buf) {
|
||||
super.serialize(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(ByteBuf buf) {
|
||||
super.deserialize(buf);
|
||||
}
|
||||
}
|
||||
208
src/main/java/com/hbm/util/Calculator.java
Normal file
208
src/main/java/com/hbm/util/Calculator.java
Normal file
@ -0,0 +1,208 @@
|
||||
package com.hbm.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.Locale;
|
||||
import java.util.Stack;
|
||||
|
||||
public class Calculator {
|
||||
|
||||
/**
|
||||
* Mathematically evaluates user-inputted strings<br>
|
||||
* It is recommended to catch all exceptions when using this
|
||||
*/
|
||||
public static double evaluateExpression(String input) {
|
||||
if (input.contains("^")) input = preEvaluatePower(input);
|
||||
|
||||
char[] tokens = input.toCharArray();
|
||||
Stack<Double> values = new Stack<>();
|
||||
Stack<String> operators = new Stack<>();
|
||||
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i] == ' ') continue;
|
||||
|
||||
if (tokens[i] >= '0' && tokens[i] <= '9' || tokens[i] == '.' || (tokens[i] == '-' && (i == 0 || "+-*/^(".contains(String.valueOf(tokens[i - 1]))))) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
if (tokens[i] == '-') {
|
||||
buffer.append('-'); // for negative numbers
|
||||
i++;
|
||||
}
|
||||
while (i < tokens.length && (tokens[i] >= '0' && tokens[i] <= '9' || tokens[i] == '.')) buffer.append(tokens[i++]);
|
||||
values.push(Double.parseDouble(buffer.toString()));
|
||||
i--;
|
||||
} else if (tokens[i] == '(') operators.push(Character.toString(tokens[i]));
|
||||
else if (tokens[i] == ')') {
|
||||
while (!operators.isEmpty() && operators.peek().charAt(0) != '(')
|
||||
values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
operators.pop();
|
||||
if (!operators.isEmpty() && operators.peek().length() > 1)
|
||||
values.push(evaluateFunction(operators.pop(), values.pop()));
|
||||
} else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*' || tokens[i] == '/' || tokens[i] == '^') {
|
||||
while (!operators.isEmpty() && hasPrecedence(String.valueOf(tokens[i]), operators.peek()))
|
||||
values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
operators.push(Character.toString(tokens[i]));
|
||||
} else if (tokens[i] == '!') {
|
||||
values.push((double) factorial((int) Math.round(values.pop())));
|
||||
}else if (tokens[i] >= 'A' && tokens[i] <= 'Z' || tokens[i] >= 'a' && tokens[i] <= 'z') {
|
||||
StringBuilder charBuffer = new StringBuilder();
|
||||
while (i < tokens.length && (tokens[i] >= 'A' && tokens[i] <= 'Z' || tokens[i] >= 'a' && tokens[i] <= 'z'))
|
||||
charBuffer.append(tokens[i++]);
|
||||
String string = charBuffer.toString();
|
||||
if (string.equalsIgnoreCase("pi")) values.push(Math.PI);
|
||||
else if (string.equalsIgnoreCase("e")) values.push(Math.E);
|
||||
else operators.push(string.toLowerCase(Locale.ROOT));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// if the expression is correctly formatted, no function is remaining
|
||||
while (!operators.empty()) values.push(evaluateOperator(operators.pop().charAt(0), values.pop(), values.pop()));
|
||||
|
||||
return values.pop();
|
||||
}
|
||||
|
||||
private static double evaluateOperator(char operator, double x, double y) {
|
||||
switch (operator) {
|
||||
case '+': return y + x;
|
||||
case '-': return y - x;
|
||||
case '*': return y * x;
|
||||
case '/': return y / x;
|
||||
|
||||
case '^': return Math.pow(y, x); // should not happen here, but oh well
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static double evaluateFunction(String function, double x) {
|
||||
switch (function) {
|
||||
case "sqrt": return Math.sqrt(x);
|
||||
|
||||
case "sin": return Math.sin(x);
|
||||
case "cos": return Math.cos(x);
|
||||
case "tan": return Math.tan(x);
|
||||
case "asin": return Math.asin(x);
|
||||
case "acos": return Math.acos(x);
|
||||
case "atan": return Math.atan(x);
|
||||
|
||||
case "log": return Math.log10(x);
|
||||
case "ln": return Math.log(x);
|
||||
|
||||
case "ceil": return Math.ceil(x);
|
||||
case "floor": return Math.floor(x);
|
||||
case "round": return Math.round(x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns whether {@code second} has precedence over {@code first} */
|
||||
private static boolean hasPrecedence(String first, String second) {
|
||||
if (second.length() > 1) return false;
|
||||
|
||||
char firstChar = first.charAt(0);
|
||||
char secondChar = second.charAt(0);
|
||||
|
||||
if (secondChar == '(' || secondChar == ')') return false;
|
||||
else return (firstChar != '*' && firstChar != '/' && firstChar != '^') || (secondChar != '+' && secondChar != '-');
|
||||
}
|
||||
|
||||
/** Returns the input with all powers evaluated */
|
||||
private static String preEvaluatePower(String input) {
|
||||
do {
|
||||
int powerOperatorIndex = input.lastIndexOf('^');
|
||||
|
||||
// find base
|
||||
boolean previousTokenIsParentheses = input.charAt(powerOperatorIndex - 1) == ')';
|
||||
int parenthesesDepth = previousTokenIsParentheses ? 1 : 0;
|
||||
int baseExpressionStart = previousTokenIsParentheses ? powerOperatorIndex - 2 : powerOperatorIndex - 1;
|
||||
baseLoop:
|
||||
for (; baseExpressionStart >= 0; baseExpressionStart--) { // search backwards
|
||||
switch (input.charAt(baseExpressionStart)) {
|
||||
case ')':
|
||||
if (previousTokenIsParentheses) parenthesesDepth++;
|
||||
else break baseLoop;
|
||||
break;
|
||||
case '(':
|
||||
if (previousTokenIsParentheses && parenthesesDepth > 0) parenthesesDepth--;
|
||||
else break baseLoop;
|
||||
break;
|
||||
case '+': case '-': case '*': case '/': case '^':
|
||||
if (parenthesesDepth == 0) break baseLoop;
|
||||
}
|
||||
}
|
||||
baseExpressionStart++; // go one token forward again
|
||||
if (parenthesesDepth > 0) throw new IllegalArgumentException("Incomplete parentheses");
|
||||
|
||||
// find exponent
|
||||
boolean nextTokenIsParentheses = input.charAt(powerOperatorIndex + 1) == '(';
|
||||
parenthesesDepth = nextTokenIsParentheses ? 1 : 0;
|
||||
int exponentExpressionEnd = nextTokenIsParentheses ? powerOperatorIndex + 2 : powerOperatorIndex + 1;
|
||||
exponentLoop:
|
||||
for (; exponentExpressionEnd < input.length(); exponentExpressionEnd++) {
|
||||
switch (input.charAt(exponentExpressionEnd)) {
|
||||
case '(':
|
||||
if (nextTokenIsParentheses) parenthesesDepth++;
|
||||
else break exponentLoop;
|
||||
break;
|
||||
case ')':
|
||||
if (nextTokenIsParentheses && parenthesesDepth > 0) parenthesesDepth--;
|
||||
else break exponentLoop;
|
||||
break;
|
||||
case '+': case '-': case '*': case '/': case '^':
|
||||
if (parenthesesDepth == 0) break exponentLoop;
|
||||
}
|
||||
}
|
||||
if (parenthesesDepth > 0) throw new IllegalArgumentException("Incomplete parentheses");
|
||||
|
||||
double base = evaluateExpression(input.substring(baseExpressionStart, powerOperatorIndex));
|
||||
double exponent = evaluateExpression(input.substring(powerOperatorIndex + 1, exponentExpressionEnd));
|
||||
double result = Math.pow(base, exponent);
|
||||
// use big decimal to avoid scientific notation messing with the calculation
|
||||
input = input.substring(0, baseExpressionStart) + (new BigDecimal(result, MathContext.DECIMAL64)).toPlainString() + input.substring(exponentExpressionEnd);
|
||||
} while (input.contains("^"));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
// TODO Maybe switch the whole calculator to using BigInteger/BigDecimal?
|
||||
// SplitRecursive algorithm
|
||||
private static int factorial(int in) {
|
||||
if (in < 0) throw new IllegalArgumentException("Factorial needs n >= 0");
|
||||
if (in < 2) return 1;
|
||||
int p = 1, r = 1;
|
||||
factorialCurrentN = 1;
|
||||
int h = 0, shift = 0, high = 1;
|
||||
int log2n = log2(in);
|
||||
while (h != in) {
|
||||
shift += h;
|
||||
h = in >> log2n--;
|
||||
int len = high;
|
||||
high = (h - 1) | 1;
|
||||
len = (high - len) / 2;
|
||||
|
||||
if (len > 0) {
|
||||
p *= factorialProduct(len);
|
||||
r *= p;
|
||||
}
|
||||
}
|
||||
|
||||
return r << shift;
|
||||
}
|
||||
|
||||
private static int factorialCurrentN;
|
||||
|
||||
private static int factorialProduct(int in) {
|
||||
int m = in / 2;
|
||||
if (m == 0) return factorialCurrentN += 2;
|
||||
if (in == 2) return (factorialCurrentN += 2) * (factorialCurrentN += 2);
|
||||
return factorialProduct(in - m) * factorialProduct(m);
|
||||
}
|
||||
|
||||
private static int log2(int in) {
|
||||
int log = 0;
|
||||
if((in & 0xffff0000) != 0) { in >>>= 16; log = 16; }
|
||||
if(in >= 256) { in >>>= 8; log += 8; }
|
||||
if(in >= 16) { in >>>= 4; log += 4; }
|
||||
if(in >= 4) { in >>>= 2; log += 2; }
|
||||
return log + (in >>> 1);
|
||||
}
|
||||
}
|
||||
@ -223,6 +223,7 @@ container.bat9000=Big-Ass Tank 9000
|
||||
container.battery=Energiespeicher
|
||||
container.batteryREDD=FEnSU
|
||||
container.batterySocket=Batteriesockel
|
||||
container.bigAssTank=Big-Ass Tank
|
||||
container.bombMulti=Mehrzweckbombe
|
||||
container.casingBag=Hülsentasche
|
||||
container.catalyticReformer=Katalytischer Reformer
|
||||
@ -4414,6 +4415,7 @@ tile.machine_battery_potato.name=Kartoffelbatterieblock (LEGACY)
|
||||
tile.machine_battery_redd.name=FEnSU
|
||||
tile.machine_battery_socket.name=Batteriesockel
|
||||
tile.machine_battery_socket.desc=Erlaubt es, Batterien direkt mit$dem Stromnetz zu verbinden.$Verhält sich wie ein Kabel, alle$Verbindungen sind im selben Netzwek.
|
||||
tile.machine_bigasstank.name=Big-Ass Tank
|
||||
tile.machine_boiler.name=Boiler
|
||||
tile.machine_boiler.desc=Großer Boiler zum Verdampfen von Wasser oder$Erhitzen von Öl. Benötigt externe Hitzequelle.$Wärmestransferrate: ΔT*0.1 TU/t
|
||||
tile.machine_boiler_electric_off.name=Elektrischer Ölwärmer
|
||||
|
||||
@ -624,6 +624,7 @@ container.bat9000=Big-Ass Tank 9000
|
||||
container.battery=Energy Storage
|
||||
container.batteryREDD=FEnSU
|
||||
container.batterySocket=Battery Socket
|
||||
container.bigAssTank=Big-Ass Tank
|
||||
container.bombMulti=Multi Purpose Bomb
|
||||
container.casingBag=Bullet Casing Bag
|
||||
container.catalyticReformer=Catalytic Reformer
|
||||
@ -5662,6 +5663,7 @@ tile.machine_battery_potato.name=Potato Battery Block (LEGACY)
|
||||
tile.machine_battery_redd.name=FEnSU
|
||||
tile.machine_battery_socket.name=Battery Socket
|
||||
tile.machine_battery_socket.desc=Allows battery items to be connected$to the power grid directly.$Acts as a cable, all ports are connected$to the same network.
|
||||
tile.machine_bigasstank.name=Big-Ass Tank
|
||||
tile.machine_boiler.name=Boiler
|
||||
tile.machine_boiler.desc=Large boiler that can boil water or heat up oil.$Requires external heat source.$Heat transfer rate: ΔT*0.1 TU/t
|
||||
tile.machine_boiler_electric_off.name=Electric Oil Heater
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user