introduce bitloops

This commit is contained in:
mike
2026-01-18 04:11:43 +01:00
parent b026ebfbd2
commit 948730d7be
5 changed files with 186 additions and 99 deletions

View File

@@ -13,78 +13,81 @@ public class ConnectivityTest {
Rng rng = new Rng(42);
Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
// 1. Maak een masker met één component van clues (bijv. 3 clues naast elkaar)
// 1. Maak een masker met één component van clues (bijv. 2 clues die elkaar kruisen)
Clues singleComp = Clues.createEmpty();
// Gebruik offsets die dicht bij elkaar liggen
int off1 = SwedishGenerator.Grid.offset(1, 1);
int off2 = SwedishGenerator.Grid.offset(1, 2);
int off3 = SwedishGenerator.Grid.offset(2, 1);
// Clue 1: (0,0) Right. Slot: (0,1), (0,2), (0,3)
// Clue 2: (1,2) Up. Slot: (0,2)
// Ze zijn NIET 8-naburig, maar wel verbonden via slot op (0,2)
singleComp.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1);
singleComp.setClueLo(1L << SwedishGenerator.Grid.offset(2,2), (byte)2); // Up van (2,2) naar (1,2), (0,2)
singleComp.setClueLo(1L << off1, (byte)1); // Right
singleComp.setClueLo(1L << off2, (byte)1); // Right
singleComp.setClueLo(1L << off3, (byte)0); // Down
long fitnessSingle = masker.maskFitness(singleComp, 3);
long fitnessSingle = masker.maskFitness(singleComp, 2);
// 2. Maak een masker met twee eilandjes van clues
Clues twoIslands = Clues.createEmpty();
int offA1 = SwedishGenerator.Grid.offset(1, 1);
int offB1 = SwedishGenerator.Grid.offset(6, 6); // Ver weg
// We moeten zorgen dat ze elk minstens 1 slot vormen om door isValid(2) te komen
twoIslands.setClueLo(1L << offA1, (byte)1);
twoIslands.setClueLo(1L << offB1, (byte)1);
twoIslands.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1);
twoIslands.setClueLo( SwedishGenerator.Grid.offset(7,7) < 64 ? 1L << SwedishGenerator.Grid.offset(7,7) : 0, (byte)1);
// Voor de zekerheid checken we of offset(7,7) in lo of hi zit
int off77 = SwedishGenerator.Grid.offset(7,7);
if (off77 < 64) twoIslands.setClueLo(1L << off77, (byte)1);
else twoIslands.setClueHi(1L << (off77 - 64), (byte)1);
long fitnessIslands = masker.maskFitness(twoIslands, 2);
System.out.println("[DEBUG_LOG] Fitness single component: " + fitnessSingle);
System.out.println("[DEBUG_LOG] Fitness two islands: " + fitnessIslands);
// De eilandjes moeten een hogere penalty hebben (als clueCount gelijk is)
Clues twoIslands3 = Clues.createEmpty();
twoIslands3.setClueLo(1L << offA1, (byte)1);
twoIslands3.setClueLo(1L << offB1, (byte)1);
int offB2 = SwedishGenerator.Grid.offset(6, 7);
twoIslands3.setClueLo(1L << offB2, (byte)1);
long fitnessIslands3 = masker.maskFitness(twoIslands3, 3);
System.out.println("[DEBUG_LOG] Fitness three clues in two islands: " + fitnessIslands3);
assertTrue(fitnessIslands3 > fitnessSingle, "Islands should have higher penalty than single component");
assertTrue(fitnessIslands > fitnessSingle + 10000, "Islands should have much higher penalty");
}
@Test
void testIntersectionConnectivity() {
void testPhysicalAdjacency() {
Rng rng = new Rng(42);
Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
// Test of slots die elkaar kruisen als verbonden worden beschouwd,
// zelfs als de clues niet 8-naburig zijn.
Clues crossing = Clues.createEmpty();
// Clue 1: (0,0) naar rechts. Slot op (0,1), (0,2), (0,3)
// Clue 2: (1,2) omhoog. Slot op (0,2)
// Ze kruisen op (0,2)
crossing.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1); // Right
crossing.setClueLo(1L << SwedishGenerator.Grid.offset(1,2), (byte)2); // Up
Clues clues = Clues.createEmpty();
// Twee clues naast elkaar, maar slots kruisen niet.
// Clue 1: (1,1) Right. Slot (1,2), (1,3), (1,4)
// Clue 2: (2,1) Right. Slot (2,2), (2,3), (2,4)
clues.setClueLo(1L << SwedishGenerator.Grid.offset(1,1), (byte)1);
clues.setClueLo(1L << SwedishGenerator.Grid.offset(2,1), (byte)1);
// Deze twee clues zijn niet 8-naburig (0,0 en 1,2)
// Maar hun slots kruisen op (0,2)
long fitness = masker.maskFitness(clues, 2);
long fitness = masker.maskFitness(crossing, 2);
System.out.println("[DEBUG_LOG] Fitness crossing: " + fitness);
// Als 8-naburigheid NIET MEER meetelt, moet de penalty hoog zijn.
System.out.println("[DEBUG_LOG] Fitness physically adjacent: " + fitness);
assertTrue(fitness > 20000, "Should have island penalty even if physically adjacent");
}
@Test
void testCornerClueConnectivity() {
Rng rng = new Rng(42);
Masker masker = new Masker(rng, new int[STACK_SIZE], Clues.createEmpty());
// Als ze als verbonden worden gezien, is er 1 component.
// Penalty voor connectiviteit zou 0 moeten zijn (bovenop andere penalties).
// Als we een derde clue ver weg toevoegen, moet de penalty significant stijgen.
Clues clues = Clues.createEmpty();
// Clue A: (2,0) Right. Slot: (2,1), (2,2), (2,3), ...
// Clue B: (1,2) Corner Down. Word starts at (1,3) en gaat omlaag: (1,3), (2,3), (3,3)...
// Ze kruisen op (2,3).
clues.setClueLo(1L << SwedishGenerator.Grid.offset(2,0), (byte)1); // Right
clues.setClueLo(1L << SwedishGenerator.Grid.offset(1,2), (byte)4); // Corner Down
Clues crossingPlusIsland = Clues.createEmpty();
crossingPlusIsland.setClueLo(1L << SwedishGenerator.Grid.offset(0,0), (byte)1);
crossingPlusIsland.setClueLo(1L << SwedishGenerator.Grid.offset(1,2), (byte)2);
crossingPlusIsland.setClueLo(1L << SwedishGenerator.Grid.offset(7,7), (byte)1);
long fitness = masker.maskFitness(clues, 2);
System.out.println("[DEBUG_LOG] Fitness corner clue connected: " + fitness);
long fitnessIsland = masker.maskFitness(crossingPlusIsland, 3);
System.out.println("[DEBUG_LOG] Fitness crossing plus island: " + fitnessIsland);
// Als ze verbonden zijn, is de penalty voor eilandjes 0.
// We vergelijken met een island scenario (2 clues die elkaar NIET raken)
Clues island = Clues.createEmpty();
int offA = SwedishGenerator.Grid.offset(2,0);
if (offA < 64) island.setClueLo(1L << offA, (byte)1);
else island.setClueHi(1L << (offA - 64), (byte)1);
assertTrue(fitnessIsland > fitness + 10000, "Island should add significant penalty");
int offB = SwedishGenerator.Grid.offset(7,7);
if (offB < 64) island.setClueLo(1L << offB, (byte)1);
else island.setClueHi(1L << (offB - 64), (byte)1);
long fitnessIsland = masker.maskFitness(island, 2);
System.out.println("[DEBUG_LOG] Fitness island: " + fitnessIsland);
assertTrue(fitnessIsland > fitness + 20000, "Island should add significant penalty compared to connected corner clue");
}
}