@jetta/blocks-allocator 0.2.1-2 → 0.2.1-4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetta/blocks-allocator",
3
- "version": "0.2.1-2",
3
+ "version": "0.2.1-4",
4
4
  "description": "Blocks wall allocation library",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -41,7 +41,7 @@
41
41
  "license": "ISC",
42
42
  "dependencies": {
43
43
  "@jetta/axle-load-calculator": "^0.4.1",
44
- "@jetta/empty-spaces-manager": "^0.1.1-0",
44
+ "@jetta/empty-spaces-manager": "^0.1.2-1",
45
45
  "@jetta/item-amount-controller": "0.1.0-0",
46
46
  "@jetta/logger": "^2.0.1",
47
47
  "@jetta/lp-framework": "2.1.0-6",
@@ -0,0 +1,67 @@
1
+ const leftover_unitary_blocks = require('../space_and_block_chooser/leftover_unitary_blocks')
2
+
3
+ /**
4
+ * Records a stall, unless this is the one-shot retry that admits hidden unitaries.
5
+ * @param {object} context
6
+ * @param {object[]} effective_item_list
7
+ * @param {Record<string, number>} amounts_before
8
+ * @param {object} empty_space
9
+ * @param {string} fingerprint
10
+ * @param {object[]} block_list
11
+ * @returns {boolean} True when any effective item amount decreased.
12
+ */
13
+ function update_skip_state_after_attempt(
14
+ context,
15
+ effective_item_list,
16
+ amounts_before,
17
+ empty_space,
18
+ fingerprint,
19
+ block_list
20
+ )
21
+ {
22
+ if (amount_decreased(effective_item_list, amounts_before))
23
+ {
24
+ context.space_skip_state.clear_stalls()
25
+ context.recovery_state.count = 0
26
+ return true
27
+ }
28
+ if (defer_stall_for_hidden_unitaries(context, block_list))
29
+ {
30
+ return false
31
+ }
32
+ context.space_skip_state.record_stall(empty_space, fingerprint)
33
+ return false
34
+ }
35
+
36
+ /**
37
+ * @param {object[]} effective_item_list
38
+ * @param {Record<string, number>} amounts_before
39
+ * @returns {boolean}
40
+ */
41
+ function amount_decreased(effective_item_list, amounts_before)
42
+ {
43
+ return effective_item_list.some(item => item.get_amount() < amounts_before[item.get_id()])
44
+ }
45
+
46
+ /**
47
+ * Opens the leftover catalog once when a no-progress attempt used only remembered unitaries.
48
+ * @param {object} context
49
+ * @param {object[]} block_list
50
+ * @returns {boolean} True when the space must be retried before it is stalled.
51
+ */
52
+ function defer_stall_for_hidden_unitaries(context, block_list)
53
+ {
54
+ const session = context.chooser_session?.obligate_compound_session
55
+ const remembered_only = leftover_unitary_blocks.blocks_are_remembered_unitaries_only(
56
+ block_list ?? [],
57
+ session
58
+ )
59
+ if (!remembered_only)
60
+ {
61
+ return false
62
+ }
63
+ session.admit_non_remembered_unitaries = true
64
+ return true
65
+ }
66
+
67
+ module.exports = { update_skip_state_after_attempt }
@@ -9,6 +9,7 @@ const {
9
9
  update_item_continuation_lock
10
10
  } = require('./item_continuation_lock_gate')
11
11
  const { empty_space_stacks_on_tie_ratio_supporter } = require('../Allocation_Optimization/tie_ratio/tie_ratio_orientation_below_empty_space')
12
+ const { update_skip_state_after_attempt } = require('./leftover_catalog_retry')
12
13
 
13
14
  /**
14
15
  * Runs one allocation iteration: chooser, LP attempt, skip-state update.
@@ -69,7 +70,8 @@ async function run_allocation_iteration(context, container, locked_item)
69
70
  effective_item_list,
70
71
  amounts_before,
71
72
  empty_space,
72
- fingerprint
73
+ fingerprint,
74
+ block_list
73
75
  )
74
76
  update_item_continuation_lock(context, wall_output.single_slot_allocated_item_ids)
75
77
  context.picking_continuity.update_from_wall(wall_output.last_allocated_item_id)
@@ -117,29 +119,6 @@ function update_compound_probe_session(context, block_list, effective_item_list,
117
119
  }
118
120
  }
119
121
 
120
- /**
121
- * @param {object} context
122
- * @param {object[]} effective_item_list
123
- * @param {Record<string, number>} amounts_before
124
- * @param {object} empty_space
125
- * @param {string} fingerprint
126
- * @returns {boolean} True when any effective item amount decreased.
127
- */
128
- function update_skip_state_after_attempt(context, effective_item_list, amounts_before, empty_space, fingerprint)
129
- {
130
- const progressed = effective_item_list.some(
131
- item => item.get_amount() < amounts_before[item.get_id()]
132
- )
133
- if (progressed)
134
- {
135
- context.space_skip_state.clear_stalls()
136
- context.recovery_state.count = 0
137
- return true
138
- }
139
- context.space_skip_state.record_stall(empty_space, fingerprint)
140
- return false
141
- }
142
-
143
122
  /**
144
123
  * @param {object[]} block_list
145
124
  * @returns {void}
@@ -152,4 +131,4 @@ function assert_blocks_available(block_list)
152
131
  }
153
132
  }
154
133
 
155
- module.exports = { run_allocation_iteration }
134
+ module.exports = { run_allocation_iteration, update_skip_state_after_attempt }
@@ -1,19 +1,108 @@
1
1
  /**
2
- * Maps allocated container items to empty-space chooser snapshots.
3
- * @param {object} container - Container with get_allocated_items().
4
- * @returns {Array<{ x: number, y: number, z: number, width: number, height: number, length: number }>}
2
+ * @param {object} item - Allocated item.
3
+ * @param {string} reader_name - Accessor name.
4
+ * @returns {string|undefined} Non-empty text when the accessor returns one.
5
5
  */
6
- function build_allocated_item_snapshots(container)
6
+ function optional_identity(item, reader_name)
7
7
  {
8
- const allocated_items = container.get_allocated_items?.() ?? []
9
- return allocated_items.map(item => ({
8
+ const reader = item[reader_name]
9
+ if (typeof reader !== 'function')
10
+ {
11
+ return undefined
12
+ }
13
+ const value = reader.call(item)
14
+ if (typeof value !== 'string' || value.length === 0)
15
+ {
16
+ return undefined
17
+ }
18
+ return value
19
+ }
20
+
21
+ /**
22
+ * @param {object} snapshot - Geometry snapshot.
23
+ * @param {object} item - Allocated item.
24
+ * @returns {object} Snapshot with identity fields when the item exposes them.
25
+ */
26
+ function assign_identity(snapshot, item)
27
+ {
28
+ const item_id = optional_identity(item, 'get_id')
29
+ const tie_ratio_orientation = optional_identity(item, 'get_tie_ratio_orientation')
30
+ if (item_id !== undefined)
31
+ {
32
+ snapshot.item_id = item_id
33
+ }
34
+ if (tie_ratio_orientation !== undefined)
35
+ {
36
+ snapshot.tie_ratio_orientation = tie_ratio_orientation
37
+ }
38
+ return assign_stacking(snapshot, item)
39
+ }
40
+
41
+ /**
42
+ * @param {object} item - Allocated item.
43
+ * @returns {object|undefined} Stacking info from the item or its source.
44
+ */
45
+ function read_stacking_info(item)
46
+ {
47
+ const source = typeof item.get_stacking_source_item === 'function'
48
+ ? item.get_stacking_source_item()
49
+ : item
50
+ if (typeof source.get_stacking_info !== 'function')
51
+ {
52
+ return undefined
53
+ }
54
+ return source.get_stacking_info()
55
+ }
56
+
57
+ /**
58
+ * @param {object} snapshot - Geometry snapshot.
59
+ * @param {object} item - Allocated item.
60
+ * @returns {object} Snapshot with stacking fields when present.
61
+ */
62
+ function assign_stacking(snapshot, item)
63
+ {
64
+ const info = read_stacking_info(item)
65
+ if (!info)
66
+ {
67
+ return snapshot
68
+ }
69
+ if (typeof info.stacking_family === 'string' && info.stacking_family.length > 0)
70
+ {
71
+ snapshot.stacking_family = info.stacking_family
72
+ }
73
+ if (Array.isArray(info.supported_families) && info.supported_families.length > 0)
74
+ {
75
+ snapshot.supported_families = info.supported_families
76
+ }
77
+ return snapshot
78
+ }
79
+
80
+ /**
81
+ * @param {object} item - Allocated item.
82
+ * @returns {object} Chooser snapshot.
83
+ */
84
+ function snapshot_from_item(item)
85
+ {
86
+ const snapshot = {
10
87
  x: item.get_x(),
11
88
  y: item.get_y(),
12
89
  z: item.get_z(),
13
90
  width: item.get_width(),
14
91
  height: item.get_height(),
15
92
  length: item.get_length()
16
- }))
93
+ }
94
+ return assign_identity(snapshot, item)
95
+ }
96
+
97
+ /**
98
+ * Maps allocated container items to empty-space chooser snapshots.
99
+ * @param {object} container - Container with get_allocated_items().
100
+ * @returns {Array<object>} Geometry plus optional identity and stacking fields.
101
+ */
102
+ function build_allocated_item_snapshots(container)
103
+ {
104
+ const allocated_items = container.get_allocated_items?.() ?? []
105
+ return allocated_items.map(snapshot_from_item)
17
106
  }
18
107
 
19
108
  module.exports = build_allocated_item_snapshots
@@ -24,10 +24,10 @@ async function resolve_after_compound_probe(
24
24
  )
25
25
  {
26
26
  const compound_block_list = compound_blocks_from_list(pre_selected_block_list)
27
- const leftover_block_list = leftover_unitary_blocks(
27
+ const leftover_block_list = leftover_unitary_blocks.from_session(
28
28
  pre_selected_block_list,
29
29
  compound_block_list,
30
- filter_data.obligate_compound_session?.leftover_sku_shape_hashes
30
+ filter_data.obligate_compound_session
31
31
  )
32
32
  leftover_unitary_blocks.remember_leftover_sku_hashes(
33
33
  filter_data.obligate_compound_session,
@@ -0,0 +1,159 @@
1
+ const { cube_map_function } = require('../Blocks_Preparation/Cube_Map_Function')
2
+ const round = require('../tools/Rounder')
3
+
4
+ /**
5
+ * Stores leftover SKU shape hashes while compounds still remain.
6
+ * @param {{ leftover_sku_shape_hashes?: string[] }|undefined} session
7
+ * @param {object[]} leftover_block_list
8
+ * @param {object[]} compound_block_list
9
+ * @returns {void}
10
+ */
11
+ function remember_leftover_sku_hashes(session, leftover_block_list, compound_block_list)
12
+ {
13
+ if (!session || compound_block_list.length === 0 || leftover_block_list.length === 0)
14
+ {
15
+ return
16
+ }
17
+ if (session.leftover_sku_shape_hashes?.length > 0)
18
+ {
19
+ return
20
+ }
21
+ session.leftover_sku_shape_hashes = [...leftover_sku_shape_hashes(leftover_block_list)]
22
+ }
23
+
24
+ /**
25
+ * Width/height/length hashes for leftover 1-slot blocks, including swapped floor axes.
26
+ * @param {object[]} leftover_block_list
27
+ * @returns {Set<string>}
28
+ */
29
+ function leftover_sku_shape_hashes(leftover_block_list)
30
+ {
31
+ const hashes = new Set()
32
+ for (const block of leftover_block_list)
33
+ {
34
+ add_slot_orientation_hashes(hashes, block)
35
+ }
36
+ return hashes
37
+ }
38
+
39
+ /**
40
+ * @param {Set<string>} hashes
41
+ * @param {object} block
42
+ * @returns {void}
43
+ */
44
+ function add_slot_orientation_hashes(hashes, block)
45
+ {
46
+ if (typeof block.get_slot_list !== 'function')
47
+ {
48
+ return
49
+ }
50
+ const slot_list = block.get_slot_list()
51
+ if (slot_list.length !== 1 || typeof slot_list[0].get_width !== 'function')
52
+ {
53
+ return
54
+ }
55
+ hashes.add(cube_map_function(slot_list[0]))
56
+ hashes.add(swapped_length_width_hash(slot_list[0]))
57
+ }
58
+
59
+ /**
60
+ * @param {object} slot
61
+ * @returns {string}
62
+ */
63
+ function swapped_length_width_hash(slot)
64
+ {
65
+ return round(slot.get_length()) + ';' + round(slot.get_height()) + ';' + round(slot.get_width())
66
+ }
67
+
68
+ /**
69
+ * @param {Set<string>|string[]|undefined} remembered_sku_hashes
70
+ * @returns {Set<string>}
71
+ */
72
+ function to_hash_set(remembered_sku_hashes)
73
+ {
74
+ if (!remembered_sku_hashes)
75
+ {
76
+ return new Set()
77
+ }
78
+ if (remembered_sku_hashes instanceof Set)
79
+ {
80
+ return remembered_sku_hashes
81
+ }
82
+ return new Set(remembered_sku_hashes)
83
+ }
84
+
85
+ /**
86
+ * @param {object[]} compound_block_list
87
+ * @returns {Set<string>}
88
+ */
89
+ function compound_slot_shape_hashes(compound_block_list)
90
+ {
91
+ const hashes = new Set()
92
+ for (const block of compound_block_list)
93
+ {
94
+ add_compound_slot_hashes(hashes, block)
95
+ }
96
+ return hashes
97
+ }
98
+
99
+ /**
100
+ * @param {Set<string>} hashes
101
+ * @param {object} block
102
+ * @returns {void}
103
+ */
104
+ function add_compound_slot_hashes(hashes, block)
105
+ {
106
+ if (typeof block.get_slot_list !== 'function')
107
+ {
108
+ return
109
+ }
110
+ for (const slot of block.get_slot_list())
111
+ {
112
+ add_measured_slot_hash(hashes, slot)
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param {Set<string>} hashes
118
+ * @param {object} slot
119
+ * @returns {void}
120
+ */
121
+ function add_measured_slot_hash(hashes, slot)
122
+ {
123
+ if (typeof slot.get_width !== 'function')
124
+ {
125
+ return
126
+ }
127
+ hashes.add(cube_map_function(slot))
128
+ hashes.add(swapped_length_width_hash(slot))
129
+ }
130
+
131
+ /**
132
+ * @param {object} block
133
+ * @param {Set<string>} remembered
134
+ * @returns {boolean}
135
+ */
136
+ function is_unitary_matching_hashes(block, remembered)
137
+ {
138
+ if (typeof block.get_slot_list !== 'function')
139
+ {
140
+ return false
141
+ }
142
+ const slot_list = block.get_slot_list()
143
+ if (slot_list.length !== 1 || typeof slot_list[0].get_width !== 'function')
144
+ {
145
+ return false
146
+ }
147
+ return remembered.has(cube_map_function(slot_list[0]))
148
+ || remembered.has(swapped_length_width_hash(slot_list[0]))
149
+ }
150
+
151
+ module.exports = {
152
+ remember_leftover_sku_hashes,
153
+ leftover_sku_shape_hashes,
154
+ to_hash_set,
155
+ compound_slot_shape_hashes,
156
+ is_unitary_matching_hashes,
157
+ cube_map_function,
158
+ swapped_length_width_hash
159
+ }
@@ -56,12 +56,10 @@ function skip_probe_or_leftover_resolution(filter_data, empty_space_list, pre_se
56
56
  {
57
57
  const session = filter_data.obligate_compound_session
58
58
  const leftover_spaces = spaces_matching_remembered_leftover(empty_space_list, session)
59
- const leftover_block_list = leftover_unitary_blocks(
59
+ const leftover_block_list = leftover_unitary_blocks.from_session(
60
60
  pre_selected_block_list,
61
- pre_selected_block_list.filter(
62
- block => typeof block.get_slot_list === 'function' && block.get_slot_list().length > 1
63
- ),
64
- session?.leftover_sku_shape_hashes
61
+ compound_blocks(pre_selected_block_list),
62
+ session
65
63
  )
66
64
  if (leftover_spaces.length > 0 && leftover_block_list.length > 0)
67
65
  {
@@ -75,6 +73,24 @@ function skip_probe_or_leftover_resolution(filter_data, empty_space_list, pre_se
75
73
  return skip_probe_resolution(empty_space_list, pre_selected_block_list)
76
74
  }
77
75
 
76
+ /**
77
+ * @param {object[]} block_list
78
+ * @returns {object[]}
79
+ */
80
+ function compound_blocks(block_list)
81
+ {
82
+ return block_list.filter(is_compound_block)
83
+ }
84
+
85
+ /**
86
+ * @param {object} block
87
+ * @returns {boolean}
88
+ */
89
+ function is_compound_block(block)
90
+ {
91
+ return typeof block.get_slot_list === 'function' && block.get_slot_list().length > 1
92
+ }
93
+
78
94
  function space_bbox(space)
79
95
  {
80
96
  if (typeof space.get_x !== 'function')
@@ -0,0 +1,89 @@
1
+ const {
2
+ to_hash_set,
3
+ is_unitary_matching_hashes
4
+ } = require('./leftover_sku_hashes')
5
+
6
+ /**
7
+ * 1-slot blocks whose shape is outside the remembered leftover allow-list.
8
+ * @param {object[]} pre_selected_block_list
9
+ * @param {Set<string>|string[]} [remembered_sku_hashes]
10
+ * @returns {object[]}
11
+ */
12
+ function unitaries_outside_remembered_hashes(pre_selected_block_list, remembered_sku_hashes)
13
+ {
14
+ const remembered = to_hash_set(remembered_sku_hashes)
15
+ return pre_selected_block_list.filter(block => is_hidden_unitary(block, remembered))
16
+ }
17
+
18
+ /**
19
+ * Remembered matches plus every other 1-slot block, in pre-selected order.
20
+ * @param {object[]} pre_selected_block_list
21
+ * @param {object[]} remembered_matches
22
+ * @param {Set<string>|string[]|undefined} remembered_sku_hashes
23
+ * @returns {object[]}
24
+ */
25
+ function unite_with_hidden_unitaries(pre_selected_block_list, remembered_matches, remembered_sku_hashes)
26
+ {
27
+ const hidden = new Set(
28
+ unitaries_outside_remembered_hashes(pre_selected_block_list, remembered_sku_hashes)
29
+ )
30
+ const remembered = new Set(remembered_matches)
31
+ return pre_selected_block_list.filter(block => remembered.has(block) || hidden.has(block))
32
+ }
33
+
34
+ /**
35
+ * True when every block is a remembered 1-slot and the one-shot release has not run.
36
+ * @param {object[]} block_list
37
+ * @param {{ leftover_sku_shape_hashes?: string[], admit_non_remembered_unitaries?: boolean }|undefined} session
38
+ * @returns {boolean}
39
+ */
40
+ function blocks_are_remembered_unitaries_only(block_list, session)
41
+ {
42
+ if (!session || session.admit_non_remembered_unitaries === true || block_list.length === 0)
43
+ {
44
+ return false
45
+ }
46
+ const remembered = to_hash_set(session.leftover_sku_shape_hashes)
47
+ if (remembered.size === 0)
48
+ {
49
+ return false
50
+ }
51
+ return block_list.every(block => is_unitary_matching_hashes(block, remembered))
52
+ }
53
+
54
+ /**
55
+ * @param {object} block
56
+ * @param {Set<string>} remembered
57
+ * @returns {boolean}
58
+ */
59
+ function is_hidden_unitary(block, remembered)
60
+ {
61
+ if (!is_single_slot_block(block))
62
+ {
63
+ return false
64
+ }
65
+ if (remembered.size === 0)
66
+ {
67
+ return true
68
+ }
69
+ return !is_unitary_matching_hashes(block, remembered)
70
+ }
71
+
72
+ /**
73
+ * @param {object} block
74
+ * @returns {boolean}
75
+ */
76
+ function is_single_slot_block(block)
77
+ {
78
+ if (typeof block.get_slot_list !== 'function')
79
+ {
80
+ return false
81
+ }
82
+ return block.get_slot_list().length === 1
83
+ }
84
+
85
+ module.exports = {
86
+ unitaries_outside_remembered_hashes,
87
+ unite_with_hidden_unitaries,
88
+ blocks_are_remembered_unitaries_only
89
+ }
@@ -1,114 +1,90 @@
1
- const { cube_map_function } = require('../Blocks_Preparation/Cube_Map_Function')
2
- const round = require('../tools/Rounder')
1
+ const {
2
+ remember_leftover_sku_hashes,
3
+ leftover_sku_shape_hashes,
4
+ to_hash_set,
5
+ compound_slot_shape_hashes,
6
+ is_unitary_matching_hashes,
7
+ cube_map_function,
8
+ swapped_length_width_hash
9
+ } = require('./leftover_sku_hashes')
10
+ const {
11
+ unite_with_hidden_unitaries,
12
+ unitaries_outside_remembered_hashes,
13
+ blocks_are_remembered_unitaries_only
14
+ } = require('./leftover_unitary_admission')
3
15
 
4
16
  /**
5
17
  * 1-slot blocks of leftover SKUs: not used by remaining compounds, or remembered after compounds are gone.
18
+ * When `admit_other_unitaries` is true, other 1-slot blocks are included without changing stored hashes.
6
19
  * @param {object[]} pre_selected_block_list
7
20
  * @param {object[]} compound_block_list
8
21
  * @param {Set<string>|string[]} [remembered_sku_hashes]
22
+ * @param {boolean} [admit_other_unitaries]
9
23
  * @returns {object[]}
10
24
  */
11
- function leftover_unitary_blocks(pre_selected_block_list, compound_block_list, remembered_sku_hashes)
25
+ function leftover_unitary_blocks(
26
+ pre_selected_block_list,
27
+ compound_block_list,
28
+ remembered_sku_hashes,
29
+ admit_other_unitaries
30
+ )
12
31
  {
13
- const remembered = to_hash_set(remembered_sku_hashes)
14
- if (remembered.size > 0)
32
+ const remembered_matches = remembered_or_current_unitaries(
33
+ pre_selected_block_list,
34
+ compound_block_list,
35
+ remembered_sku_hashes
36
+ )
37
+ if (admit_other_unitaries !== true)
15
38
  {
16
- return pre_selected_block_list.filter(block => is_unitary_matching_hashes(block, remembered))
39
+ return remembered_matches
17
40
  }
18
- return pre_selected_block_list.filter(
19
- block => is_leftover_unitary_block(block, compound_slot_shape_hashes(compound_block_list))
41
+ return unite_with_hidden_unitaries(
42
+ pre_selected_block_list,
43
+ remembered_matches,
44
+ remembered_sku_hashes
20
45
  )
21
46
  }
22
47
 
23
48
  /**
24
- * Stores leftover SKU shape hashes while compounds still remain.
25
- * @param {{ leftover_sku_shape_hashes?: string[] }|undefined} session
26
- * @param {object[]} leftover_block_list
49
+ * Applies the session allow-list, including hidden unitaries after the one-shot release.
50
+ * @param {object[]} pre_selected_block_list
27
51
  * @param {object[]} compound_block_list
52
+ * @param {{ leftover_sku_shape_hashes?: string[], admit_non_remembered_unitaries?: boolean }|undefined} session
53
+ * @returns {object[]}
28
54
  */
29
- function remember_leftover_sku_hashes(session, leftover_block_list, compound_block_list)
55
+ function leftover_unitary_blocks_from_session(pre_selected_block_list, compound_block_list, session)
30
56
  {
31
- if (!session || compound_block_list.length === 0 || leftover_block_list.length === 0)
32
- {
33
- return
34
- }
35
- if (session.leftover_sku_shape_hashes?.length > 0)
36
- {
37
- return
38
- }
39
- session.leftover_sku_shape_hashes = [...leftover_sku_shape_hashes(leftover_block_list)]
57
+ return leftover_unitary_blocks(
58
+ pre_selected_block_list,
59
+ compound_block_list,
60
+ session?.leftover_sku_shape_hashes,
61
+ session?.admit_non_remembered_unitaries === true
62
+ )
40
63
  }
41
64
 
42
65
  /**
43
- * Width/height/length hashes for leftover 1-slot blocks, including swapped floor axes.
44
- * @param {object[]} leftover_block_list
45
- * @returns {Set<string>}
66
+ * @param {object[]} pre_selected_block_list
67
+ * @param {object[]} compound_block_list
68
+ * @param {Set<string>|string[]|undefined} remembered_sku_hashes
69
+ * @returns {object[]}
46
70
  */
47
- function leftover_sku_shape_hashes(leftover_block_list)
48
- {
49
- const hashes = new Set()
50
- for (const block of leftover_block_list)
51
- {
52
- add_slot_orientation_hashes(hashes, block)
53
- }
54
- return hashes
55
- }
56
-
57
- function add_slot_orientation_hashes(hashes, block)
58
- {
59
- if (typeof block.get_slot_list !== 'function')
60
- {
61
- return
62
- }
63
- const slot_list = block.get_slot_list()
64
- if (slot_list.length !== 1 || typeof slot_list[0].get_width !== 'function')
65
- {
66
- return
67
- }
68
- hashes.add(cube_map_function(slot_list[0]))
69
- hashes.add(swapped_length_width_hash(slot_list[0]))
70
- }
71
-
72
- function swapped_length_width_hash(slot)
73
- {
74
- return round(slot.get_length()) + ';' + round(slot.get_height()) + ';' + round(slot.get_width())
75
- }
76
-
77
- function to_hash_set(remembered_sku_hashes)
71
+ function remembered_or_current_unitaries(pre_selected_block_list, compound_block_list, remembered_sku_hashes)
78
72
  {
79
- if (!remembered_sku_hashes)
80
- {
81
- return new Set()
82
- }
83
- if (remembered_sku_hashes instanceof Set)
84
- {
85
- return remembered_sku_hashes
86
- }
87
- return new Set(remembered_sku_hashes)
88
- }
89
-
90
- function compound_slot_shape_hashes(compound_block_list)
91
- {
92
- const hashes = new Set()
93
- for (const block of compound_block_list)
73
+ const remembered = to_hash_set(remembered_sku_hashes)
74
+ if (remembered.size > 0)
94
75
  {
95
- if (typeof block.get_slot_list !== 'function')
96
- {
97
- continue
98
- }
99
- for (const slot of block.get_slot_list())
100
- {
101
- if (typeof slot.get_width !== 'function')
102
- {
103
- continue
104
- }
105
- hashes.add(cube_map_function(slot))
106
- hashes.add(swapped_length_width_hash(slot))
107
- }
76
+ return pre_selected_block_list.filter(block => is_unitary_matching_hashes(block, remembered))
108
77
  }
109
- return hashes
78
+ return pre_selected_block_list.filter(
79
+ block => is_leftover_unitary_block(block, compound_slot_shape_hashes(compound_block_list))
80
+ )
110
81
  }
111
82
 
83
+ /**
84
+ * @param {object} block
85
+ * @param {Set<string>} compound_slot_hashes
86
+ * @returns {boolean}
87
+ */
112
88
  function is_leftover_unitary_block(block, compound_slot_hashes)
113
89
  {
114
90
  if (typeof block.get_slot_list !== 'function')
@@ -128,26 +104,25 @@ function is_leftover_unitary_block(block, compound_slot_hashes)
128
104
  {
129
105
  return true
130
106
  }
131
- return !compound_slot_hashes.has(cube_map_function(slot_list[0]))
132
- && !compound_slot_hashes.has(swapped_length_width_hash(slot_list[0]))
107
+ return slot_shape_is_absent(slot_list[0], compound_slot_hashes)
133
108
  }
134
109
 
135
- function is_unitary_matching_hashes(block, remembered)
110
+ /**
111
+ * @param {object} slot
112
+ * @param {Set<string>} compound_slot_hashes
113
+ * @returns {boolean}
114
+ */
115
+ function slot_shape_is_absent(slot, compound_slot_hashes)
136
116
  {
137
- if (typeof block.get_slot_list !== 'function')
138
- {
139
- return false
140
- }
141
- const slot_list = block.get_slot_list()
142
- if (slot_list.length !== 1 || typeof slot_list[0].get_width !== 'function')
143
- {
144
- return false
145
- }
146
- return remembered.has(cube_map_function(slot_list[0]))
147
- || remembered.has(swapped_length_width_hash(slot_list[0]))
117
+ const matches_cube = compound_slot_hashes.has(cube_map_function(slot))
118
+ const matches_swap = compound_slot_hashes.has(swapped_length_width_hash(slot))
119
+ return !matches_cube && !matches_swap
148
120
  }
149
121
 
150
122
  leftover_unitary_blocks.remember_leftover_sku_hashes = remember_leftover_sku_hashes
151
123
  leftover_unitary_blocks.leftover_sku_shape_hashes = leftover_sku_shape_hashes
124
+ leftover_unitary_blocks.from_session = leftover_unitary_blocks_from_session
125
+ leftover_unitary_blocks.unitaries_outside_remembered_hashes = unitaries_outside_remembered_hashes
126
+ leftover_unitary_blocks.blocks_are_remembered_unitaries_only = blocks_are_remembered_unitaries_only
152
127
 
153
128
  module.exports = leftover_unitary_blocks
@@ -119,10 +119,10 @@ function resolve_compound_first_or_leftover(
119
119
  empty_space_list,
120
120
  pre_selected_block_list,
121
121
  leftover_empty_spaces,
122
- leftover_unitary_blocks(
122
+ leftover_unitary_blocks.from_session(
123
123
  pre_selected_block_list,
124
124
  compound_block_list,
125
- filter_data.obligate_compound_session?.leftover_sku_shape_hashes
125
+ filter_data.obligate_compound_session
126
126
  )
127
127
  )
128
128
  }