Trapezoidal jumps

I haven't checked this yet, but it seems like it also reduces the
complexity (runtime) from ≈O(n^2) to ≈O(k^2 + n)
(n = number of jump curves)
(k = number of unique destinations)

The worst case, that is k = n, is still O(n^2) but generally it's much
more (scalably) performant.

Thanks Arkanic for suggesting this!
https://discord.com/channels/391020510269669376/663854113418641429/1256161815503704104

Co-authored-by: Arkanic <50847107+Arkanic@users.noreply.github.com>
This commit is contained in:
code-explorer786
2024-06-30 12:00:34 +07:00
parent c5b8133ff9
commit a5de131711
3 changed files with 53 additions and 25 deletions

View File

@@ -21,12 +21,12 @@ import mindustry.logic.LStatements.*;
import mindustry.ui.*;
public class LCanvas extends Table{
public static final int maxJumpsDrawn = 100;
private static final int invalidJump = Integer.MAX_VALUE; // terrible hack
//ew static variables
static LCanvas canvas;
private static boolean dynamicJumpHeights = false;
private static boolean coloredJumps = false;
private static boolean trapezoidalJumps = false;
public DragLayout statements;
public ScrollPane pane;
@@ -35,7 +35,6 @@ public class LCanvas extends Table{
StatementElem dragging;
StatementElem hovered;
float targetWidth;
int jumpCount = 0;
boolean privileged;
Seq<Tooltip> tooltips = new Seq<>();
@@ -114,6 +113,7 @@ public class LCanvas extends Table{
dynamicJumpHeights = Core.settings.getBool("dynamicjumpheights", false);
coloredJumps = Core.settings.getBool("coloredjumps", false);
trapezoidalJumps = Core.settings.getBool("trapezoidaljumps", false);
pane = pane(t -> {
t.center();
@@ -132,7 +132,6 @@ public class LCanvas extends Table{
@Override
public void draw(){
jumpCount = 0;
super.draw();
}
@@ -205,6 +204,8 @@ public class LCanvas extends Table{
boolean invalidated;
public Group jumps = new WidgetGroup();
private Seq<JumpCurve> processedJumps = new Seq<JumpCurve>();
private IntMap<JumpCurve> reprBefore = new IntMap<JumpCurve>();
private IntMap<JumpCurve> reprAfter = new IntMap<JumpCurve>();
public boolean updateJumpHeights = true;
private Color[] jumpColors = new Color[LExecutor.maxInstructions];
@@ -321,14 +322,32 @@ public class LCanvas extends Table{
private void setJumpHeights(){
SnapshotSeq<Element> jumpsChildren = jumps.getChildren();
processedJumps.clear();
jumpsChildren.each(e -> {
if(e instanceof JumpCurve e2){
if(trapezoidalJumps){
reprBefore.clear();
reprAfter.clear();
jumpsChildren.each(e -> {
if(!(e instanceof JumpCurve e2)) return;
e2.prepareHeight();
if(e2.jumpUIBegin != invalidJump){
processedJumps.add(e2);
if(e2.jumpUIBegin == invalidJump) return;
if(e2.flipped){
JumpCurve prev = reprAfter.get(e2.jumpUIBegin);
if(prev != null && prev.jumpUIEnd >= e2.jumpUIEnd) return;
reprAfter.put(e2.jumpUIBegin, e2);
}else{
JumpCurve prev = reprBefore.get(e2.jumpUIEnd);
if(prev != null && prev.jumpUIBegin <= e2.jumpUIBegin) return;
reprBefore.put(e2.jumpUIEnd, e2);
}
}
});
});
processedJumps.add(reprBefore.values().toArray());
processedJumps.add(reprAfter.values().toArray());
} else {
jumpsChildren.each(e -> {
if(!(e instanceof JumpCurve e2)) return;
e2.prepareHeight();
processedJumps.add(e2);
});
}
processedJumps.sort((a,b) -> a.jumpUIBegin - b.jumpUIBegin);
Seq<JumpCurve> occupiers = Pools.obtain(Seq.class, Seq<JumpCurve>::new);
@@ -351,6 +370,15 @@ public class LCanvas extends Table{
occupiers.clear();
Pools.free(occupied);
Pools.free(occupiers);
if(trapezoidalJumps){
jumpsChildren.each(e -> {
if(!(e instanceof JumpCurve e2)) return;
if(e2.jumpUIBegin == invalidJump) return;
e2.predHeight = e2.flipped ? reprAfter.get(e2.jumpUIBegin).predHeight : reprBefore.get(e2.jumpUIEnd).predHeight;
e2.markedDone = true;
});
}
}
private int getJumpHeight(int index, Seq<JumpCurve> occupiers, Bits occupied){
@@ -661,8 +689,9 @@ public class LCanvas extends Table{
public int predHeight = 0;
public boolean markedDone = false;
public int jumpUIBegin = 0, jumpUIEnd = 0;
public boolean flipped = false;
private float uiHeight = 100f;
private float uiHeight = 60f;
public JumpCurve(JumpButton button){
this.button = button;
@@ -679,12 +708,6 @@ public class LCanvas extends Table{
@Override
public void draw(){
canvas.jumpCount ++;
if(canvas.jumpCount > maxJumpsDrawn && !button.selecting && !button.listener.isOver()){
return;
}
Element hover = button.to.get() == null && button.selecting ? canvas.hovered : button.to.get();
boolean draw = false;
Vec2 t = Tmp.v1, r = Tmp.v2;
@@ -723,18 +746,19 @@ public class LCanvas extends Table{
Draw.color(button.color);
// exponential smoothing
uiHeight = Mathf.lerp(100f + 100f * (float) predHeight, uiHeight, dynamicJumpHeights ? Mathf.pow(0.9f, Time.delta) : 0);
//square jumps
if(false){
float len = Scl.scl(Mathf.randomSeed(hashCode(), 10, 50));
float maxX = Math.max(x, x2) + len;
uiHeight = Mathf.lerp(
trapezoidalJumps ? 60f + 20f * (float) predHeight : 100f + 100f * (float) predHeight,
uiHeight,
dynamicJumpHeights ? Mathf.pow(0.9f, Time.delta) : 0
);
//trapezoidal jumps
if(trapezoidalJumps){
float dy = (y2 == y ? 0f : y2 > y ? 1f : -1f) * uiHeight * 0.5f;
Lines.beginLine();
Lines.linePoint(x, y);
Lines.linePoint(maxX, y);
Lines.linePoint(maxX, y2);
Lines.linePoint(x + uiHeight, y + dy);
Lines.linePoint(x + uiHeight, y2 - dy);
Lines.linePoint(x2, y2);
Lines.endLine();
return;
@@ -753,11 +777,13 @@ public class LCanvas extends Table{
if(this.button.to.get() == null){
this.markedDone = true;
this.predHeight = 0;
this.flipped = false;
this.jumpUIBegin = this.jumpUIEnd = invalidJump;
} else {
this.markedDone = false;
int i = this.button.elem.index;
int j = this.button.to.get().index;
this.flipped = i >= j;
this.jumpUIBegin = Math.min(i,j);
this.jumpUIEnd = Math.max(i,j);
// height will be recalculated later

View File

@@ -505,6 +505,7 @@ public class SettingsMenuDialog extends BaseDialog{
graphics.checkPref("dynamicjumpheights", true);
graphics.checkPref("coloredjumps", true);
graphics.checkPref("trapezoidaljumps", true);
}
public void exportData(Fi file) throws IOException{