11import type { Mapping } from '../types' ;
2- import { shuffleArray , buildEvenAnchors , placeSizesGeneric , buildMappingFromSetZ0 , canPlace , place } from './utilities' ;
2+ import { generateBaseLayerWithShapes , shuffleArray } from './utilities' ;
33import type { BaseLayerOptions } from './consts' ;
44
5- function ringPerimeter ( x0 : number , y0 : number , w : number , h : number ) : Array < [ number , number ] > {
5+ export function ringPerimeter ( x0 : number , y0 : number , w : number , h : number ) : Array < [ number , number ] > {
66 const x1 = x0 + ( w - 1 ) * 2 ;
77 const y1 = y0 + ( h - 1 ) * 2 ;
88 const per : Array < [ number , number ] > = [ ] ;
@@ -21,75 +21,13 @@ function ringPerimeter(x0: number, y0: number, w: number, h: number): Array<[num
2121 return per ;
2222}
2323
24- export function generateBaseLayerRings ( { minTarget, maxTarget, xMax, yMax } : BaseLayerOptions ) : Mapping {
25- // Random placement of hollow rectangular rings on z=0 with spacing 2 and unique sizes per layer.
26- // - Ring outer width/height in [3..8]
27- // - Borders only, continuous per ring
28- // - Spacing: at least 2 cells empty between different rings (Chebyshev radius 2)
29- // - Use even-even grid to cooperate with blocksOverlap safety
30- // - Do not place two rings with identical (w,h)
31-
32- const occupied = new Set < string > ( ) ;
33- const blocked = new Set < string > ( ) ;
34- const usedSizes = new Set < string > ( ) ;
35-
24+ export function generateBaseLayerRings ( options : BaseLayerOptions ) : Mapping {
3625 const allSizes : Array < [ number , number ] > = [ ] ;
3726 for ( let w = 3 ; w <= 8 ; w ++ ) {
3827 for ( let h = 3 ; h <= 8 ; h ++ ) {
3928 allSizes . push ( [ w , h ] ) ;
4029 }
4130 }
42- // Randomize size order; we will still enforce uniqueness by usedSizes
4331 shuffleArray ( allSizes ) ;
44-
45- // Build randomized list of even-even anchor positions within bounds
46- const anchors = buildEvenAnchors ( xMax , yMax ) ;
47- shuffleArray ( anchors ) ;
48-
49- let total = 0 ;
50- // Phase 1: try randomized sizes against randomized anchors
51- total = placeSizesGeneric ( total , allSizes , anchors , minTarget , maxTarget , ( x0 , y0 , w , h ) =>
52- canPlace ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) ? place ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) : 0
53- ) ;
54-
55- // Phase 2: if still below minTarget, try remaining unused sizes in a fresh random order and reshuffled anchors
56- if ( total < minTarget ) {
57- const remainingSizes = allSizes . filter ( ( [ w , h ] ) => ! usedSizes . has ( `${ w } x${ h } ` ) ) ;
58- shuffleArray ( remainingSizes ) ;
59- shuffleArray ( anchors ) ;
60- total = placeSizesGeneric ( total , remainingSizes , anchors , minTarget , maxTarget , ( x0 , y0 , w , h ) =>
61- canPlace ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) ? place ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) : 0
62- ) ;
63- }
64-
65- // Phase 3: fill remaining empty spaces with rings too, up to maxTarget.
66- // Keep trying any remaining unused sizes; if all sizes are used and still room, allow reuse of sizes to pack gaps.
67- if ( total < maxTarget ) {
68- let progress = true ;
69- let allowReuse = false ;
70- while ( progress && total < maxTarget ) {
71- progress = false ;
72- const sizePool : Array < [ number , number ] > =
73- allowReuse ? [ ...allSizes ] : allSizes . filter ( ( [ w , h ] ) => ! usedSizes . has ( `${ w } x${ h } ` ) ) ;
74- if ( sizePool . length === 0 && ! allowReuse ) {
75- allowReuse = true ; // all unique sizes exhausted; permit reuse to truly fill spaces
76- continue ;
77- }
78- shuffleArray ( sizePool ) ;
79- shuffleArray ( anchors ) ;
80- total = placeSizesGeneric ( total , sizePool , anchors , minTarget , maxTarget , ( x0 , y0 , w , h ) => {
81- if ( ! canPlace ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) ) {
82- return 0 ;
83- }
84- const added = place ( x0 , y0 , w , h , occupied , blocked , usedSizes , ringPerimeter ) ;
85- if ( added > 0 ) {
86- progress = true ;
87- }
88- return added ;
89- } ) ;
90- }
91- }
92-
93- // Build mapping in y,x order
94- return buildMappingFromSetZ0 ( occupied , xMax , yMax , 2 ) ;
32+ return generateBaseLayerWithShapes ( allSizes , ringPerimeter , options ) ;
9533}
0 commit comments