@woosh/meep-engine 3.29.0 → 3.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { IndexedFloatMinHeap } from "../collection/heap/IndexedFloatMinHeap.js";
|
|
3
|
+
import { lowbias32 } from "../math/hash/lowbias32.js";
|
|
4
|
+
import { WFCCellChoice } from "./WFCCellChoice.js";
|
|
5
|
+
import { WFCLattice } from "./WFCLattice.js";
|
|
6
|
+
import { WFCRuleTable, wfc_tail_mask } from "./WFCRuleTable.js";
|
|
7
|
+
import { WFCTileWeights } from "./WFCTileWeights.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Entropy differences below this are not meaningful — the heap stores a `float32`, whose precision
|
|
11
|
+
* near `ln(2)` is about `6e-8` — so a jitter of this size orders ties without reordering anything
|
|
12
|
+
* real.
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
const ENTROPY_JITTER_SCALE = 1e-6;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Possibility counts are integers a whole unit apart, so half a unit of jitter separates ties at
|
|
19
|
+
* any count a `float32` can still resolve.
|
|
20
|
+
* @type {number}
|
|
21
|
+
*/
|
|
22
|
+
const COUNT_JITTER_SCALE = 0.5;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initial capacity of the undo trail, in entries. Grows by doubling; never shrinks.
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
const TRAIL_INITIAL_CAPACITY = 1024;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `u32` words per trail entry: the address that was written, and the bits that were cleared.
|
|
32
|
+
* @type {number}
|
|
33
|
+
*/
|
|
34
|
+
const TRAIL_ENTRY_WORDS = 2;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `u32` words per decision-stack entry: the cell, the trail length before the collapse, and the
|
|
38
|
+
* tile that was tried.
|
|
39
|
+
* @type {number}
|
|
40
|
+
*/
|
|
41
|
+
const DECISION_ENTRY_WORDS = 3;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Everything a solve mutates: the wave, the aggregates derived from it, the propagation queue, the
|
|
45
|
+
* undo trail and the decision stack.
|
|
46
|
+
*
|
|
47
|
+
* All of it lives in the object, which is what makes {@link wfc_solve} resumable — a call that
|
|
48
|
+
* runs out of budget mid-propagation leaves its work here and the next call continues from it.
|
|
49
|
+
*
|
|
50
|
+
* Build one per solve. The {@link WFCRuleTable}, {@link WFCLattice} and {@link WFCTileWeights} it
|
|
51
|
+
* is given are read-only to it and can be shared across many.
|
|
52
|
+
*
|
|
53
|
+
* @author Alex Goldring
|
|
54
|
+
* @copyright Company Named Limited (c) 2026
|
|
55
|
+
*/
|
|
56
|
+
export class WFCState {
|
|
57
|
+
/**
|
|
58
|
+
* @param {WFCRuleTable} rules must be finalized
|
|
59
|
+
* @param {WFCLattice} lattice must have the same direction count as `rules`
|
|
60
|
+
* @param {WFCTileWeights} weights must have the same tile count as `rules`
|
|
61
|
+
* @param {function():number} random RNG returning values in `[0, 1)`. Consumed once here and
|
|
62
|
+
* once per collapse, so a seeded generator reproduces a solve exactly.
|
|
63
|
+
* @param {WFCCellChoice} [cell_choice] defaults to {@link WFCCellChoice.SCANLINE}
|
|
64
|
+
*/
|
|
65
|
+
constructor(rules, lattice, weights, random, cell_choice = WFCCellChoice.SCANLINE) {
|
|
66
|
+
assert.isInstanceOf(rules, WFCRuleTable, 'rules');
|
|
67
|
+
assert.isInstanceOf(lattice, WFCLattice, 'lattice');
|
|
68
|
+
assert.isInstanceOf(weights, WFCTileWeights, 'weights');
|
|
69
|
+
assert.isFunction(random, 'random');
|
|
70
|
+
assert.isOneOf(
|
|
71
|
+
cell_choice,
|
|
72
|
+
[WFCCellChoice.ENTROPY, WFCCellChoice.MINIMUM_REMAINING, WFCCellChoice.SCANLINE],
|
|
73
|
+
'cell_choice'
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (!rules.finalized) {
|
|
77
|
+
throw new Error('rule table is not finalized; call finalize() after the last mutation');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (rules.direction_count !== lattice.direction_count) {
|
|
81
|
+
throw new Error(`rule table has ${rules.direction_count} directions, lattice has ${lattice.direction_count}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (rules.tile_count !== weights.tile_count) {
|
|
85
|
+
throw new Error(`rule table has ${rules.tile_count} tiles, weights have ${weights.tile_count}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const cell_count = lattice.cell_count;
|
|
89
|
+
const words_per_cell = rules.words_per_cell;
|
|
90
|
+
|
|
91
|
+
// the trail stores `cell * words_per_cell + word` in a u32 and decodes it back with an
|
|
92
|
+
// int32 conversion, so the bound is 2^31 rather than 2^32. A real throw: consumers strip
|
|
93
|
+
// assert.* out of shipped builds, and silent index wraparound is exactly what must not
|
|
94
|
+
// depend on a build flag.
|
|
95
|
+
if (cell_count * words_per_cell >= 0x80000000) {
|
|
96
|
+
throw new Error(`cell_count(=${cell_count}) x words_per_cell(=${words_per_cell}) must stay below 2^31`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @type {WFCRuleTable} */
|
|
100
|
+
this.rules = rules;
|
|
101
|
+
/** @type {WFCLattice} */
|
|
102
|
+
this.lattice = lattice;
|
|
103
|
+
/** @type {WFCTileWeights} */
|
|
104
|
+
this.weights = weights;
|
|
105
|
+
/** @type {function():number} */
|
|
106
|
+
this.random = random;
|
|
107
|
+
/** @type {WFCCellChoice} */
|
|
108
|
+
this.cell_choice = cell_choice;
|
|
109
|
+
|
|
110
|
+
/** @type {number} */
|
|
111
|
+
this.cell_count = cell_count;
|
|
112
|
+
/** @type {number} */
|
|
113
|
+
this.tile_count = rules.tile_count;
|
|
114
|
+
/** @type {number} */
|
|
115
|
+
this.words_per_cell = words_per_cell;
|
|
116
|
+
/** @type {number} */
|
|
117
|
+
this.direction_count = rules.direction_count;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* A domain with every tile in it, tail-masked.
|
|
121
|
+
* @type {Uint32Array}
|
|
122
|
+
*/
|
|
123
|
+
this.full_mask = new Uint32Array(words_per_cell);
|
|
124
|
+
this.full_mask.fill(0xFFFFFFFF);
|
|
125
|
+
this.full_mask[words_per_cell - 1] = wfc_tail_mask(this.tile_count);
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Seeds the per-cell tie-break that separates cells of equal score. Drawn from `random`,
|
|
129
|
+
* so a seeded generator reproduces the whole solve.
|
|
130
|
+
* @type {number}
|
|
131
|
+
* @private
|
|
132
|
+
*/
|
|
133
|
+
this.__noise_seed = (random() * 0x100000000) >>> 0;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @type {number}
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
this.__jitter_scale = cell_choice === WFCCellChoice.ENTROPY
|
|
140
|
+
? ENTROPY_JITTER_SCALE
|
|
141
|
+
: COUNT_JITTER_SCALE;
|
|
142
|
+
|
|
143
|
+
const f64_bytes = cell_count * 8;
|
|
144
|
+
const wave_bytes = cell_count * words_per_cell * 4;
|
|
145
|
+
const u32_bytes = cell_count * 4;
|
|
146
|
+
|
|
147
|
+
let offset = 0;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Single backing buffer for every per-cell array.
|
|
151
|
+
* @type {ArrayBuffer}
|
|
152
|
+
* @private
|
|
153
|
+
*/
|
|
154
|
+
this.__data_buffer = new ArrayBuffer((f64_bytes * 2) + wave_bytes + (u32_bytes * 3) + (cell_count * 3));
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Sum of the weights still possible in each cell.
|
|
158
|
+
*
|
|
159
|
+
* Maintained incrementally and therefore subject to drift; only the entropy heuristic
|
|
160
|
+
* reads it, and {@link wfc_state_collapse} recomputes the sum exactly rather than trusting
|
|
161
|
+
* it.
|
|
162
|
+
* @type {Float64Array}
|
|
163
|
+
*/
|
|
164
|
+
this.weight_sum = new Float64Array(this.__data_buffer, offset, cell_count);
|
|
165
|
+
offset += f64_bytes;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Sum of `w·ln(w)` over the weights still possible in each cell.
|
|
169
|
+
* @type {Float64Array}
|
|
170
|
+
*/
|
|
171
|
+
this.weight_log_sum = new Float64Array(this.__data_buffer, offset, cell_count);
|
|
172
|
+
offset += f64_bytes;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* `words_per_cell` bits per cell: is tile `t` still possible here?
|
|
176
|
+
* @type {Uint32Array}
|
|
177
|
+
*/
|
|
178
|
+
this.wave = new Uint32Array(this.__data_buffer, offset, cell_count * words_per_cell);
|
|
179
|
+
offset += wave_bytes;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Population count of each cell's domain, cached rather than recomputed.
|
|
183
|
+
* @type {Uint32Array}
|
|
184
|
+
*/
|
|
185
|
+
this.possibility_count = new Uint32Array(this.__data_buffer, offset, cell_count);
|
|
186
|
+
offset += u32_bytes;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Cells whose domain shrank and whose neighbours have not been relaxed against them yet.
|
|
190
|
+
* Bounded at `cell_count` because {@link in_queue} de-duplicates.
|
|
191
|
+
* @type {Uint32Array}
|
|
192
|
+
*/
|
|
193
|
+
this.queue = new Uint32Array(this.__data_buffer, offset, cell_count);
|
|
194
|
+
offset += u32_bytes;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Cells whose selection score changed during the current wave. Flushed to the heap once
|
|
198
|
+
* per wave rather than once per banned tile.
|
|
199
|
+
* @type {Uint32Array}
|
|
200
|
+
*/
|
|
201
|
+
this.dirty_list = new Uint32Array(this.__data_buffer, offset, cell_count);
|
|
202
|
+
offset += u32_bytes;
|
|
203
|
+
|
|
204
|
+
/** @type {Uint8Array} */
|
|
205
|
+
this.in_queue = new Uint8Array(this.__data_buffer, offset, cell_count);
|
|
206
|
+
offset += cell_count;
|
|
207
|
+
|
|
208
|
+
/** @type {Uint8Array} */
|
|
209
|
+
this.dirty = new Uint8Array(this.__data_buffer, offset, cell_count);
|
|
210
|
+
offset += cell_count;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* May the solver choose to collapse this cell? Cells outside the eligible set still
|
|
214
|
+
* constrain their neighbours through propagation; they are simply never selected.
|
|
215
|
+
* @type {Uint8Array}
|
|
216
|
+
*/
|
|
217
|
+
this.eligible = new Uint8Array(this.__data_buffer, offset, cell_count);
|
|
218
|
+
offset += cell_count;
|
|
219
|
+
|
|
220
|
+
/** @type {number} */
|
|
221
|
+
this.queue_count = 0;
|
|
222
|
+
/** @type {number} */
|
|
223
|
+
this.dirty_count = 0;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* `(address, removed_bits)` pairs, in the order they were applied.
|
|
227
|
+
* @type {Uint32Array}
|
|
228
|
+
* @private
|
|
229
|
+
*/
|
|
230
|
+
this.__trail = new Uint32Array(TRAIL_INITIAL_CAPACITY * TRAIL_ENTRY_WORDS);
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Entries, not words.
|
|
234
|
+
* @type {number}
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
237
|
+
this.__trail_length = 0;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* `(cell, trail_mark, tried_tile)` triples.
|
|
241
|
+
* @type {Uint32Array}
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
this.__decisions = new Uint32Array(64 * DECISION_ENTRY_WORDS);
|
|
245
|
+
|
|
246
|
+
/** @type {number} @private */
|
|
247
|
+
this.__decision_count = 0;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Scratch for the propagator: the target bits not yet known to be supported.
|
|
251
|
+
* Owned by the state rather than the module, so two solves can interleave.
|
|
252
|
+
* @type {Uint32Array}
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
this.__uncovered = new Uint32Array(words_per_cell);
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Set by {@link wfc_state_ban_bits} when a cell's domain empties. Checked once per
|
|
259
|
+
* relaxation rather than returned through every call.
|
|
260
|
+
* @type {boolean}
|
|
261
|
+
*/
|
|
262
|
+
this.contradiction = false;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Eligible cells that still have more than one possibility. The solve is finished when it
|
|
266
|
+
* reaches zero.
|
|
267
|
+
* @type {number}
|
|
268
|
+
*/
|
|
269
|
+
this.undecided_eligible = 0;
|
|
270
|
+
|
|
271
|
+
/** @type {number} */
|
|
272
|
+
this.backtrack_count = 0;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* High-water mark of {@link __trail_length}, in entries — what a pathological rule set
|
|
276
|
+
* costs in memory.
|
|
277
|
+
* @type {number}
|
|
278
|
+
*/
|
|
279
|
+
this.trail_peak = 0;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Where {@link WFCCellChoice.SCANLINE} has reached.
|
|
283
|
+
* @type {number}
|
|
284
|
+
* @private
|
|
285
|
+
*/
|
|
286
|
+
this.__scan_cursor = 0;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Present only for the policies that need a priority queue.
|
|
290
|
+
* @type {IndexedFloatMinHeap|null}
|
|
291
|
+
*/
|
|
292
|
+
this.heap = cell_choice === WFCCellChoice.SCANLINE
|
|
293
|
+
? null
|
|
294
|
+
: new IndexedFloatMinHeap(cell_count);
|
|
295
|
+
|
|
296
|
+
// every cell starts with every tile, and every cell starts queued: the initial sweep is
|
|
297
|
+
// the propagation queue being pre-filled. Each relaxation in it has a pristine source, so
|
|
298
|
+
// the rule table's full_support answers it in O(words_per_cell).
|
|
299
|
+
for (let cell = 0; cell < cell_count; cell++) {
|
|
300
|
+
const base = cell * words_per_cell;
|
|
301
|
+
|
|
302
|
+
for (let w = 0; w < words_per_cell; w++) {
|
|
303
|
+
this.wave[base + w] = this.full_mask[w];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
this.possibility_count[cell] = this.tile_count;
|
|
307
|
+
this.weight_sum[cell] = weights.total_weight;
|
|
308
|
+
this.weight_log_sum[cell] = weights.total_weight_log_weight;
|
|
309
|
+
|
|
310
|
+
this.queue[cell] = cell;
|
|
311
|
+
this.in_queue[cell] = 1;
|
|
312
|
+
this.eligible[cell] = 1;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.queue_count = cell_count;
|
|
316
|
+
|
|
317
|
+
this.reseed_selection();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Bytes held by the per-cell arrays. The heap, trail and decision stack are separate and grow.
|
|
322
|
+
* @returns {number}
|
|
323
|
+
*/
|
|
324
|
+
get byte_size() {
|
|
325
|
+
return this.__data_buffer.byteLength;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Trail entries currently recorded.
|
|
330
|
+
* @returns {number}
|
|
331
|
+
*/
|
|
332
|
+
get trail_length() {
|
|
333
|
+
return this.__trail_length;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Decisions currently on the stack — the depth of the search.
|
|
338
|
+
* @returns {number}
|
|
339
|
+
*/
|
|
340
|
+
get decision_count() {
|
|
341
|
+
return this.__decision_count;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Selection score of a cell under the current {@link WFCCellChoice}; lower is chosen sooner.
|
|
346
|
+
*
|
|
347
|
+
* @param {number} cell
|
|
348
|
+
* @returns {number}
|
|
349
|
+
*/
|
|
350
|
+
score_of(cell) {
|
|
351
|
+
const jitter = ((lowbias32(cell ^ this.__noise_seed) >>> 8) / 0x1000000) * this.__jitter_scale;
|
|
352
|
+
|
|
353
|
+
if (this.cell_choice === WFCCellChoice.ENTROPY) {
|
|
354
|
+
const sum = this.weight_sum[cell];
|
|
355
|
+
|
|
356
|
+
return Math.log(sum) - (this.weight_log_sum[cell] / sum) + jitter;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return this.possibility_count[cell] + jitter;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Make everything decided so far permanent: drop the decision stack and the undo trail, so no
|
|
364
|
+
* later contradiction can rewind past this point.
|
|
365
|
+
*
|
|
366
|
+
* The wave is untouched — this is about what the *search* may reconsider, not what the grid
|
|
367
|
+
* holds. Afterwards a contradiction reports {@link WFCStatus.UNSATISFIABLE} rather than
|
|
368
|
+
* dismantling work already treated as finished.
|
|
369
|
+
*/
|
|
370
|
+
commit() {
|
|
371
|
+
this.__decision_count = 0;
|
|
372
|
+
this.__trail_length = 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Rebuild the selection queue and the undecided count from the current wave.
|
|
377
|
+
*
|
|
378
|
+
* Called at construction, and by {@link wfc_state_set_eligible} when the eligible set changes.
|
|
379
|
+
*
|
|
380
|
+
* @param {Uint32Array|number[]} [cells] the eligible set when it is already known, which makes
|
|
381
|
+
* the rebuild proportional to it rather than to the whole grid. Must not repeat a cell;
|
|
382
|
+
* {@link wfc_state_set_eligible} asserts that.
|
|
383
|
+
*/
|
|
384
|
+
reseed_selection(cells) {
|
|
385
|
+
const { cell_count, heap, possibility_count, eligible } = this;
|
|
386
|
+
|
|
387
|
+
this.__scan_cursor = 0;
|
|
388
|
+
|
|
389
|
+
// clear only the flags that are actually set — `dirty[cell]` is raised only when the cell
|
|
390
|
+
// is appended to `dirty_list`, so the list names every one. A `fill(0)` here is a
|
|
391
|
+
// whole-grid memset, which block solving pays once per block.
|
|
392
|
+
for (let i = 0; i < this.dirty_count; i++) {
|
|
393
|
+
this.dirty[this.dirty_list[i]] = 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
this.dirty_count = 0;
|
|
397
|
+
|
|
398
|
+
if (heap !== null) {
|
|
399
|
+
heap.clear();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
let undecided = 0;
|
|
403
|
+
|
|
404
|
+
const count = cells === undefined ? cell_count : cells.length;
|
|
405
|
+
|
|
406
|
+
for (let i = 0; i < count; i++) {
|
|
407
|
+
const cell = cells === undefined ? i : cells[i];
|
|
408
|
+
|
|
409
|
+
if (eligible[cell] === 0 || possibility_count[cell] <= 1) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
undecided++;
|
|
414
|
+
|
|
415
|
+
if (heap !== null) {
|
|
416
|
+
heap.insert(cell, this.score_of(cell));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.undecided_eligible = undecided;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Record that `bits` were cleared at `address`, so backtracking can put them back.
|
|
425
|
+
*
|
|
426
|
+
* @param {number} address `cell * words_per_cell + word`
|
|
427
|
+
* @param {number} bits the bits that were actually cleared
|
|
428
|
+
*/
|
|
429
|
+
trail_push(address, bits) {
|
|
430
|
+
const length = this.__trail_length;
|
|
431
|
+
|
|
432
|
+
if ((length + 1) * TRAIL_ENTRY_WORDS > this.__trail.length) {
|
|
433
|
+
const grown = new Uint32Array(this.__trail.length * 2);
|
|
434
|
+
|
|
435
|
+
grown.set(this.__trail);
|
|
436
|
+
|
|
437
|
+
this.__trail = grown;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const word = length * TRAIL_ENTRY_WORDS;
|
|
441
|
+
|
|
442
|
+
this.__trail[word] = address;
|
|
443
|
+
this.__trail[word + 1] = bits;
|
|
444
|
+
|
|
445
|
+
const next = length + 1;
|
|
446
|
+
|
|
447
|
+
this.__trail_length = next;
|
|
448
|
+
|
|
449
|
+
if (next > this.trail_peak) {
|
|
450
|
+
this.trail_peak = next;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @param {number} entry
|
|
456
|
+
* @returns {number} the address written by that trail entry
|
|
457
|
+
*/
|
|
458
|
+
trail_address(entry) {
|
|
459
|
+
return this.__trail[entry * TRAIL_ENTRY_WORDS];
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* @param {number} entry
|
|
464
|
+
* @returns {number} the bits that entry cleared
|
|
465
|
+
*/
|
|
466
|
+
trail_bits(entry) {
|
|
467
|
+
return this.__trail[entry * TRAIL_ENTRY_WORDS + 1];
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Drop trail entries above `length`. The caller has already restored the wave from them.
|
|
472
|
+
* @param {number} length
|
|
473
|
+
*/
|
|
474
|
+
trail_truncate(length) {
|
|
475
|
+
this.__trail_length = length;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Push a decision the search can return to.
|
|
480
|
+
*
|
|
481
|
+
* `trail_mark` is taken before the collapse and `tile` is only known after it, so the caller
|
|
482
|
+
* passes both rather than this reading the current trail length.
|
|
483
|
+
*
|
|
484
|
+
* @param {number} cell
|
|
485
|
+
* @param {number} trail_mark trail length immediately before the collapse
|
|
486
|
+
* @param {number} tile
|
|
487
|
+
*/
|
|
488
|
+
decision_push(cell, trail_mark, tile) {
|
|
489
|
+
const count = this.__decision_count;
|
|
490
|
+
|
|
491
|
+
if ((count + 1) * DECISION_ENTRY_WORDS > this.__decisions.length) {
|
|
492
|
+
const grown = new Uint32Array(this.__decisions.length * 2);
|
|
493
|
+
|
|
494
|
+
grown.set(this.__decisions);
|
|
495
|
+
|
|
496
|
+
this.__decisions = grown;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const word = count * DECISION_ENTRY_WORDS;
|
|
500
|
+
|
|
501
|
+
this.__decisions[word] = cell;
|
|
502
|
+
this.__decisions[word + 1] = trail_mark;
|
|
503
|
+
this.__decisions[word + 2] = tile;
|
|
504
|
+
|
|
505
|
+
this.__decision_count = count + 1;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Remove the newest decision and report it.
|
|
510
|
+
*
|
|
511
|
+
* @param {Uint32Array|number[]} out receives `[cell, trail_mark, tried_tile]`
|
|
512
|
+
* @returns {boolean} false when the stack was already empty
|
|
513
|
+
*/
|
|
514
|
+
decision_pop(out) {
|
|
515
|
+
if (this.__decision_count === 0) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const count = this.__decision_count - 1;
|
|
520
|
+
const word = count * DECISION_ENTRY_WORDS;
|
|
521
|
+
|
|
522
|
+
out[0] = this.__decisions[word];
|
|
523
|
+
out[1] = this.__decisions[word + 1];
|
|
524
|
+
out[2] = this.__decisions[word + 2];
|
|
525
|
+
|
|
526
|
+
this.__decision_count = count;
|
|
527
|
+
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Scratch for {@link wfc_state_propagate}.
|
|
533
|
+
* @returns {Uint32Array}
|
|
534
|
+
*/
|
|
535
|
+
get uncovered() {
|
|
536
|
+
return this.__uncovered;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @returns {number}
|
|
541
|
+
*/
|
|
542
|
+
get scan_cursor() {
|
|
543
|
+
return this.__scan_cursor;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @param {number} v
|
|
548
|
+
*/
|
|
549
|
+
set scan_cursor(v) {
|
|
550
|
+
this.__scan_cursor = v;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome of a call to {@link wfc_solve }.
|
|
3
|
+
*/
|
|
4
|
+
export type WFCStatus = number;
|
|
5
|
+
export namespace WFCStatus {
|
|
6
|
+
let SOLVED: number;
|
|
7
|
+
let RUNNING: number;
|
|
8
|
+
let UNSATISFIABLE: number;
|
|
9
|
+
let EXHAUSTED: number;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=WFCStatus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WFCStatus.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/WFCStatus.js"],"names":[],"mappings":";;;wBAIU,MAAM"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome of a call to {@link wfc_solve}.
|
|
3
|
+
*
|
|
4
|
+
* @readonly
|
|
5
|
+
* @enum {number}
|
|
6
|
+
*/
|
|
7
|
+
export const WFCStatus = {
|
|
8
|
+
/**
|
|
9
|
+
* Every eligible cell has exactly one possibility left. The result is ready to read.
|
|
10
|
+
*/
|
|
11
|
+
SOLVED: 0,
|
|
12
|
+
/**
|
|
13
|
+
* The operation budget ran out. Nothing is wrong; call again to continue. All progress,
|
|
14
|
+
* including a half-drained propagation queue, lives in the state.
|
|
15
|
+
*/
|
|
16
|
+
RUNNING: 1,
|
|
17
|
+
/**
|
|
18
|
+
* The search space is exhausted — the instance has no solution under the caller's initial
|
|
19
|
+
* restrictions. This is an answer, not a failure.
|
|
20
|
+
*/
|
|
21
|
+
UNSATISFIABLE: 2,
|
|
22
|
+
/**
|
|
23
|
+
* The backtrack budget ran out before the search either succeeded or proved the instance
|
|
24
|
+
* unsatisfiable. The conventional response is to restart with a different seed; a caller
|
|
25
|
+
* that wants to keep searching raises `max_backtracks` instead.
|
|
26
|
+
*/
|
|
27
|
+
EXHAUSTED: 3
|
|
28
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative placement likelihoods, one per tile.
|
|
3
|
+
*
|
|
4
|
+
* Nothing is normalised — `[1, 9]` and `[0.1, 0.9]` behave identically.
|
|
5
|
+
*
|
|
6
|
+
* Weights must be finite and strictly positive; a non-positive one throws. A zero-weight tile
|
|
7
|
+
* would sit in a cell's domain, count toward its possibility count and never be selected, which
|
|
8
|
+
* surfaces much later as a solve that cannot finish. A tile you do not want is one you leave out
|
|
9
|
+
* of the rule table.
|
|
10
|
+
*
|
|
11
|
+
* Held apart from {@link WFCRuleTable} so the same structure can be solved with different
|
|
12
|
+
* preferences.
|
|
13
|
+
*
|
|
14
|
+
* @author Alex Goldring
|
|
15
|
+
* @copyright Company Named Limited (c) 2026
|
|
16
|
+
*/
|
|
17
|
+
export class WFCTileWeights {
|
|
18
|
+
/**
|
|
19
|
+
* Every tile equally likely — the same as passing an array of ones.
|
|
20
|
+
*
|
|
21
|
+
* @param {number} tile_count
|
|
22
|
+
* @returns {WFCTileWeights}
|
|
23
|
+
*/
|
|
24
|
+
static uniform(tile_count: number): WFCTileWeights;
|
|
25
|
+
/**
|
|
26
|
+
* @param {number[]|Float64Array} weights one strictly positive, finite weight per tile
|
|
27
|
+
*/
|
|
28
|
+
constructor(weights: number[] | Float64Array);
|
|
29
|
+
/** @type {number} */
|
|
30
|
+
tile_count: number;
|
|
31
|
+
/** @type {Float64Array} */
|
|
32
|
+
weight: Float64Array;
|
|
33
|
+
/**
|
|
34
|
+
* `w · ln(w)`, the numerator term of the Shannon entropy of a weighted domain.
|
|
35
|
+
* @type {Float64Array}
|
|
36
|
+
*/
|
|
37
|
+
weight_log_weight: Float64Array;
|
|
38
|
+
/**
|
|
39
|
+
* Sum over every tile — the value a pristine cell's running sum starts at.
|
|
40
|
+
* @type {number}
|
|
41
|
+
*/
|
|
42
|
+
total_weight: number;
|
|
43
|
+
/**
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
total_weight_log_weight: number;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=WFCTileWeights.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WFCTileWeights.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/WFCTileWeights.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH;IAwDI;;;;;OAKG;IACH,2BAHW,MAAM,GACJ,cAAc,CAM1B;IAjED;;OAEG;IACH,qBAFW,MAAM,EAAE,GAAC,YAAY,EAoD/B;IA3CG,qBAAqB;IACrB,YADW,MAAM,CACW;IAE5B,2BAA2B;IAC3B,QADW,YAAY,CACmB;IAE1C;;;OAGG;IACH,mBAFU,YAAY,CAE+B;IAuBrD;;;OAGG;IACH,cAFU,MAAM,CAES;IAEzB;;OAEG;IACH,yBAFU,MAAM,CAEwB;CAc/C"}
|