heat/cool prediction: fixed embarassing off-by-1 bug! removed the "margin of error" config convering up this bug.

This commit is contained in:
Louis Hong
2024-10-29 00:47:36 -07:00
parent 475cb1c1f0
commit 1e41e5733d
6 changed files with 79 additions and 65 deletions

View File

@@ -504,15 +504,4 @@ public interface EasyGiantsFoundryConfig extends Config
) )
String generalSettings = "generalSettings"; String generalSettings = "generalSettings";
@ConfigItem(
keyName = "heatingCoolingMarginOfError",
name = "Heating/Cooling Margin of Error",
description = "The margin of error for lava/waterfall calculations to compensate for decay and overshooting.",
position = 0,
section = generalSettings
)
default int heatingCoolingBuffer()
{
return 20;
}
} }

View File

@@ -338,7 +338,7 @@ public class EasyGiantsFoundryPlugin extends Plugin
{ {
Widget title = Objects.requireNonNull(mouldParent.getChild(1)); Widget title = Objects.requireNonNull(mouldParent.getChild(1));
// not sure why, the ":" character turns into ": ," when rendered; obmitting it. // not sure why, the ":" character turns into ": ," when rendered; omitting it.
title.setText("Giants' Foundry Mould Setup <col=FFFFFF>(Score " + mouldScore + ")"); title.setText("Giants' Foundry Mould Setup <col=FFFFFF>(Score " + mouldScore + ")");
} }
} }
@@ -369,8 +369,8 @@ public class EasyGiantsFoundryPlugin extends Plugin
state.heatingCoolingState.onTick(); state.heatingCoolingState.onTick();
} }
previousHeat = event.getValue();
} }
previousHeat = event.getValue();
} }
@Subscribe @Subscribe

View File

@@ -134,7 +134,7 @@ public class FoundryOverlay3D extends Overlay
return null; return null;
} }
drawHeatingActionOverlay(graphics, stageObject); drawActionOverlay(graphics, stageObject);
Heat heat = state.getCurrentHeat(); Heat heat = state.getCurrentHeat();
Color color = getObjectColor(stage, heat); Color color = getObjectColor(stage, heat);
@@ -155,11 +155,11 @@ public class FoundryOverlay3D extends Overlay
if (state.heatingCoolingState.isCooling()) if (state.heatingCoolingState.isCooling())
{ {
drawHeatingActionOverlay(graphics, waterfall, false); drawHeatingCoolingOverlay(graphics, waterfall);
} }
if (state.heatingCoolingState.isHeating()) if (state.heatingCoolingState.isHeating())
{ {
drawHeatingActionOverlay(graphics, lavaPool, true); drawHeatingCoolingOverlay(graphics, lavaPool);
} }
@@ -192,10 +192,10 @@ public class FoundryOverlay3D extends Overlay
modelOutlineRenderer.drawOutline(stageObject, config.borderThickness(), _color, config.borderFeather()); modelOutlineRenderer.drawOutline(stageObject, config.borderThickness(), _color, config.borderFeather());
} }
private void drawHeatingActionOverlay( private void drawHeatingCoolingOverlay(
Graphics2D graphics, Graphics2D graphics,
GameObject stageObject, GameObject stageObject
boolean isLava /* and not cooling */) )
{ {
if (!config.drawLavaWaterInfoOverlay()) if (!config.drawLavaWaterInfoOverlay())
{ {
@@ -208,22 +208,10 @@ public class FoundryOverlay3D extends Overlay
} }
String text; String text;
if (isLava) text = String.format("%d %s",
{ state.heatingCoolingState.getRemainingDuration(),
// %d heats or %d dunks state.heatingCoolingState.getActionName()
text = String.format("%d %s", );
state.heatingCoolingState.getRemainingDuration(),
state.heatingCoolingState.getActionName()
);
}
else
{
// %d cools
text = String.format("%d %s",
state.heatingCoolingState.getRemainingDuration(),
state.heatingCoolingState.getActionName()
);
}
LocalPoint stageLoc = stageObject.getLocalLocation(); LocalPoint stageLoc = stageObject.getLocalLocation();
stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY()); stageLoc = new LocalPoint(stageLoc.getX(), stageLoc.getY());
@@ -437,7 +425,7 @@ public class FoundryOverlay3D extends Overlay
} }
} }
private void drawHeatingActionOverlay(Graphics2D graphics, GameObject gameObject) private void drawActionOverlay(Graphics2D graphics, GameObject gameObject)
{ {
int actionsLeft = state.getActionsLeftInStage(); int actionsLeft = state.getActionsLeftInStage();
int heatLeft = state.getActionsForHeatLevel(); int heatLeft = state.getActionsForHeatLevel();

View File

@@ -78,6 +78,13 @@ public class HeatActionSolver
{ {
/** /**
* <b>Warning:</b> this method prefers overshooting goal. For example, if goal is 957,
* it will return index that reaches >957.<br>
* This may be desirable if we're aiming to heat over range minimum,
* but undesirable when cooling below range maximum; make sure to -1 the index if so.
*
*
*
* @param goal the desired heat destination * @param goal the desired heat destination
* @param init_dx1 initial speed of heating/cooling. currently 7 for heat/cool, 27 for dunk/quench. * @param init_dx1 initial speed of heating/cooling. currently 7 for heat/cool, 27 for dunk/quench.
* @param dx2_offset bonus acceleration. currently, 0 for heat/cool, 2 for dunk/quench. * @param dx2_offset bonus acceleration. currently, 0 for heat/cool, 2 for dunk/quench.

View File

@@ -113,26 +113,32 @@ public class HeatActionStateMachine
*/ */
public void calculateEstimates() public void calculateEstimates()
{ {
// 0: left/min 1: right/max
int[] range = State.getCurrentHeatRange(); int[] range = State.getCurrentHeatRange();
int stageMin = range[0];
int stageMax = range[1];
Stage stage = State.getCurrentStage(); Stage stage = State.getCurrentStage();
int actionsLeft = State.getActionsLeftInStage(); int actionsLeft = State.getActionsLeftInStage();
int actionsLeft_DeltaHeat = actionsLeft * stage.getHeatChange(); int actionsLeft_DeltaHeat = (actionsLeft+1) * stage.getHeatChange();
if (isHeating()) if (isHeating())
{ {
if (stage.isHeating()) if (stage.isHeating())
{ {
GoalHeat = Math.max(range[0] + Config.heatingCoolingBuffer(), range[1] - actionsLeft_DeltaHeat); GoalHeat = Math.max(stageMin, stageMax - actionsLeft_DeltaHeat);
if (StartingHeat < GoalHeat) if (StartingHeat < GoalHeat)
{ {
EstimatedDuration = HeatActionSolver.findDx0Index( int duration = HeatActionSolver.findDx0Index(
GoalHeat - StartingHeat, GoalHeat - StartingHeat,
Velocity, AccelerationBonus); Velocity, AccelerationBonus
);
GoalHeat += EstimatedDuration / 2; // compensate for decay during heating GoalHeat += duration / 2;
EstimatedDuration = HeatActionSolver.findDx0Index( EstimatedDuration = HeatActionSolver.findDx0Index(
GoalHeat - StartingHeat, GoalHeat - StartingHeat,
Velocity, AccelerationBonus); Velocity, AccelerationBonus
);
} }
else // overheating else // overheating
{ {
@@ -141,13 +147,21 @@ public class HeatActionStateMachine
} }
else // is cooling else // is cooling
{ {
GoalHeat = Math.min(range[1] - Config.heatingCoolingBuffer(), range[0] - actionsLeft_DeltaHeat); // actionsLeft_DeltaHeat is negative here
GoalHeat = Math.min(stageMax, stageMin - actionsLeft_DeltaHeat);
if (StartingHeat < GoalHeat) if (StartingHeat < GoalHeat)
{ {
int duration = HeatActionSolver.findDx0Index(
GoalHeat - StartingHeat,
Velocity, AccelerationBonus
) - 1;
GoalHeat -= duration / 2;
EstimatedDuration = HeatActionSolver.findDx0Index( EstimatedDuration = HeatActionSolver.findDx0Index(
GoalHeat - StartingHeat, GoalHeat - StartingHeat,
Velocity, AccelerationBonus Velocity, AccelerationBonus
); ) - 1;
} }
else // cold enough else // cold enough
{ {
@@ -157,11 +171,39 @@ public class HeatActionStateMachine
} }
else if (isCooling()) else if (isCooling())
{ {
if (stage.isCooling()) if (stage.isHeating()) {
{ GoalHeat = Math.max(stageMin, stageMax - actionsLeft_DeltaHeat);
GoalHeat = Math.max(range[1] - Config.heatingCoolingBuffer(), range[0] + actionsLeft_DeltaHeat); if (StartingHeat > GoalHeat)
{
int duration = HeatActionSolver.findDx0Index(
StartingHeat - GoalHeat,
Math.abs(Velocity), Math.abs(AccelerationBonus)
) - 1;
GoalHeat += duration / 2;
EstimatedDuration = HeatActionSolver.findDx0Index(
(StartingHeat - GoalHeat),
Math.abs(Velocity), Math.abs(AccelerationBonus)
) - 1;
}
else
{
EstimatedDuration = 0;
}
}
// Heating Stage
else {
GoalHeat = Math.max(stageMax, stageMin + actionsLeft_DeltaHeat);
if (StartingHeat > GoalHeat) // too hot if (StartingHeat > GoalHeat) // too hot
{ {
int duration = HeatActionSolver.findDx0Index(
StartingHeat - GoalHeat,
Math.abs(Velocity), Math.abs(AccelerationBonus)
);
GoalHeat -= duration / 2;
EstimatedDuration = HeatActionSolver.findDx0Index( EstimatedDuration = HeatActionSolver.findDx0Index(
StartingHeat - GoalHeat, StartingHeat - GoalHeat,
Math.abs(Velocity), Math.abs(AccelerationBonus) Math.abs(Velocity), Math.abs(AccelerationBonus)
@@ -172,21 +214,7 @@ public class HeatActionStateMachine
EstimatedDuration = 0; EstimatedDuration = 0;
} }
} }
else // Heating Stage
{
GoalHeat = Math.max(range[0] + Config.heatingCoolingBuffer(), range[1] - actionsLeft_DeltaHeat);
if (StartingHeat > GoalHeat)
{
EstimatedDuration = HeatActionSolver.findDx0Index(
(StartingHeat - GoalHeat),
Math.abs(Velocity), Math.abs(AccelerationBonus)
);
}
else
{
EstimatedDuration = 0;
}
}
} }
} }

View File

@@ -90,7 +90,7 @@ public class HeatSolverTest
for (int i = 0; i < answer_dx1.length; i++) for (int i = 0; i < answer_dx1.length; i++)
{ {
TestHeatSolver_Dx0_Helper(answer_dx0.get(i), answer_dx0.get(0), i + 1); TestHeatSolver_Dx0_Helper(answer_dx0.get(i), answer_dx0.get(0), i);
} }
} }
@@ -131,7 +131,9 @@ public class HeatSolverTest
// System.err.println( // System.err.println(
// HeatSolver.findDx0IndexContinue(1000, 7, 0)); // HeatSolver.findDx0IndexContinue(1000, 7, 0));
System.err.println( System.err.println(
HeatActionSolver.findDx0Index(1000, 7, 1)); HeatActionSolver.findDx0Index(957, 27, 2));
// System.err.println(
// HeatActionSolver.findDx0Index(1000, 7, 1));
} }
public void TestHeatSolver_Dx0_Helper(int dx0, int constant, int answer_index) public void TestHeatSolver_Dx0_Helper(int dx0, int constant, int answer_index)
@@ -139,7 +141,7 @@ public class HeatSolverTest
System.err.print(dx0 + "->" + HeatActionSolver.findDx0Index(dx0, constant, 0) + ","); System.err.print(dx0 + "->" + HeatActionSolver.findDx0Index(dx0, constant, 0) + ",");
// test calcDx0Index // test calcDx0Index
assertEquals("Asserting dx0 index for " + answer_index, assertEquals("Asserting dx0 for index " + answer_index,
answer_index, HeatActionSolver.findDx0Index(dx0, constant, 0)); answer_index, HeatActionSolver.findDx0Index(dx0, constant, 0));
} }