Skip to content

Caching pattern angles signature for high-frequency matches and else - #1260

Closed
YukkuriC wants to merge 2 commits into
FallingColors:1.21from
YukkuriC:feature/cached-angles-sig
Closed

Caching pattern angles signature for high-frequency matches and else#1260
YukkuriC wants to merge 2 commits into
FallingColors:1.21from
YukkuriC:feature/cached-angles-sig

Conversation

@YukkuriC

Copy link
Copy Markdown
Contributor

tried my best to make its exposed interface stable, and relevant files change minimized ;w;

@s5bug

s5bug commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

I think the answer for the better design here may be an immutable HexPattern and a mutable HexPattern.Builder. The angle signature for HexPatterns once they're built is almost always used, so it wouldn't have to be Lazy there either.

Additionally, if HexPattern is going to be a data class, its fields should be immutable anyway.

@s5bug

s5bug commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

If we wanted to go super crazy, pattern building and checking could be a lot more optimized. I don't know Kotlin off the top of my head so I'll write the Java equivalents:

public final class HexSignature {
  // array of integers that pack in angles
  // each int is split into bits:
  // ?? jjj iii hhh ggg fff eee ddd ccc bbb aaa
  // 000 → path ends before a multiple of 10 steps
  // 001 → forward
  // 010 → right
  // etc
  // this is so new int[n] initializes everything to "end of path" i.e. it doesn't have to be set manually
  // `10` should probably be put in a constant somewhere
  // keep in mind that arrays are mutable, so don't expose any setters
  private final int[] packedTurns;
  // memoized hashcode for fast lookup
  private final int memoizedHash;
  
  private HexShape(int[] packedTurns) {
    this.packedTurns = packedTurns;
    this.memoizedHash = Arrays.hashCode(packedTurns);
  }
  
  // override equals to use Arrays.equals
  // override hashCode to just return the memoizedHash
}

public final class HexPattern {
  private final HexSignature sig;
  private final HexAngle orientation;
  
  public static final class Builder {
    private final HexAngle startDirection;
    private final IntArrayList turnsBuilder;
  
    public Builder(HexAngle startDirection) { /* implementation omitted */ }
    
    HexPattern build() { /* implementation omitted */ }
  }
}

Calling hashCode on HexSignatures should be as fast as Strings, and comparing them should be even faster (due to being smaller).

If we can assume that a vertex coordinate in a pattern will never exceed [-32768, 32767], then constructing a pattern while checking its angles can also be made a lot more efficient. Essentially you pack vertices into ints, and vertex pairs into longs. The trick is that you sort the ints before inserting them into your set, so you only have to store and check half the values:

// a long[] actually may be more performant here!
// LongArraySet provides a convenient wrapper for something that can grow, but...
// new long[1 + (packedTurns.length * 10)] is guaranteed to be enough space to hold all the edges
LongOpenHashSet edgeSet = new LongOpenHashSet(1 + (packedTurns.length * 10));

// (q, r) coordinates for our current vertex
short fromQ = ...;
short fromR = ...;
// (q, r) coordinates for our next vertex
short toQ = ...;
short toR = ...;

int from = (fromQ << 16) | fromR;
int to = (toQ << 16) | toR;

// `if(to < from) /* swap */` is "technically" faster but definitely not worth the readability loss
int lesser = Math.min(from, to);
int greater = Math.max(from, to);
long edge = ((long) lesser << 32L) | (long) greater;

if(edgeSet.add(edge)) // idk

@YukkuriC

Copy link
Copy Markdown
Contributor Author

maybe someone else will continue this one ;w;

@YukkuriC YukkuriC closed this Aug 17, 2026
@github-project-automation github-project-automation Bot moved this from 📋 Backlog to ✅ Done in Hex Casting Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants