2121import edu .wpi .first .math .geometry .Pose2d ;
2222import edu .wpi .first .math .geometry .Rotation2d ;
2323import edu .wpi .first .math .geometry .Translation2d ;
24- import edu .wpi .first .wpilibj .Timer ;
2524import org .curtinfrc .frc2026 .util .Repulsor .Predictive .Internal .CollectEval ;
2625import org .curtinfrc .frc2026 .util .Repulsor .Predictive .Internal .IntentAggCont ;
2726import org .curtinfrc .frc2026 .util .Repulsor .Predictive .Internal .ResourceRegions ;
@@ -99,11 +98,18 @@ void addDepletedMark(
9998 private static final double HIERARCHICAL_ANCHOR_MAX_DIST_M = 0.55 ;
10099 private static final double HIERARCHICAL_ANCHOR_EVIDENCE_SCALE = 0.75 ;
101100 private static final double HIERARCHICAL_ANCHOR_UNITS_SCALE = 0.60 ;
101+ private static final double SECONDARY_ANCHOR_EVIDENCE_SCALE = 0.65 ;
102+ private static final double SECONDARY_ANCHOR_UNITS_SCALE = 0.55 ;
103+ private static final double SECONDARY_FINAL_UNITS_SCALE = 0.70 ;
102104 private static final double ACTIVITY_CAP = 1.05 ;
103105 private static final int ENEMY_REGIONS_MAX = 24 ;
104106
105107 private PredictiveCollectSecondaryRankers () {}
106108
109+ private static double nowSec () {
110+ return System .nanoTime () / 1e9 ;
111+ }
112+
107113 static Translation2d anchorHierarchicalPointToFuel (
108114 SpatialDyn dyn , Translation2d seed , double cellM , double minUnits , double minEv ) {
109115 if (dyn == null || seed == null ) return null ;
@@ -219,7 +225,7 @@ static PointCandidate rankCollectHierarchical(
219225 - e .allyIntent * COLLECT_ALLY_INTENT_COST
220226 - activity
221227 - e .depleted * DEPLETED_PEN_W
222- + api .regionBanditBonus (dyn , cpt , Timer . getFPGATimestamp ());
228+ + api .regionBanditBonus (dyn , cpt , nowSec ());
223229
224230 if (ev < minEv ) score -= 2.00 ;
225231
@@ -275,7 +281,7 @@ static PointCandidate rankCollectHierarchical(
275281
276282 CollectEval e =
277283 api .evalCollectPoint (ourPos , cap , p , goal , cellM , dyn , enemyIntent , allyIntent );
278- e .banditBonus = api .regionBanditBonus (dyn , p , Timer . getFPGATimestamp ());
284+ e .banditBonus = api .regionBanditBonus (dyn , p , nowSec ());
279285 e .score += e .banditBonus ;
280286
281287 if (e .units < minUnits * 0.55 || e .count < Math .max (1 , minCount - 1 )) e .score -= 2.75 ;
@@ -325,7 +331,7 @@ static PointCandidate rankCollectHierarchical(
325331 order [best ] = tmp ;
326332 }
327333
328- double now = Timer . getFPGATimestamp ();
334+ double now = nowSec ();
329335
330336 for (int oi = 0 ; oi < candN ; oi ++) {
331337 int ci = order [oi ];
@@ -402,20 +408,37 @@ static Translation2d bestCollectHotspot(Api api, Translation2d[] points, double
402408 SpatialDyn dyn = api .cachedDyn ();
403409 if (dyn == null || dyn .resources .isEmpty ()) return null ;
404410
411+ double totalEv = dyn .totalEvidence ();
412+ double minUnits = Math .max (0.02 , api .dynamicMinUnits (totalEv ));
413+ double minEv = Math .max (0.01 , api .minEvidence (totalEv ));
414+
405415 double half = Math .max (0.05 , cellM * 0.5 );
416+ double rCore = Math .max (0.05 , PredictiveFieldStateOps .coreRadiusFor (cellM ));
406417 Translation2d best = null ;
407418 double bestU = 0.0 ;
408419
409420 for (Translation2d p : points ) {
410421 if (p == null ) continue ;
411- double u = dyn .valueInSquare (p , half );
422+ Translation2d anchored =
423+ anchorHierarchicalPointToFuel (
424+ dyn ,
425+ p ,
426+ cellM ,
427+ Math .max (0.02 , minUnits * SECONDARY_ANCHOR_UNITS_SCALE ),
428+ minEv * SECONDARY_ANCHOR_EVIDENCE_SCALE );
429+ if (anchored == null ) continue ;
430+
431+ int coreCount = dyn .countResourcesWithin (anchored , rCore );
432+ if (coreCount < 1 ) continue ;
433+
434+ double u = dyn .valueInSquare (anchored , half );
412435 if (u > bestU ) {
413436 bestU = u ;
414- best = p ;
437+ best = anchored ;
415438 }
416439 }
417440
418- double min = Math .max (0.02 , COLLECT_FINE_MIN_UNITS * 0.5 );
441+ double min = Math .max (0.02 , minUnits * SECONDARY_FINAL_UNITS_SCALE );
419442 return bestU >= min ? best : null ;
420443 }
421444
@@ -472,17 +495,29 @@ static PointCandidate rankCollectPoints(
472495 Translation2d p = targets [i ];
473496 if (p == null ) continue ;
474497
498+ Translation2d anchored =
499+ anchorHierarchicalPointToFuel (
500+ dyn ,
501+ p ,
502+ COLLECT_CELL_M ,
503+ Math .max (0.02 , minUnits * SECONDARY_ANCHOR_UNITS_SCALE ),
504+ minEv * SECONDARY_ANCHOR_EVIDENCE_SCALE );
505+ if (anchored == null ) continue ;
506+
475507 CollectEval e =
476- api .evalCollectPoint (ourPos , cap , p , goal , COLLECT_CELL_M , dyn , enemyIntent , allyIntent );
477- e .banditBonus = api .regionBanditBonus (dyn , p , Timer .getFPGATimestamp ());
508+ api .evalCollectPoint (
509+ ourPos , cap , anchored , goal , COLLECT_CELL_M , dyn , enemyIntent , allyIntent );
510+ e .banditBonus = api .regionBanditBonus (dyn , anchored , nowSec ());
478511 e .score += e .banditBonus ;
479512
480513 if (e .units < minUnits * 0.55 || e .count < Math .max (1 , minCount - 1 )) e .score -= 2.75 ;
481514 if (e .evidence < minEv ) e .score -= 2.25 ;
515+ if (dyn .countResourcesWithin (anchored , PredictiveFieldStateOps .coreRadiusFor (COLLECT_CELL_M ))
516+ < 1 ) e .score -= 3.0 ;
482517
483518 if (bestE == null || e .score > bestE .score + 1e-9 ) {
484519 bestE = e ;
485- bestP = p ;
520+ bestP = anchored ;
486521 }
487522 }
488523
@@ -494,7 +529,7 @@ static PointCandidate rankCollectPoints(
494529 return null ;
495530 }
496531
497- api .setLastReturnedCollect (bestP , Timer . getFPGATimestamp ());
532+ api .setLastReturnedCollect (bestP , nowSec ());
498533
499534 Logger .recordOutput ("Repulsor/ChosenCollect" , new Pose2d (bestP , new Rotation2d ()));
500535
0 commit comments