@jetta/blocks-allocator 0.0.0-stage → 0.1.0-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.
Files changed (282) hide show
  1. package/README.md +103 -2
  2. package/package.json +67 -5
  3. package/src/Allocation_Attempt.js +135 -0
  4. package/src/Allocation_Error_Handler.js +69 -0
  5. package/src/Allocation_Flow.js +162 -0
  6. package/src/Allocation_Optimization/Allocation_LP.js +150 -0
  7. package/src/Allocation_Optimization/Block_Allocator.js +129 -0
  8. package/src/Allocation_Optimization/Block_Layer_Order.js +50 -0
  9. package/src/Allocation_Optimization/Block_Potential_Weight.js +54 -0
  10. package/src/Allocation_Optimization/Chosen_Blocks_Stock_Cap.js +82 -0
  11. package/src/Allocation_Optimization/block_builder/Allocation_Item_Creator.js +37 -0
  12. package/src/Allocation_Optimization/block_builder/Block_Item_List_Validator.js +18 -0
  13. package/src/Allocation_Optimization/block_builder/Block_Wall_Builder.js +303 -0
  14. package/src/Allocation_Optimization/block_builder/Blocks_Builder.js +40 -0
  15. package/src/Allocation_Optimization/block_builder/Next_Block_Position.js +33 -0
  16. package/src/Allocation_Optimization/block_builder/Slot_Item_Assigner.js +45 -0
  17. package/src/Allocation_Optimization/block_builder/Stacking_Validation.js +30 -0
  18. package/src/Allocation_Optimization/block_builder/assert_tie_ratio_block_matches_orientation_below.js +44 -0
  19. package/src/Allocation_Optimization/block_builder/block_shape_stock.js +129 -0
  20. package/src/Allocation_Optimization/block_builder/exceptions/Empty_Block_Item_List_Exception.js +21 -0
  21. package/src/Allocation_Optimization/block_builder/exceptions/Invalid_Stacking_Exception.js +14 -0
  22. package/src/Allocation_Optimization/block_builder/exceptions/No_Suitable_Item_Exception.js +16 -0
  23. package/src/Allocation_Optimization/block_builder/exceptions/Restricted_Block_Exception.js +21 -0
  24. package/src/Allocation_Optimization/block_builder/should_omit_block_group_id.js +29 -0
  25. package/src/Allocation_Optimization/block_builder/snap_elevated_block_wall_items.js +34 -0
  26. package/src/Allocation_Optimization/block_builder/stacking_rules_input.js +52 -0
  27. package/src/Allocation_Optimization/cap_chosen_blocks_by_shape_stock.js +110 -0
  28. package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Preparer.js +21 -0
  29. package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Selector.js +55 -0
  30. package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Threshold_Resolver.js +28 -0
  31. package/src/Allocation_Optimization/density_groups/Adaptive_Density_Group_Thresholds.js +23 -0
  32. package/src/Allocation_Optimization/density_groups/Container_Utilization.js +67 -0
  33. package/src/Allocation_Optimization/density_groups/Density_Group_Partitioner.js +74 -0
  34. package/src/Allocation_Optimization/density_groups/Density_Group_Scheduler.js +168 -0
  35. package/src/Allocation_Optimization/density_groups/Density_Group_Stock.js +49 -0
  36. package/src/Allocation_Optimization/density_groups/Density_Groups_Strategy.js +26 -0
  37. package/src/Allocation_Optimization/density_groups/Item_Density_Calculator.js +20 -0
  38. package/src/Allocation_Optimization/density_groups/Lock_Weight_Ahead_Release.js +75 -0
  39. package/src/Allocation_Optimization/exceptions/Invalid_Item_Amount_Exception.js +17 -0
  40. package/src/Allocation_Optimization/exceptions/No_Valid_Allocation_Exception.js +14 -0
  41. package/src/Allocation_Optimization/exceptions/Optimization_Infeasible_Exception.js +14 -0
  42. package/src/Allocation_Optimization/functions/Measure_Reader.js +20 -0
  43. package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Cobination_Mode.js +25 -0
  44. package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Cobination_Strategies.js +8 -0
  45. package/src/Allocation_Optimization/functions/Weight_Getter/Measure_Combination_Mode_Checkers.js +70 -0
  46. package/src/Allocation_Optimization/functions/Weight_Getter/Translation.js +22 -0
  47. package/src/Allocation_Optimization/functions/Weight_Getter/Variable_Weight_Getter.js +85 -0
  48. package/src/Allocation_Optimization/functions/Weight_Getter/constants.js +16 -0
  49. package/src/Allocation_Optimization/functions/measure_to_optimize.js +6 -0
  50. package/src/Allocation_Optimization/item_consumption_heuristic/Capacity_Bias_Item_Order.js +76 -0
  51. package/src/Allocation_Optimization/item_consumption_heuristic/Choose_Item_Heuristic_Context.js +63 -0
  52. package/src/Allocation_Optimization/item_consumption_heuristic/Item_Chooser.js +159 -0
  53. package/src/Allocation_Optimization/item_consumption_heuristic/Item_For_Slot_Chooser.js +49 -0
  54. package/src/Allocation_Optimization/item_consumption_heuristic/Slot_Compatible_Items_Finder.js +88 -0
  55. package/src/Allocation_Optimization/item_consumption_heuristic/Slots_Items_Assigner.js +182 -0
  56. package/src/Allocation_Optimization/item_consumption_heuristic/Stack_Slot_Calculator.js +87 -0
  57. package/src/Allocation_Optimization/item_consumption_heuristic/Weight_Slot_Distribution.js +72 -0
  58. package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/Empty_Slot_Exception.js +17 -0
  59. package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/Item_Taller_Than_Limit_Exception.js +21 -0
  60. package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/No_Available_Items_Exception.js +14 -0
  61. package/src/Allocation_Optimization/item_consumption_heuristic/exceptions/No_Slots_For_Items_Exception.js +14 -0
  62. package/src/Allocation_Optimization/lp_model/Block_Weight_Calculator.js +31 -0
  63. package/src/Allocation_Optimization/lp_model/LP_Data_Processor.js +42 -0
  64. package/src/Allocation_Optimization/lp_model/LP_Item_Slot_Assignment.js +93 -0
  65. package/src/Allocation_Optimization/lp_model/LP_Result_Mapper.js +47 -0
  66. package/src/Allocation_Optimization/lp_model/model_builder/Dimension_Range_Helper.js +49 -0
  67. package/src/Allocation_Optimization/lp_model/model_builder/Item_Assignment_Variables.js +133 -0
  68. package/src/Allocation_Optimization/lp_model/model_builder/LP_Model_Builder.js +132 -0
  69. package/src/Allocation_Optimization/lp_model/model_builder/exceptions/Missing_Item_Stock_Exception.js +18 -0
  70. package/src/Allocation_Optimization/lp_model/model_builder/goal_function/Goal_Function_Creator.js +83 -0
  71. package/src/Allocation_Optimization/lp_model/model_builder/item_dimension_hashes.js +31 -0
  72. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Block_Item_Amount_Restriction.js +53 -0
  73. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Coherence_Restriction.js +65 -0
  74. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Container_Supported_Weight_Restriction.js +42 -0
  75. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Relational_Exact_Pass_Amount_Restriction.js +62 -0
  76. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Relational_Group_Restriction.js +97 -0
  77. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Single_Item_Type_Restriction.js +79 -0
  78. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Space_Restriction.js +47 -0
  79. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Unavailable_Block_Restriction.js +27 -0
  80. package/src/Allocation_Optimization/lp_model/model_builder/restrictions/Uniform_Block_Measure_Restriction.js +92 -0
  81. package/src/Allocation_Optimization/next_group_id_after_preloaded.js +30 -0
  82. package/src/Allocation_Optimization/preferential_blocks/Preferential_Block_Identifier.js +74 -0
  83. package/src/Allocation_Optimization/preferential_blocks/key_item/Key_Item_Mapper.js +49 -0
  84. package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Almost_Unique_Item.js +31 -0
  85. package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Cant_Stack_It_Self.js +68 -0
  86. package/src/Allocation_Optimization/preferential_blocks/key_item/rules/Rule_Interface.js +26 -0
  87. package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Intercalation_State.js +49 -0
  88. package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Orientation_Filter.js +33 -0
  89. package/src/Allocation_Optimization/tie_ratio/Tie_Ratio_Vertical_Stack_Filter.js +20 -0
  90. package/src/Allocation_Optimization/tie_ratio/collect_tie_ratio_orientations_below_footprint.js +64 -0
  91. package/src/Allocation_Optimization/tie_ratio/filter_blocks_by_orientation.js +17 -0
  92. package/src/Allocation_Optimization/tie_ratio/find_orientation_below_space.js +77 -0
  93. package/src/Allocation_Optimization/tie_ratio/loose_on_block/allocated_item_penetrates_any.js +31 -0
  94. package/src/Allocation_Optimization/tie_ratio/loose_on_block/apply_loose_placement_to_allocated_item.js +94 -0
  95. package/src/Allocation_Optimization/tie_ratio/loose_on_block/axis_overlap_length.js +16 -0
  96. package/src/Allocation_Optimization/tie_ratio/loose_on_block/block_local_origin.js +18 -0
  97. package/src/Allocation_Optimization/tie_ratio/loose_on_block/box_fits_inside_container.js +39 -0
  98. package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_allocated_item_at_placement.js +18 -0
  99. package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_placement_on_generic_supporter.js +64 -0
  100. package/src/Allocation_Optimization/tie_ratio/loose_on_block/build_slot_grid_from_cluster.js +66 -0
  101. package/src/Allocation_Optimization/tie_ratio/loose_on_block/compare_group_ids.js +20 -0
  102. package/src/Allocation_Optimization/tie_ratio/loose_on_block/container_with_pending_wall_items.js +26 -0
  103. package/src/Allocation_Optimization/tie_ratio/loose_on_block/empty_space_is_on_floor.js +16 -0
  104. package/src/Allocation_Optimization/tie_ratio/loose_on_block/finalize_loose_item_placement.js +58 -0
  105. package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_best_generic_supporter_placement.js +58 -0
  106. package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_next_free_slot_index.js +119 -0
  107. package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_supporter_directly_below.js +51 -0
  108. package/src/Allocation_Optimization/tie_ratio/loose_on_block/find_tie_ratio_supporter_cluster.js +57 -0
  109. package/src/Allocation_Optimization/tie_ratio/loose_on_block/footprint_xz_overlap_area.js +26 -0
  110. package/src/Allocation_Optimization/tie_ratio/loose_on_block/item_fits_supporter_slot.js +22 -0
  111. package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_footprint_region_from_options.js +24 -0
  112. package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_item_fits_inside_container.js +21 -0
  113. package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_item_has_geometric_support.js +21 -0
  114. package/src/Allocation_Optimization/tie_ratio/loose_on_block/loose_on_block_slot_state.js +88 -0
  115. package/src/Allocation_Optimization/tie_ratio/loose_on_block/placement_coords_fit_inside_container.js +34 -0
  116. package/src/Allocation_Optimization/tie_ratio/loose_on_block/read_empilhar_area_igual_from_allocation_item.js +12 -0
  117. package/src/Allocation_Optimization/tie_ratio/loose_on_block/realigned_loose_geometry_gates.js +25 -0
  118. package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_loose_on_generic_supporter.js +65 -0
  119. package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_loose_placement_position.js +68 -0
  120. package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_placement_y_at_slot.js +45 -0
  121. package/src/Allocation_Optimization/tie_ratio/loose_on_block/resolve_without_tie_ratio_cluster.js +79 -0
  122. package/src/Allocation_Optimization/tie_ratio/loose_on_block/select_tie_ratio_slot_placement.js +84 -0
  123. package/src/Allocation_Optimization/tie_ratio/loose_on_block/slot_footprint_collision.js +105 -0
  124. package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_cluster_selection.js +119 -0
  125. package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_footprint_overlap.js +56 -0
  126. package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_placement_plane.js +109 -0
  127. package/src/Allocation_Optimization/tie_ratio/loose_on_block/tie_ratio_supporter_predicate.js +23 -0
  128. package/src/Allocation_Optimization/tie_ratio/loose_on_block/try_tie_ratio_slot_placement.js +62 -0
  129. package/src/Allocation_Optimization/tie_ratio/snap_stacked_items_to_floor_footprints.js +138 -0
  130. package/src/Allocation_Optimization/tie_ratio/supporters_by_top_y_index.js +78 -0
  131. package/src/Allocation_Optimization/tie_ratio/tie_ratio_orientation_below_empty_space.js +89 -0
  132. package/src/Allocation_Optimization/tie_ratio/tie_ratio_orientation_from_group.js +48 -0
  133. package/src/Block_Management.js +34 -0
  134. package/src/Blocks_Preparation/Cube_Map_Function.js +27 -0
  135. package/src/Blocks_Wall_Allocation.js +3 -0
  136. package/src/IO/Answer_Status.js +4 -0
  137. package/src/IO/Output_Builder.js +35 -0
  138. package/src/IO/count_allocated_items.js +31 -0
  139. package/src/IO/create_error_response.js +62 -0
  140. package/src/IO/format_allocation_error_message.js +25 -0
  141. package/src/Item_Continuation_Lock.js +129 -0
  142. package/src/Item_Picking_Continuity.js +41 -0
  143. package/src/allocation_flow/chooser_session_state.js +21 -0
  144. package/src/allocation_flow/compound_probe_fallback.js +17 -0
  145. package/src/allocation_flow/container_remaining_capacity.js +23 -0
  146. package/src/allocation_flow/density_group_item_filter.js +31 -0
  147. package/src/allocation_flow/effective_item_fingerprint.js +14 -0
  148. package/src/allocation_flow/item_continuation_lock_gate.js +38 -0
  149. package/src/allocation_flow/no_space_left_recovery.js +48 -0
  150. package/src/allocation_flow/run_allocation_iteration.js +155 -0
  151. package/src/allocation_flow/space_skip_state.js +91 -0
  152. package/src/allocation_flow/try_no_space_left_recovery.js +50 -0
  153. package/src/exceptions/Invalid_Parameter_Exception.js +17 -0
  154. package/src/exceptions/Relational_Allocation_Incomplete_Exception.js +24 -0
  155. package/src/exceptions/Relational_Colocation_Violation_Exception.js +23 -0
  156. package/src/exceptions/Relational_Config_Mismatch_Exception.js +17 -0
  157. package/src/exceptions/There_Is_No_Block_Options_To_Allocate_Exception.js +14 -0
  158. package/src/index.js +6 -0
  159. package/src/input_preparation/Block_Formatter.js +179 -0
  160. package/src/input_preparation/Input_Creator.js +76 -0
  161. package/src/input_preparation/Input_State_Preparation.js +47 -0
  162. package/src/input_preparation/State_Builder.js +27 -0
  163. package/src/input_preparation/block_formatter/align_flush_axis_config.js +36 -0
  164. package/src/input_preparation/block_formatter/align_flush_axis_single_round.js +112 -0
  165. package/src/input_preparation/block_formatter/align_flush_stacked_slots.js +67 -0
  166. package/src/input_preparation/block_formatter/overlapped_slots.js +24 -0
  167. package/src/input_preparation/block_formatter/parallelepiped_shell.js +38 -0
  168. package/src/input_preparation/block_formatter/rectangle_coverage.js +112 -0
  169. package/src/input_preparation/block_formatter/shell_face_coverage.js +64 -0
  170. package/src/input_preparation/block_formatter/shell_snap_convergence.js +104 -0
  171. package/src/input_preparation/block_preparation/Block_Data_To_Object_Transformer.js +57 -0
  172. package/src/input_preparation/block_preparation/Block_Module_Name.js +17 -0
  173. package/src/input_preparation/block_preparation/Blocks_Creator.js +101 -0
  174. package/src/input_preparation/block_preparation/Blocksmith.js +19 -0
  175. package/src/input_preparation/block_preparation/block_modules/create_block_candidates.js +41 -0
  176. package/src/input_preparation/block_preparation/block_modules/manual_blocks.js +10 -0
  177. package/src/input_preparation/block_preparation/block_modules/module_registry.js +20 -0
  178. package/src/input_preparation/block_preparation/block_modules/run_creator.js +34 -0
  179. package/src/input_preparation/block_preparation/block_modules/single_item_blocks.js +12 -0
  180. package/src/input_preparation/block_preparation/block_modules/spiral_blocks.js +12 -0
  181. package/src/input_preparation/block_preparation/block_modules/tie_ratio_blocks.js +12 -0
  182. package/src/input_preparation/block_preparation/block_modules/tower_blocks.js +12 -0
  183. package/src/input_preparation/block_preparation/exceptions/Failed_To_Create_Block_Exception.js +14 -0
  184. package/src/input_preparation/block_preparation/exceptions/Failed_To_Retrieve_Block_Exception.js +17 -0
  185. package/src/input_preparation/block_preparation/exceptions/Missing_Object_Store_Exception.js +10 -0
  186. package/src/input_preparation/block_preparation/exceptions/No_Blocks_Were_Created_Exception.js +14 -0
  187. package/src/input_preparation/block_preparation/input/Input_Creator.js +96 -0
  188. package/src/input_preparation/block_preparation/manual_blocks/Manual_Blocks.js +95 -0
  189. package/src/input_preparation/build_empty_space_finder_options.js +43 -0
  190. package/src/input_preparation/item_preparation/Items_Reader.js +27 -0
  191. package/src/input_preparation/min_extents_from_items.js +29 -0
  192. package/src/input_preparation/stackability_index/Blocks_Stackability_Index_Calculator.js +58 -0
  193. package/src/input_preparation/stackability_index/Slots_Stackability_index_Calculator.js +28 -0
  194. package/src/input_preparation/stackability_index/Stackability_Input_Creator.js +27 -0
  195. package/src/input_preparation/stackability_index/stackability_index_pop_stack.js +81 -0
  196. package/src/input_preparation/stacking_constraints/Weight_Stacking_Validation.js +15 -0
  197. package/src/lp_optimizer_result_status.js +20 -0
  198. package/src/messages/Allocator_Message.js +42 -0
  199. package/src/messages/resolve_error_message_entry.js +57 -0
  200. package/src/models/Allocated_Item.js +136 -0
  201. package/src/models/Allocation_Item.js +219 -0
  202. package/src/models/Block.js +198 -0
  203. package/src/models/Cargo_Profile.js +418 -0
  204. package/src/models/Preloaded_Allocated_Item.js +132 -0
  205. package/src/models/Slot.js +67 -0
  206. package/src/models/Stacking_Rules.js +58 -0
  207. package/src/models/auxiliaryFunctions/Available_Block_Module_List_Creator.js +9 -0
  208. package/src/models/auxiliaryFunctions/Measure_Translator.js +24 -0
  209. package/src/models/auxiliaryFunctions/item_json_reader.js +44 -0
  210. package/src/models/item_json_reader.js +71 -0
  211. package/src/models/placed_item_record.js +70 -0
  212. package/src/models/preloaded_rotation_helpers.js +38 -0
  213. package/src/models/slots_have_same_measure.js +45 -0
  214. package/src/models/transport/Container.js +162 -0
  215. package/src/models/transport/Transport.js +62 -0
  216. package/src/models/transport/build_stacking_feasibility_checker.js +64 -0
  217. package/src/models/transport/container_stacking_checkpoint.js +42 -0
  218. package/src/models/transport/factory/Container_Factory.js +46 -0
  219. package/src/models/transport/factory/Corner_Casting_Factory.js +62 -0
  220. package/src/models/transport/factory/Previously_Allocated_Item_Factory.js +28 -0
  221. package/src/models/transport/factory/Transport_Factory.js +13 -0
  222. package/src/models/transport/items_for_empty_space_finder.js +91 -0
  223. package/src/models/transport/resolve_container_stacking_inputs.js +23 -0
  224. package/src/models/transport/stacking_input_from_wire.js +58 -0
  225. package/src/optimizer_connection_errors.js +50 -0
  226. package/src/relational/Relational_Error_Codes.js +7 -0
  227. package/src/relational/finalize_relational_allocation.js +20 -0
  228. package/src/relational/has_relational_items.js +11 -0
  229. package/src/relational/is_relational_error_code.js +15 -0
  230. package/src/relational/resolve_relational_container_sequences.js +29 -0
  231. package/src/run_core_allocation.js +118 -0
  232. package/src/space_and_block_chooser/Space_And_Blocks_Chooser.js +115 -0
  233. package/src/space_and_block_chooser/blocks_filters/Block_Filter_Interface.js +19 -0
  234. package/src/space_and_block_chooser/blocks_filters/Filter_Runner.js +46 -0
  235. package/src/space_and_block_chooser/blocks_filters/initial_blocks_filter/Block_With_Overlapped_Slots_Filter.js +14 -0
  236. package/src/space_and_block_chooser/blocks_filters/initial_blocks_filter/Initial_Blocks_Filter_List.js +19 -0
  237. package/src/space_and_block_chooser/blocks_filters/pos_selection_filters/Blocks_Bigger_Than_Space_Filter.js +17 -0
  238. package/src/space_and_block_chooser/blocks_filters/pos_selection_filters/Post_Selection_Filter_List.js +9 -0
  239. package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/Insuficient_Items_Filter.js +81 -0
  240. package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/Pre_Selection_Filter_List.js +8 -0
  241. package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/max_tower_height/Blocks_Lower_Than_Max_Tower_Height.js +23 -0
  242. package/src/space_and_block_chooser/blocks_filters/pre_selection_filter/max_tower_height/Max_Tower_Height.js +82 -0
  243. package/src/space_and_block_chooser/build_allocated_item_snapshots.js +19 -0
  244. package/src/space_and_block_chooser/compound_first_empty_space_branch.js +61 -0
  245. package/src/space_and_block_chooser/compound_first_with_leftover_fill.js +142 -0
  246. package/src/space_and_block_chooser/compound_first_without_leftover_fill.js +56 -0
  247. package/src/space_and_block_chooser/empty_spaces_where_post_selection_keeps_blocks.js +83 -0
  248. package/src/space_and_block_chooser/exceptions/Invalid_Space_To_Allocate_Exception.js +14 -0
  249. package/src/space_and_block_chooser/leftover_space_memory.js +113 -0
  250. package/src/space_and_block_chooser/leftover_unitary_blocks.js +153 -0
  251. package/src/space_and_block_chooser/leftover_unitary_empty_spaces.js +135 -0
  252. package/src/space_and_block_chooser/probe_set_pool.js +35 -0
  253. package/src/space_and_block_chooser/run_space_and_block_selection_attempt.js +88 -0
  254. package/src/tools/Array_Validator.js +6 -0
  255. package/src/tools/Clone.js +27 -0
  256. package/src/tools/Hash.js +8 -0
  257. package/src/tools/Rounder.js +5 -0
  258. package/src/tools/String_To_Boolean.js +12 -0
  259. package/src/tools/cargo_profile/Cargo_Profile_Field_Value_Resolver.js +44 -0
  260. package/src/tools/compact_items_with_stock.js +9 -0
  261. package/src/tools/mm_to_allocation_domain.js +14 -0
  262. package/src/tracing/Allocation_Tracer.js +52 -0
  263. package/src/tracing/Trace_Context.js +18 -0
  264. package/src/tracing/trace_outcome.js +18 -0
  265. package/src/tracing/traced_step.js +57 -0
  266. package/src/validation/Item_Continuation_Lock_Flag.js +52 -0
  267. package/src/validation/Item_Validation.js +29 -0
  268. package/src/validation/Relational_Colocation_Validator.js +60 -0
  269. package/src/validation/Relational_Completeness_Validator.js +146 -0
  270. package/src/validation/Relational_Continuation_Lock_Validation.js +37 -0
  271. package/src/validation/Relational_Proportional_Normalizer.js +194 -0
  272. package/src/validation/Validation.js +9 -0
  273. package/src/validation/Validation_Runner.js +20 -0
  274. package/src/validation/exceptions/Invalid_Block_Module_Config_Exception.js +14 -0
  275. package/src/validation/exceptions/Invalid_Input_Exception.js +14 -0
  276. package/src/validation/exceptions/Invalid_Input_Type_Exception.js +14 -0
  277. package/src/validation/schemas/allocated_item_schema.js +18 -0
  278. package/src/validation/schemas/allocation_request_schema.js +178 -0
  279. package/src/validation/schemas/container_row_schema.js +16 -0
  280. package/src/validation/schemas/item_schema.js +60 -0
  281. package/src/validation/schemas/transport_env_schema.js +19 -0
  282. package/src/validation/validate_block_module_config.js +147 -0
@@ -0,0 +1,159 @@
1
+ const No_Available_Items_Exception = require('./exceptions/No_Available_Items_Exception')
2
+ const No_Slots_For_Items_Exception = require('./exceptions/No_Slots_For_Items_Exception')
3
+ const Cargo_Profile = require('../../models/Cargo_Profile')
4
+ const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
5
+ const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
6
+ const Allocated_Item = require('../../models/Allocated_Item')
7
+ const { distribute_items_by_weight_range } = require('./Weight_Slot_Distribution')
8
+ const {
9
+ resolve_choose_item_heuristic_context,
10
+ format_slot_label_for_exception
11
+ } = require('./Choose_Item_Heuristic_Context')
12
+ const {
13
+ calculate_total_stack_slots,
14
+ sort_stacking_slots_by_proximity
15
+ } = require('./Stack_Slot_Calculator')
16
+ const { order_items_by_capacity_bias } = require('./Capacity_Bias_Item_Order')
17
+
18
+ /**
19
+ * Chooses an item from available items by distributing them into stacking slots by weight
20
+ * and returning the item in the slot closest to the block slot position.
21
+ * @param {object} data - Input bag.
22
+ * @param {object} [data.slot] - Slot with get_y() and get_height() (production).
23
+ * @param {object} [data.block_slot] - Legacy alias for slot (tests).
24
+ * @param {object} [data.container] - Container with get_height() and is_a_valid_stacking().
25
+ * @param {number} [data.height_limit] - Used with a stub container when data.container is absent.
26
+ * @param {object} [data.item_position] - { x, y, z }; defaults to origin when absent.
27
+ * @param {object[]} data.item_list - Items with get_weight().
28
+ * @param {number} [data.qty_of_slots] - Required when the heuristic runs.
29
+ * @param {string} [data.previous_chosen_item_id] - Optional previous choice.
30
+ * @returns {object} The chosen item.
31
+ * @throws {Item_Bigger_Than_Limit} When item height exceeds height_limit.
32
+ * @throws {Empty_Slot_Error} When no stacking slots have items.
33
+ * @throws {No_Available_Items_Exception} When item_list is empty.
34
+ * @throws {No_Suitable_Item_Exception} When no item passes stacking in any weight band.
35
+ */
36
+ module.exports = function choose_item(data)
37
+ {
38
+ const { item_list, previous_chosen_item_id } = data
39
+ if (item_list.length === 0)
40
+ {
41
+ throw new No_Available_Items_Exception()
42
+ }
43
+ const is_to_prefer_same_id = data.block.get_slot_list().length > 0 && previous_chosen_item_id !== undefined && Cargo_Profile.prefer_block_with_same_item()
44
+ return is_to_prefer_same_id ? prefer_same_id(data) : choose_item_with_heuristic(data)
45
+ }
46
+
47
+ function prefer_same_id(data)
48
+ {
49
+ const { container, item_list, previous_chosen_item_id, item_position } = data
50
+ const allocation_item = item_list.find(item => item.get_id() === previous_chosen_item_id)
51
+ if (allocation_item)
52
+ {
53
+ const result = is_stacking_valid(container, allocation_item, item_position, data.block)
54
+ if (result.is_valid)
55
+ {
56
+ return result.allocated_item
57
+ }
58
+ }
59
+
60
+ return choose_item_with_heuristic(data)
61
+ }
62
+
63
+ /**
64
+ * Heuristic path: weight bands, proximity-ordered bands, stacking validation per candidate.
65
+ * @param {object} data - Input bag (see choose_item).
66
+ * @returns {object} Chosen item.
67
+ */
68
+ function choose_item_with_heuristic(data)
69
+ {
70
+ const { slot, container, item_position } = resolve_choose_item_heuristic_context(data)
71
+ const { item_list, qty_of_slots } = data
72
+ const total_slots = calculate_total_stack_slots(container.get_height(), slot)
73
+ const stacking_slots = distribute_items_by_weight_range(item_list, total_slots)
74
+ const ordered_bands = sort_stacking_slots_by_proximity(
75
+ stacking_slots,
76
+ slot.get_y(),
77
+ slot.get_height()
78
+ )
79
+
80
+ for (const band of ordered_bands)
81
+ {
82
+ const candidate_items = band.items
83
+ while (candidate_items.length > 0)
84
+ {
85
+ const allocation_item = get_item(candidate_items, qty_of_slots, container)
86
+ const result = is_stacking_valid(container, allocation_item, item_position, data.block)
87
+ if (result.is_valid)
88
+ {
89
+ return result.allocated_item
90
+ }
91
+
92
+ remove_item_from_candidate_list(candidate_items, allocation_item)
93
+ }
94
+ }
95
+
96
+ const slot_label = format_slot_label_for_exception(slot)
97
+ throw new No_Suitable_Item_Exception(ALLOCATOR_MESSAGE.NO_SUITABLE_ITEM, [slot_label])
98
+ }
99
+
100
+ function is_stacking_valid(container, allocation_item, item_position, block)
101
+ {
102
+ const allocated_item = new Allocated_Item(
103
+ allocation_item,
104
+ item_position.x,
105
+ item_position.y,
106
+ item_position.z
107
+ )
108
+ if (should_defer_loose_on_block_stacking_validation(block))
109
+ {
110
+ return {
111
+ is_valid: true,
112
+ allocated_item
113
+ }
114
+ }
115
+ const is_valid = container.is_a_valid_stacking(allocated_item)
116
+
117
+ return {
118
+ is_valid,
119
+ allocated_item
120
+ }
121
+ }
122
+
123
+ function should_defer_loose_on_block_stacking_validation(block)
124
+ {
125
+ return Cargo_Profile.stack_loose_on_tie_ratio_blocks()
126
+ && block?.get_slot_list?.().length === 1
127
+ }
128
+
129
+ function remove_item_from_candidate_list(candidate_item_list, allocation_item)
130
+ {
131
+ const index = candidate_item_list.indexOf(allocation_item)
132
+ if (index > -1)
133
+ {
134
+ candidate_item_list.splice(index, 1)
135
+ }
136
+ }
137
+
138
+ function get_item(item_list, qty_of_slots, container)
139
+ {
140
+ if (qty_of_slots === undefined)
141
+ {
142
+ throw new No_Slots_For_Items_Exception()
143
+ }
144
+
145
+ if (item_list.length === 0)
146
+ {
147
+ throw new No_Available_Items_Exception()
148
+ }
149
+
150
+ const ordered_item_list = order_items_by_capacity_bias(item_list, container)
151
+ const preferable_item_list = ordered_item_list.filter(item => item.get_amount() >= qty_of_slots)
152
+
153
+ if (preferable_item_list.length > 0)
154
+ {
155
+ return preferable_item_list[0]
156
+ }
157
+
158
+ return ordered_item_list[0]
159
+ }
@@ -0,0 +1,49 @@
1
+ const choose_item = require('./Item_Chooser')
2
+ const get_available_items_for_slot = require('./Slot_Compatible_Items_Finder')
3
+ const { order_items_by_capacity_bias } = require('./Capacity_Bias_Item_Order')
4
+ const { ge } = require('@jetta/number-compare')
5
+ const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
6
+ const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
7
+
8
+ /**
9
+ * Chooses an item suitable for the given slot from available items, respecting weight and stacking.
10
+ * @param {object} data - Container, block, slot, weight, and item maps.
11
+ * @returns {object} The chosen item for the slot.
12
+ * @throws {No_Suitable_Item_Exception} When no item fits the slot or stacking rules.
13
+ */
14
+ module.exports = function choose_item_for_slot(data)
15
+ {
16
+ const item_list = get_available_item_list(data)
17
+ return choose_item({ ...data, item_list, height_limit: data.container.get_height() })
18
+ }
19
+
20
+ /**
21
+ * @param {object} data
22
+ * @returns {object[]}
23
+ */
24
+ function get_available_item_list(data)
25
+ {
26
+ const { slot, container_supported_weight, item_map, item_amount_map } = data
27
+ const available_items_for_slot = get_available_items_for_slot(slot, item_map, item_amount_map)
28
+ const available_item_list = available_items_for_slot.filter(
29
+ item => item_supports_weight(container_supported_weight, item)
30
+ )
31
+ if (available_item_list.length === 0)
32
+ {
33
+ throw new No_Suitable_Item_Exception(
34
+ ALLOCATOR_MESSAGE.NO_SUITABLE_ITEM,
35
+ [slot.to_string()]
36
+ )
37
+ }
38
+ return order_items_by_capacity_bias(available_item_list, data.container)
39
+ }
40
+
41
+ /**
42
+ * @param {number} max_weight
43
+ * @param {object} item
44
+ * @returns {boolean}
45
+ */
46
+ function item_supports_weight(max_weight, item)
47
+ {
48
+ return ge(max_weight, item.get_weight())
49
+ }
@@ -0,0 +1,88 @@
1
+ const { cube_map_function } = require('../../Blocks_Preparation/Cube_Map_Function')
2
+
3
+ const dimension_index_by_item_map = new WeakMap()
4
+
5
+ /**
6
+ * Returns items that have positive amount and fit the slot (including rotations).
7
+ * Builds a dimension→item index once per `item_map` instance (WeakMap-cached).
8
+ * @param {object} slot - Target slot.
9
+ * @param {object} item_map - Map of item id to item.
10
+ * @param {object} item_amount_map - Map of item to available amount.
11
+ * @returns {Array} List of compatible rotated items.
12
+ */
13
+ module.exports = function get_available_items_for_slot(slot, item_map, item_amount_map)
14
+ {
15
+ const dimension_index = get_or_build_dimension_index(item_map)
16
+ const candidates = dimension_index.get(cube_map_function(slot)) || []
17
+ const compatible = []
18
+ for (const candidate of candidates)
19
+ {
20
+ const item = item_map[candidate.item_id]
21
+ if (!item || item_amount_map.get_item_amount(item) <= 0)
22
+ {
23
+ continue
24
+ }
25
+ compatible.push(item.copy_rotated(item.get_rotated_item(candidate.rotation)))
26
+ }
27
+ return compatible
28
+ }
29
+
30
+ /**
31
+ * @param {object} item_map
32
+ * @returns {Map<string, Array<{ item_id: string, rotation: * }>>}
33
+ */
34
+ function get_or_build_dimension_index(item_map)
35
+ {
36
+ let dimension_index = dimension_index_by_item_map.get(item_map)
37
+ if (dimension_index)
38
+ {
39
+ return dimension_index
40
+ }
41
+ dimension_index = build_dimension_index(item_map)
42
+ dimension_index_by_item_map.set(item_map, dimension_index)
43
+ return dimension_index
44
+ }
45
+
46
+ /**
47
+ * @param {object} item_map
48
+ * @returns {Map<string, Array<{ item_id: string, rotation: * }>>}
49
+ */
50
+ function build_dimension_index(item_map)
51
+ {
52
+ const dimension_index = new Map()
53
+ for (const item_id of Object.keys(item_map))
54
+ {
55
+ index_item_rotations(dimension_index, item_map[item_id], item_id)
56
+ }
57
+ return dimension_index
58
+ }
59
+
60
+ /**
61
+ * @param {Map<string, Array<{ item_id: string, rotation: * }>>} dimension_index
62
+ * @param {object} item
63
+ * @param {string} item_id
64
+ * @returns {void}
65
+ */
66
+ function index_item_rotations(dimension_index, item, item_id)
67
+ {
68
+ const indexed_dimensions = new Set()
69
+ for (const rotation of item.get_rotations())
70
+ {
71
+ const rotated_item = item.get_rotated_item(rotation)
72
+ const dimension_key = cube_map_function(rotated_item)
73
+ if (indexed_dimensions.has(dimension_key))
74
+ {
75
+ continue
76
+ }
77
+ indexed_dimensions.add(dimension_key)
78
+ const candidates = dimension_index.get(dimension_key)
79
+ if (candidates)
80
+ {
81
+ candidates.push({ item_id, rotation })
82
+ }
83
+ else
84
+ {
85
+ dimension_index.set(dimension_key, [{ item_id, rotation }])
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,182 @@
1
+ const choose_item_for_slot = require('./Item_For_Slot_Chooser')
2
+ const No_Suitable_Item_Exception = require('../block_builder/exceptions/No_Suitable_Item_Exception')
3
+ const { ALLOCATOR_MESSAGE } = require('../../messages/Allocator_Message')
4
+ const Allocated_Item = require('../../models/Allocated_Item')
5
+ const { block_has_sufficient_shape_stock } = require('../block_builder/block_shape_stock')
6
+ const { Logger } = require('@jetta/logger')
7
+ const logger = new Logger('Item Consumption Heuristic')
8
+ const order_slots_by_y = (slot_list) => [...slot_list].sort(compare_slot_y_asc)
9
+ const compare_slot_y_asc = (slot_a, slot_b) => slot_a.get_y() - slot_b.get_y()
10
+
11
+ function build_item_map(item_list)
12
+ {
13
+ const item_map = {}
14
+ for (const item of item_list)
15
+ {
16
+ item_map[item.get_id()] = item
17
+ }
18
+ return item_map
19
+ }
20
+
21
+ function process_one_slot(data)
22
+ {
23
+ const allocated_item = choose_item_for_slot(data)
24
+ data.item_amount_map.discount_single_item(allocated_item)
25
+ const next_weight = data.container_supported_weight - allocated_item.get_weight()
26
+ return { allocated_item, next_weight }
27
+ }
28
+
29
+ /**
30
+ * Assigns items to block slots using a consumption heuristic (slot order and stacking).
31
+ */
32
+ class Item_Consumption_Heuristic
33
+ {
34
+ #empty_space
35
+ #item_map = {}
36
+ #item_amount_map
37
+ #container
38
+
39
+ /**
40
+ * @param {object[]} item_list - Items available for allocation.
41
+ * @param {object} item_amount_map - Tracks remaining amount per item.
42
+ * @param {object} container - Target container.
43
+ */
44
+ constructor(empty_space, item_list, item_amount_map, container)
45
+ {
46
+ this.#empty_space = empty_space
47
+ this.#item_map = build_item_map(item_list)
48
+ this.#item_amount_map = item_amount_map
49
+ this.#container = container
50
+ }
51
+
52
+ /**
53
+ * Assigns one item per slot of the block, ordered by slot y, updating weight and amounts.
54
+ * @param {object} block - Block whose slots are to be filled.
55
+ * @param {number} container_supported_weight - Supported weight for the layer.
56
+ * @param {object} item_position - Base block position { x, y, z } before per-slot offsets (from space / block placement).
57
+ * @param {string|undefined} picking_continuity_seed - Prior SKU id to prefer on the first slot.
58
+ * @returns {object[]|undefined} Allocated items, or undefined if a non-rethrown error occurred.
59
+ */
60
+ assign_items_to_slots(block, container_supported_weight, item_position, picking_continuity_seed)
61
+ {
62
+ const slot_count = block.get_slot_list().length
63
+ if (slot_count === 0)
64
+ {
65
+ return []
66
+ }
67
+ if (!block_has_sufficient_shape_stock(block, this.#item_map, this.#item_amount_map))
68
+ {
69
+ throw new No_Suitable_Item_Exception(
70
+ ALLOCATOR_MESSAGE.INSUFFICIENT_SHAPE_STOCK,
71
+ [String(slot_count)]
72
+ )
73
+ }
74
+ logger.debug(`assigning items to ${slot_count} slot(s)`)
75
+ return this.#assign_items_for_ordered_slots(
76
+ block,
77
+ Number(container_supported_weight),
78
+ item_position,
79
+ picking_continuity_seed
80
+ )
81
+ }
82
+
83
+ /**
84
+ * Assigns specific items to slots using the LP plan (relational co-location path).
85
+ * @param {object} block
86
+ * @param {string[]} slot_item_ids - Item ids per slot (same order as ordered slots).
87
+ * @param {number} container_supported_weight
88
+ * @param {object} item_position
89
+ * @returns {object[]}
90
+ */
91
+ assign_items_from_plan(block, slot_item_ids, container_supported_weight, item_position)
92
+ {
93
+ const slot_list = order_slots_by_y(block.get_slot_list())
94
+ const allocated_item_list = []
95
+
96
+ for (let index = 0; index < slot_list.length; index++)
97
+ {
98
+ const slot = slot_list[index]
99
+ const item_id = slot_item_ids[index]
100
+ const allocation_item = this.#item_map[item_id]
101
+ if (!allocation_item || allocation_item.get_amount() <= 0)
102
+ {
103
+ throw new No_Suitable_Item_Exception(
104
+ ALLOCATOR_MESSAGE.LP_PLAN_ITEM_UNAVAILABLE,
105
+ [String(item_id), slot.to_string()]
106
+ )
107
+ }
108
+
109
+ const current_item_position = this.#update_item_position(item_position, slot)
110
+ const allocated_item = new Allocated_Item(
111
+ allocation_item,
112
+ current_item_position.x,
113
+ current_item_position.y,
114
+ current_item_position.z
115
+ )
116
+
117
+ if (!this.#container.is_a_valid_stacking(allocated_item))
118
+ {
119
+ throw new No_Suitable_Item_Exception(
120
+ ALLOCATOR_MESSAGE.LP_PLAN_ITEM_STACKING_FAILED,
121
+ [String(item_id), slot.to_string()]
122
+ )
123
+ }
124
+
125
+ this.#item_amount_map.discount_single_item(allocated_item)
126
+ allocated_item_list.push(allocated_item)
127
+ }
128
+
129
+ logger.debug(`assigned ${allocated_item_list.length} item(s) from LP plan`)
130
+ return allocated_item_list
131
+ }
132
+
133
+ #update_item_position(item_position, slot)
134
+ {
135
+ return {
136
+ x: item_position.x + slot.get_x(),
137
+ y: item_position.y + slot.get_y(),
138
+ z: item_position.z + slot.get_z()
139
+ }
140
+ }
141
+
142
+ #assign_items_for_ordered_slots(block, initial_weight, starting_item_position, picking_continuity_seed)
143
+ {
144
+ const slot_list = order_slots_by_y(block.get_slot_list())
145
+ const allocated_item_list = new Array(slot_list.length)
146
+ const provisional_amount_map = this.#item_amount_map.copy()
147
+ let current_weight = initial_weight
148
+ let previous_chosen_item_id = picking_continuity_seed ?? undefined
149
+ let qty_of_slots = slot_list.length
150
+
151
+ for (let index = 0; index < slot_list.length; index++)
152
+ {
153
+ const slot = slot_list[index]
154
+ const current_item_position = this.#update_item_position(starting_item_position, slot)
155
+ const result = process_one_slot({
156
+ empty_space: this.#empty_space,
157
+ slot,
158
+ container_supported_weight: current_weight,
159
+ container: this.#container,
160
+ block,
161
+ item_map: this.#item_map,
162
+ item_amount_map: provisional_amount_map,
163
+ previous_chosen_item_id,
164
+ qty_of_slots,
165
+ item_position: current_item_position
166
+ })
167
+ allocated_item_list[index] = result.allocated_item
168
+ current_weight = result.next_weight
169
+ previous_chosen_item_id = result.allocated_item.get_id()
170
+ qty_of_slots--
171
+ }
172
+
173
+ for (const allocated_item of allocated_item_list)
174
+ {
175
+ this.#item_amount_map.discount_single_item(allocated_item)
176
+ }
177
+
178
+ return allocated_item_list
179
+ }
180
+ }
181
+
182
+ module.exports = Item_Consumption_Heuristic
@@ -0,0 +1,87 @@
1
+ const Empty_Slot_Error = require('./exceptions/Empty_Slot_Exception')
2
+ const Item_Bigger_Than_Limit = require('./exceptions/Item_Taller_Than_Limit_Exception')
3
+
4
+ /**
5
+ * @param {number} height_limit - Maximum stack height.
6
+ * @param {object} item - With get_height().
7
+ * @returns {number} Number of vertical slots that fit.
8
+ * @throws {Item_Bigger_Than_Limit} When item height exceeds height_limit.
9
+ */
10
+ function calculate_total_stack_slots(height_limit, item)
11
+ {
12
+ const total_slots = Math.floor(height_limit / item.get_height())
13
+ if (total_slots === 0)
14
+ {
15
+ throw new Item_Bigger_Than_Limit(height_limit, item)
16
+ }
17
+ return total_slots
18
+ }
19
+
20
+ /**
21
+ * @param {object[]} slots - Slots with vertical_index and items.
22
+ * @param {number} target_y - Target y position.
23
+ * @param {number} item_height - Height per slot.
24
+ * @returns {object} Slot closest to target_y.
25
+ * @throws {Empty_Slot_Error} When slots is empty.
26
+ */
27
+ function find_closest_slot_to_position(slots, target_y, item_height)
28
+ {
29
+ const first_slot = slots[0]
30
+ if (!first_slot)
31
+ {
32
+ throw new Empty_Slot_Error(target_y)
33
+ }
34
+
35
+ let closest_slot = first_slot
36
+ let smallest_difference = Infinity
37
+
38
+ for (const slot of slots)
39
+ {
40
+ const slot_y = slot.vertical_index * item_height
41
+ const distance = Math.abs(slot_y - target_y)
42
+ if (distance < smallest_difference)
43
+ {
44
+ smallest_difference = distance
45
+ closest_slot = slot
46
+ }
47
+ }
48
+
49
+ return closest_slot
50
+ }
51
+
52
+ /**
53
+ * Non-empty stacking slots ordered by vertical distance to target_y (ties keep input order).
54
+ * @param {object[]} slots - Slots with vertical_index and items.
55
+ * @param {number} target_y - Target y position.
56
+ * @param {number} item_height - Height per slot.
57
+ * @returns {object[]} Same slot objects as input, sorted by proximity.
58
+ * @throws {Empty_Slot_Error} When slots is empty.
59
+ */
60
+ function sort_stacking_slots_by_proximity(slots, target_y, item_height)
61
+ {
62
+ const first_slot = slots[0]
63
+ if (!first_slot)
64
+ {
65
+ throw new Empty_Slot_Error(target_y)
66
+ }
67
+ const with_meta = slots.map((slot, index) => ({
68
+ slot,
69
+ distance: Math.abs(slot.vertical_index * item_height - target_y),
70
+ index
71
+ }))
72
+ with_meta.sort((a, b) =>
73
+ {
74
+ if (a.distance !== b.distance)
75
+ {
76
+ return a.distance - b.distance
77
+ }
78
+ return a.index - b.index
79
+ })
80
+ return with_meta.map((entry) => entry.slot)
81
+ }
82
+
83
+ module.exports = {
84
+ calculate_total_stack_slots,
85
+ find_closest_slot_to_position,
86
+ sort_stacking_slots_by_proximity
87
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Distributes items into stacking slots by normalized weight (heavier toward bottom).
3
+ * @param {object[]} items - Items with get_weight().
4
+ * @param {number} total_slots - Number of vertical slots.
5
+ * @returns {object[]} Slots with vertical_index and items (non-empty only).
6
+ */
7
+ function distribute_items_by_weight_range(items, total_slots)
8
+ {
9
+ const normalized_weights = normalize_weights(items)
10
+ const slots = initialize_slots(total_slots)
11
+
12
+ for (let index = 0; index < items.length; index++)
13
+ {
14
+ const relative_weight = normalized_weights[index]
15
+ const slot_index = map_weight_to_slot_index(relative_weight, total_slots)
16
+ slots[slot_index].items.push(items[index])
17
+ }
18
+
19
+ return slots.filter(slot_has_items)
20
+ }
21
+
22
+ function slot_has_items(slot)
23
+ {
24
+ return slot.items.length > 0
25
+ }
26
+
27
+ /**
28
+ * @param {object[]} item_list - Items with get_weight().
29
+ * @returns {number[]} Weights normalized to [0, 1] per item.
30
+ */
31
+ function normalize_weights(item_list)
32
+ {
33
+ const weights = item_list.map(get_item_weight)
34
+ const min = Math.min(...weights)
35
+ const max = Math.max(...weights)
36
+ const delta = max - min || 1e-6
37
+ const result = new Array(item_list.length)
38
+ for (let index = 0; index < item_list.length; index++)
39
+ {
40
+ result[index] = normalized_weight(item_list[index], min, delta)
41
+ }
42
+ return result
43
+ }
44
+
45
+ function get_item_weight(item)
46
+ {
47
+ return item.get_weight()
48
+ }
49
+
50
+ function normalized_weight(item, min, delta)
51
+ {
52
+ return (item.get_weight() - min) / delta
53
+ }
54
+
55
+ function initialize_slots(count)
56
+ {
57
+ const slots = new Array(count)
58
+ for (let index = 0; index < count; index++)
59
+ {
60
+ slots[index] = { vertical_index: index, items: [] }
61
+ }
62
+ return slots
63
+ }
64
+
65
+ function map_weight_to_slot_index(relative_weight, total_slots)
66
+ {
67
+ const raw_index = Math.floor(relative_weight * total_slots)
68
+ const clamped_index = Math.max(0, Math.min(total_slots - 1, raw_index))
69
+ return total_slots - 1 - clamped_index
70
+ }
71
+
72
+ module.exports = { distribute_items_by_weight_range }
@@ -0,0 +1,17 @@
1
+ const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
2
+ const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
3
+
4
+ class Empty_Slot_Exception extends Error
5
+ {
6
+ /**
7
+ * @param {number} target_y
8
+ */
9
+ constructor(target_y)
10
+ {
11
+ const message_key = ALLOCATOR_MESSAGE.EMPTY_SLOT
12
+ super(message_key)
13
+ this.message_entry = build_message_entry(message_key, [String(target_y)])
14
+ }
15
+ }
16
+
17
+ module.exports = Empty_Slot_Exception
@@ -0,0 +1,21 @@
1
+ const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
2
+ const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
3
+
4
+ class Item_Taller_Than_Limit_Exception extends Error
5
+ {
6
+ /**
7
+ * @param {number} height_limit
8
+ * @param {object} item
9
+ */
10
+ constructor(height_limit, item)
11
+ {
12
+ const message_key = ALLOCATOR_MESSAGE.ITEM_TALLER_THAN_LIMIT
13
+ super(message_key)
14
+ this.message_entry = build_message_entry(
15
+ message_key,
16
+ [String(item.get_height()), String(height_limit)]
17
+ )
18
+ }
19
+ }
20
+
21
+ module.exports = Item_Taller_Than_Limit_Exception
@@ -0,0 +1,14 @@
1
+ const { build_message_entry } = require('../../../messages/resolve_error_message_entry')
2
+ const { ALLOCATOR_MESSAGE } = require('../../../messages/Allocator_Message')
3
+
4
+ class No_Available_Items_Exception extends Error
5
+ {
6
+ constructor()
7
+ {
8
+ const message_key = ALLOCATOR_MESSAGE.NO_AVAILABLE_ITEMS
9
+ super(message_key)
10
+ this.message_entry = build_message_entry(message_key)
11
+ }
12
+ }
13
+
14
+ module.exports = No_Available_Items_Exception