@zoodogood/utils 4.0.0-change.2617 → 4.2.1-change.3358

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.
@@ -6,10 +6,12 @@
6
6
  * 2) Хотя у нас есть список занятых номеров, у нас не может быть списка свободных (за условием задачи)
7
7
  * Этот алгоритм используется для эффективного поиска тех самых свободных номеров, которые удовлетворяют заданному условию
8
8
  */
9
+ export declare function size_of_area(area: readonly [number, number]): number;
9
10
  export declare class BusyNumeric {
10
11
  #private;
11
12
  readonly range: number;
12
13
  readonly busy_areas: (readonly [number, number])[];
14
+ free_area: number;
13
15
  get peak_start_busy(): boolean;
14
16
  get peak_end_busy(): boolean;
15
17
  constructor(range: number);
@@ -26,6 +26,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
26
26
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
27
27
  };
28
28
  var _BusyNumeric_peak_start_busy, _BusyNumeric_peak_end_busy;
29
+ import assert from "node:assert";
29
30
  import { binary_search } from "../primitives/binary_search.js";
30
31
  /**
31
32
  * MARK: Представьте отель
@@ -39,6 +40,9 @@ import { binary_search } from "../primitives/binary_search.js";
39
40
  // Если основное количество производительности не реализуется из-за особенностей структуры списка, то это можно оптимизировать
40
41
  // Интересно что ветки дерева можно определять по индексу. Да, это интересное замечание.
41
42
  // В BusyNumeric можно добавить ещё метод separate
43
+ export function size_of_area(area) {
44
+ return area[1] - area[0] + 1;
45
+ }
42
46
  export class BusyNumeric {
43
47
  get peak_start_busy() {
44
48
  var _a;
@@ -77,10 +81,9 @@ export class BusyNumeric {
77
81
  this.refresh._peak();
78
82
  },
79
83
  };
80
- if (range <= 0) {
81
- throw new Error("Assertion: range must be positive");
82
- }
84
+ assert(range > 0, "Range must be positive");
83
85
  this.range = range;
86
+ this.free_area = this.range + /* includes position 0 */ 1;
84
87
  }
85
88
  bifurcate(point) {
86
89
  this.insert_area(point, point);
@@ -118,34 +121,32 @@ export class BusyNumeric {
118
121
  return { size, left, right };
119
122
  }
120
123
  insert_area(start, end) {
121
- if (!Number.isInteger(start) || !Number.isInteger(end)) {
122
- throw new Error(`Assertion error: start or end not integer ${start} ${end}, maybe float?`);
123
- }
124
+ assert(Number.isInteger(start) && Number.isInteger(end), `Assertion error: start or end not integer ${start} ${end}, maybe float?`);
124
125
  if (start > end) {
125
126
  [start, end] = [end, start];
126
127
  }
127
- if (start < 0) {
128
- throw new Error("Assertion error: start < 0");
129
- }
130
- if (end > this.range) {
131
- throw new Error("Assertion error: end > this.range");
132
- }
133
- const place_index = binary_search(this.busy_areas.length - 1, (index) => {
134
- var _a, _b, _c;
135
- const value = (_a = this.busy_areas[index]) === null || _a === void 0 ? void 0 : _a[1];
136
- const biggest = end < value;
137
- if (biggest) {
138
- return 1;
139
- }
140
- return (+(((_c = (_b = this.busy_areas[index + 1]) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER) > end) - 1);
141
- }) + 1;
128
+ assert(start >= 0);
129
+ assert(end <= this.range);
130
+ const place_index = this.busy_areas.length
131
+ ? binary_search(this.busy_areas.length - 1, (index) => {
132
+ var _a, _b, _c;
133
+ const value = (_a = this.busy_areas[index]) === null || _a === void 0 ? void 0 : _a[1];
134
+ const biggest = end < value;
135
+ if (biggest) {
136
+ return 1 /* BinarySearchCompareSpec.Biggest */;
137
+ }
138
+ return (+(((_c = (_b = this.busy_areas[index + 1]) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER) > end) - 1);
139
+ }) + 1
140
+ : 0;
142
141
  const left = this.busy_areas[place_index - 1];
143
142
  const right = this.busy_areas[place_index];
144
143
  const is_left_included = !!left && left[1] + 1 >= start;
145
144
  const is_right_included = !!right && right[0] - 1 <= end;
146
145
  // Merge strategy 3
147
146
  if (is_left_included && is_right_included) {
148
- this.busy_areas.splice(place_index - 1, 2, [left[0], right[1]]);
147
+ const points = [left[0], right[1]];
148
+ this.free_area -= size_of_area(points) - size_of_area(left) - size_of_area(right);
149
+ this.busy_areas.splice(place_index - 1, 2, points);
149
150
  return;
150
151
  }
151
152
  // Merge strategy 2
@@ -154,13 +155,13 @@ export class BusyNumeric {
154
155
  const [index, points] = is_left_included
155
156
  ? [place_index - 1, [target[0], end]]
156
157
  : [place_index, [start, target[1]]];
157
- if (target[0] <= start && target[1] >= end) {
158
- throw new Error("Assertion error: [start, end] in range");
159
- }
158
+ assert(!(target[0] <= start && target[1] >= end), "Assertion error: [start, end] in range");
159
+ this.free_area -= size_of_area(points) - size_of_area(target);
160
160
  this.busy_areas.splice(index, 1, points);
161
161
  return;
162
162
  }
163
163
  // Merge strategy 1
164
+ this.free_area -= size_of_area([start, end]);
164
165
  this.busy_areas.splice(place_index, 0, [start, end]);
165
166
  }
166
167
  }
@@ -0,0 +1,53 @@
1
+ type Predicate<T> = (T: T, index: number, array: T[]) => boolean;
2
+ export declare const enum ArrayEmulateStrategy {
3
+ Partial = 0,
4
+ Proxied = 1
5
+ }
6
+ interface Configuration {
7
+ chunks_count?: number;
8
+ revert?: boolean;
9
+ emulate?: ArrayEmulateStrategy;
10
+ }
11
+ type Chunk<T> = LazySort<T>;
12
+ type WithValue<T> = [T, number];
13
+ export declare class LazySort<T> {
14
+ #private;
15
+ emulate: ArrayEmulateStrategy;
16
+ revert: boolean;
17
+ chunks_count: number;
18
+ iterable: WithValue<T>[];
19
+ length: number;
20
+ calculated: boolean;
21
+ is_atomic?: boolean;
22
+ max?: number;
23
+ min?: number;
24
+ chunk_range?: number;
25
+ chunks?: Chunk<T>[];
26
+ chunk_thresholds?: number[];
27
+ static ofNumbers(numbers: number[]): LazySort<number>;
28
+ static ofArrayMapValue<T>(array: T[], valueOf: (T: T, index: number, arr: T[]) => T): LazySort<T>;
29
+ constructor(iterable1: WithValue<T>[], { revert: revert1, chunks_count: chunks_count1, emulate: emulate1 }?: Configuration);
30
+ get atomic_chunk_arr(): WithValue<T>[];
31
+ chunks_update_thresholds_after(chunk_index: number, diff: number): number[];
32
+ entry(): LazySortEntry<T>;
33
+ }
34
+ export declare class LazySortEntry<T> extends Array {
35
+ #private;
36
+ constructor(source: LazySort<T>);
37
+ entry(): this;
38
+ get length(): number;
39
+ set length(value: number);
40
+ [Symbol.iterator](): Generator<WithValue<T>>;
41
+ toArray(): WithValue<T>[];
42
+ at(at: number): WithValue<T> | undefined;
43
+ positive_at(at: number): (WithValue<T> | undefined);
44
+ find(predicate: Predicate<WithValue<T>>): WithValue<T> | undefined;
45
+ findIndex(predicate: Predicate<WithValue<T>>): number;
46
+ findLast(predicate: Predicate<WithValue<T>>): WithValue<T> | undefined;
47
+ findIndexLast(predicate: Predicate<WithValue<T>>): number;
48
+ indexOf(item: WithValue<T>): number;
49
+ some(predicate: Predicate<WithValue<T>>): boolean;
50
+ every(predicate: Predicate<WithValue<T>>): boolean;
51
+ splice(start: number, deleteCount: number, ...items: WithValue<T>[]): WithValue<T>[];
52
+ }
53
+ export {};
@@ -0,0 +1,234 @@
1
+ // Декларации:
2
+ // Утверждаю: Атомик всегда отсортирован
3
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
6
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
7
+ };
8
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
9
+ if (kind === "m") throw new TypeError("Private method is not writable");
10
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
11
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
12
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
13
+ };
14
+ var _LazySort_instances, _LazySort_to_proxied_array_emulator, _LazySort_to_partial_array_emulator, _LazySortEntry_source;
15
+ var concatAssign = (lhs, rhs) => { var _a; return (((_a = rhs === null || rhs === void 0 ? void 0 : rhs[Symbol.isConcatSpreadable]) !== null && _a !== void 0 ? _a : Array.isArray(rhs)) ? lhs.push.apply(lhs, rhs) : lhs.push(rhs), lhs); };
16
+ import assert from "node:assert";
17
+ const GOOD_CHUNKS_COUNT = 11;
18
+ export class LazySort {
19
+ static ofNumbers(numbers) {
20
+ return new this(numbers.map($1 => [$1, $1]));
21
+ }
22
+ static ofArrayMapValue(array, valueOf) {
23
+ return new this(array.map(($, i, arr) => [$, valueOf($, i, arr)]));
24
+ }
25
+ constructor(iterable1, { revert: revert1 = false, chunks_count: chunks_count1 = GOOD_CHUNKS_COUNT, emulate: emulate1 = 0 /* ArrayEmulateStrategy.Partial */ } = {}) {
26
+ _LazySort_instances.add(this);
27
+ this.calculated = false;
28
+ this.iterable = iterable1;
29
+ this.revert = revert1;
30
+ this.chunks_count = chunks_count1;
31
+ this.emulate = emulate1;
32
+ assert(this.chunks_count >= 2);
33
+ this.length = this.iterable.length;
34
+ }
35
+ get atomic_chunk_arr() {
36
+ return this.chunks[0].iterable;
37
+ }
38
+ chunks_update_thresholds_after(chunk_index, diff) {
39
+ const results = [];
40
+ for (let end1 = this.chunk_thresholds.length, i1 = chunk_index; i1 < end1; ++i1) {
41
+ const index = i1;
42
+ results.push(this.chunk_thresholds[index] += diff);
43
+ }
44
+ ;
45
+ return results;
46
+ }
47
+ entry() {
48
+ var _a, _b;
49
+ if (!this.calculated) {
50
+ const max1 = Math.max(...this.iterable.map($2 => $2[1]));
51
+ this.max = max1;
52
+ const min1 = Math.min(...this.iterable.map($3 => $3[1]));
53
+ this.min = min1;
54
+ const chunk_range1 = Math.ceil((this.max - this.min) / (this.chunks_count - 1));
55
+ this.chunk_range = chunk_range1;
56
+ this.is_atomic = ((this.chunks_count >= this.length) || (this.max - this.min === 0));
57
+ const chunks1 = (() => {
58
+ if (!this.is_atomic) {
59
+ const chunks = [...new Array(this.chunks_count)].map(() => []);
60
+ this.iterable.forEach((x) => {
61
+ return chunks[Math.floor((x[1] - this.min) / this.chunk_range)].push(x);
62
+ });
63
+ return chunks.map($4 => new LazySort($4, { revert: this.revert, chunks_count: this.chunks_count, emulate: this.emulate }));
64
+ }
65
+ else {
66
+ return [new LazySort(this.iterable.toSorted((a, b) => (-1) ** +this.revert * (a[1] - b[1])), { revert: this.revert, chunks_count: this.chunks_count, emulate: this.emulate })];
67
+ }
68
+ })();
69
+ this.chunks = chunks1;
70
+ this.revert && ((_a = this.chunks) === null || _a === void 0 ? void 0 : _a.reverse());
71
+ const chunk_thresholds1 = (_b = this.chunks) === null || _b === void 0 ? void 0 : _b.reduce((acc, next) => acc.concat([(acc[acc.length - 1] || 0) + next.length]), []);
72
+ this.chunk_thresholds = chunk_thresholds1;
73
+ }
74
+ this.calculated = true;
75
+ switch (this.emulate) {
76
+ case 0 /* ArrayEmulateStrategy.Partial */: {
77
+ return __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_partial_array_emulator).call(this);
78
+ }
79
+ case 1 /* ArrayEmulateStrategy.Proxied */: {
80
+ return __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_proxied_array_emulator).call(this);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ _LazySort_instances = new WeakSet(), _LazySort_to_proxied_array_emulator = function _LazySort_to_proxied_array_emulator() {
86
+ const instance = __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_partial_array_emulator).call(this);
87
+ return instance;
88
+ }, _LazySort_to_partial_array_emulator = function _LazySort_to_partial_array_emulator() {
89
+ return new LazySortEntry(this);
90
+ };
91
+ export class LazySortEntry extends Array {
92
+ constructor(source) {
93
+ super();
94
+ _LazySortEntry_source.set(this, void 0);
95
+ __classPrivateFieldSet(this, _LazySortEntry_source, source, "f");
96
+ }
97
+ entry() {
98
+ return this;
99
+ }
100
+ get length() {
101
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").length;
102
+ }
103
+ set length(value) {
104
+ let ref;
105
+ ((ref = this.toArray()).length = value, ref);
106
+ }
107
+ *[(_LazySortEntry_source = new WeakMap(), Symbol.iterator)]() {
108
+ for (let end2 = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length, i2 = 0; i2 < end2; ++i2) {
109
+ const index = i2;
110
+ yield this.positive_at(index);
111
+ }
112
+ }
113
+ toArray() {
114
+ if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
115
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr;
116
+ }
117
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks.map($5 => $5.entry().toArray()).flat();
118
+ }
119
+ at(at) {
120
+ return at < 0 ? this.positive_at(__classPrivateFieldGet(this, _LazySortEntry_source, "f").length - at) : this.positive_at(at);
121
+ }
122
+ positive_at(at) {
123
+ if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
124
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr[at];
125
+ }
126
+ const chunk_index = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds.findIndex((a1 => a1 > at));
127
+ if (chunk_index === -1) {
128
+ return undefined;
129
+ }
130
+ const chunk = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks[chunk_index];
131
+ return chunk.entry().positive_at(at - (__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0));
132
+ }
133
+ find(predicate) {
134
+ return this.positive_at(this.findIndex(predicate));
135
+ }
136
+ findIndex(predicate) {
137
+ for (let end3 = this.length, i3 = 0; i3 < end3; ++i3) {
138
+ const index = i3;
139
+ if (predicate(this.positive_at(index), index, this)) {
140
+ return index;
141
+ }
142
+ }
143
+ return -1;
144
+ }
145
+ findLast(predicate) {
146
+ return this.positive_at(this.findIndexLast(predicate));
147
+ }
148
+ findIndexLast(predicate) {
149
+ for (let i4 = this.length + -1; i4 >= 0; --i4) {
150
+ const index = i4;
151
+ if (predicate(this.positive_at(index), index, this)) {
152
+ return index;
153
+ }
154
+ }
155
+ return -1;
156
+ }
157
+ indexOf(item) {
158
+ if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
159
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr.indexOf(item);
160
+ }
161
+ let results1;
162
+ results1 = [];
163
+ let ref1;
164
+ for (const chunk_index in ref1 = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks) {
165
+ const chunk = ref1[chunk_index];
166
+ let ref2;
167
+ if ((ref2 = chunk.entry().indexOf(item))) {
168
+ const index = ref2;
169
+ results1 = [index, +chunk_index];
170
+ break;
171
+ }
172
+ else {
173
+ results1.push(void 0);
174
+ }
175
+ }
176
+ ;
177
+ const [index, chunk_index] = results1;
178
+ if (chunk_index === undefined) {
179
+ return -1;
180
+ }
181
+ return (__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0) + index;
182
+ }
183
+ some(predicate) {
184
+ return (this.findIndex(predicate)) !== -1;
185
+ }
186
+ // @ts-expect-error
187
+ every(predicate) {
188
+ return !this.some(predicate);
189
+ }
190
+ splice(start, deleteCount, ...items) {
191
+ start < 0 && (start = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length + start);
192
+ (start + deleteCount > __classPrivateFieldGet(this, _LazySortEntry_source, "f").length) && (deleteCount = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length - start);
193
+ (deleteCount - items.length !== 0) && (__classPrivateFieldGet(this, _LazySortEntry_source, "f").length -= (deleteCount - items.length));
194
+ if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
195
+ return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr.splice(start, deleteCount, ...items);
196
+ }
197
+ const end = start + deleteCount;
198
+ const removed = [];
199
+ const ret = removed;
200
+ __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks
201
+ .map((chunk, chunk_index) => {
202
+ return ({
203
+ chunk_start: __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0,
204
+ chunk_end: __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index],
205
+ chunk,
206
+ chunk_index
207
+ });
208
+ })
209
+ .filter(({ chunk_start, chunk_end, chunk }) => {
210
+ if (!chunk.length) {
211
+ return false;
212
+ }
213
+ return start < chunk_end && chunk_start <= end;
214
+ })
215
+ .forEach(({ chunk_start, chunk_end, chunk_index, chunk }, changed_index, changes_array) => {
216
+ const replace_start = changed_index === 0
217
+ ? start - chunk_start
218
+ : 0;
219
+ const replace_end = changed_index === changes_array.length - 1
220
+ ? end - chunk_start
221
+ : chunk.length;
222
+ const _removed_count = replace_end - replace_start;
223
+ const _added_items = items.slice(replace_start + chunk_start - start, changed_index === changes_array.length - 1 ? undefined : replace_end + chunk_start - start);
224
+ __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks_update_thresholds_after(chunk_index, _added_items.length - _removed_count);
225
+ return concatAssign(removed, chunk.entry().splice(replace_start, _removed_count, ..._added_items));
226
+ });
227
+ return ret;
228
+ }
229
+ }
230
+ // slice()
231
+ // push()
232
+ // pop()
233
+ // unshift()
234
+ // shift()
@@ -0,0 +1 @@
1
+ export {};
@@ -5,7 +5,9 @@ interface IParams<T> {
5
5
  filter?: (item: T) => boolean;
6
6
  }
7
7
  interface IPickContext<T> {
8
- busy_preventable: ReturnType<typeof create_default_preventable>;
8
+ busy_preventable: ReturnType<typeof create_default_preventable> & {
9
+ require_insert(): void;
10
+ };
9
11
  item: T;
10
12
  pick: (context: IPickContext<T>) => boolean;
11
13
  threshold: number;
@@ -22,6 +24,8 @@ export declare class RandomizerContext<T> {
22
24
  }): RandomizerContext<T>;
23
25
  pickRandom(pick?: IPickContext<T>["pick"]): T | undefined;
24
26
  }
27
+ export declare function pickInThresholds(thresholds: number[], value: number): number;
28
+ export declare function thresholdsOf(weights: NonNullable<IParams<unknown>["associatedWeights"]>): number[];
25
29
  export declare function getRandomElementIndexInWeights(weights: NonNullable<IParams<unknown>["associatedWeights"]>): number | never;
26
- export declare function getRandomElementFromArray<T>(array: T[], { associatedWeights, filter }?: IParams<T>): void;
30
+ export declare function getRandomElementFromArray<T>(array: T[], { associatedWeights, filter }?: IParams<T>): T | undefined;
27
31
  export {};
@@ -1,57 +1,74 @@
1
+ import assert from "node:assert";
1
2
  import { binary_search } from "../primitives/binary_search.js";
2
3
  import { create_default_preventable } from "../primitives/createDefaultPreventable.js";
3
- import { BusyNumeric } from "./BusyNumeric.js";
4
+ import { BusyNumeric, size_of_area } from "./BusyNumeric.js";
4
5
  import { getRandomNumberInRange } from "./getRandomNumberInRange.js";
5
6
  export class RandomizerContext {
6
7
  constructor(array, thresholds) {
7
8
  var _a;
8
9
  this.array = array;
9
10
  this.thresholds = thresholds;
10
- const range = (_a = thresholds === null || thresholds === void 0 ? void 0 : thresholds.at(-1)) !== null && _a !== void 0 ? _a : array.length;
11
+ const range = (_a = thresholds === null || thresholds === void 0 ? void 0 : thresholds.at(-1)) !== null && _a !== void 0 ? _a : array.length - 1;
11
12
  this.hotel = new BusyNumeric(range);
12
13
  }
13
14
  static from({ array, associatedWeights, }) {
14
- const thresholds = associatedWeights &&
15
- _getRandomElementIndexInWeight_thresholds(associatedWeights);
15
+ const thresholds = associatedWeights && thresholdsOf(associatedWeights);
16
16
  return new RandomizerContext(array, thresholds);
17
17
  }
18
18
  pickRandom(pick = () => true) {
19
- var _a;
20
19
  const { hotel, thresholds, array } = this;
21
20
  while (true) {
22
21
  const segments_count = hotel.segments_count();
23
22
  if (!segments_count) {
24
23
  break;
25
24
  }
26
- const { left, size } = hotel.segment(getRandomNumberInRange({ max: segments_count - 1 }));
27
- const point = ((_a = left === null || left === void 0 ? void 0 : left[1]) !== null && _a !== void 0 ? _a : -1) + getRandomNumberInRange({ min: 1, max: size });
28
- const index = thresholds
29
- ? _getRandomElementIndexInWeight_of_thresholds(thresholds, point)
30
- : point;
25
+ const target_of_free = getRandomNumberInRange({ max: hotel.free_area - 1 });
26
+ const position = (() => {
27
+ var _a, _b, _c, _d;
28
+ let segment = 0;
29
+ let distance = target_of_free;
30
+ let position = 0;
31
+ while (true) {
32
+ const free_area = ((_b = (_a = hotel.busy_areas[segment]) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : hotel.range + 1) - ((_d = (_c = hotel.busy_areas[segment - 1]) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : -1) - 1;
33
+ distance -= free_area;
34
+ position += free_area;
35
+ if (distance < 0) {
36
+ return position + distance;
37
+ }
38
+ position += size_of_area(hotel.busy_areas[segment] || [0, hotel.range + 1]);
39
+ segment++;
40
+ }
41
+ })();
42
+ let _require_insert = false;
43
+ const index = thresholds ? pickInThresholds(thresholds, position) : position;
31
44
  const element = array[index];
32
45
  const pickContext = {
33
- busy_preventable: create_default_preventable(),
46
+ busy_preventable: {
47
+ ...create_default_preventable(),
48
+ require_insert() {
49
+ _require_insert = true;
50
+ }
51
+ },
34
52
  item: element,
35
53
  pick,
36
54
  threshold: index,
37
- point,
55
+ point: position,
38
56
  };
39
- if (pick(pickContext)) {
40
- return element;
41
- }
42
- if (!pickContext.busy_preventable.default_prevented()) {
57
+ const picked = pick(pickContext);
58
+ if (_require_insert || !picked && !pickContext.busy_preventable.default_prevented()) {
43
59
  thresholds
44
60
  ? hotel.insert_area(thresholds[index - 1] + 1 || 0, thresholds[index])
45
61
  : hotel.bifurcate(index);
46
62
  }
63
+ if (picked) {
64
+ return element;
65
+ }
47
66
  }
48
67
  return undefined;
49
68
  }
50
69
  }
51
- function _getRandomElementIndexInWeight_of_thresholds(thresholds, value) {
52
- if (!thresholds.length) {
53
- return -1;
54
- }
70
+ export function pickInThresholds(thresholds, value) {
71
+ assert(thresholds.length > 0);
55
72
  return binary_search(thresholds.length - 1, (index) => {
56
73
  var _a;
57
74
  const hold = thresholds[index];
@@ -64,17 +81,15 @@ function _getRandomElementIndexInWeight_of_thresholds(thresholds, value) {
64
81
  return 1;
65
82
  });
66
83
  }
67
- function _getRandomElementIndexInWeight_thresholds(weights) {
68
- if (weights.length < 1) {
69
- new Error("Invalid array length");
70
- }
84
+ export function thresholdsOf(weights) {
85
+ assert(weights.length > 0, "Invalid array length");
71
86
  let previousLimit = 0;
72
87
  return weights.map((weight) => (previousLimit += weight));
73
88
  }
74
89
  export function getRandomElementIndexInWeights(weights) {
75
- const thresholds = _getRandomElementIndexInWeight_thresholds(weights);
76
- const lotterySecretNumber = Math.random() * thresholds.at(-1);
77
- return _getRandomElementIndexInWeight_of_thresholds(thresholds, lotterySecretNumber);
90
+ const thresholds = thresholdsOf(weights);
91
+ const lotteryPick = Math.random() * thresholds.at(-1);
92
+ return pickInThresholds(thresholds, lotteryPick);
78
93
  }
79
94
  // task: честный алгоритм , для которого каждый из элеметов списка имеет равный шанс на реализацию своей вероятности.
80
95
  // Обычно весь список фильтруется и после выбирается элемент. В нашем случае фильтр будет срабатывать только для тех элементов,
@@ -93,10 +108,8 @@ export function getRandomElementIndexInWeights(weights) {
93
108
  Повторяем
94
109
  */
95
110
  export function getRandomElementFromArray(array, { associatedWeights, filter = () => true } = {}) {
96
- if (associatedWeights && associatedWeights.length !== array.length) {
97
- throw new Error("Incorrectly passed argument associatedWeights: The length of the associatedWeights must exactly match the length of the weights array");
98
- }
99
- RandomizerContext.from({
111
+ assert(!associatedWeights || associatedWeights.length === array.length, "Incorrectly passed argument associatedWeights: The length of the associatedWeights must exactly match the length of the weights array");
112
+ return RandomizerContext.from({
100
113
  array,
101
114
  associatedWeights,
102
115
  }).pickRandom(({ item }) => filter(item));
@@ -1,10 +1,12 @@
1
+ export * from "./BusyNumeric.js";
1
2
  export * from "./CustomCollector.js";
2
- export * from "./GlitchText.js";
3
- export * from "./getRandomNumberInRange.js";
4
- export * from "./rangeToArray.js";
5
- export * from "./getRandomElementFromArray.js";
6
3
  export * from "./DotNotatedInterface.js";
7
4
  export * from "./ExtendedEnum/mod.js";
5
+ export * from "./getRandomElementFromArray.js";
6
+ export * from "./getRandomNumberInRange.js";
7
+ export * from "./GlitchText.js";
8
+ export * from "./LazySort/LazySort.build.js";
9
+ export * from "./rangeToArray.js";
8
10
  declare function omit(object: object, filter: CallableFunction): {
9
11
  [k: string]: any;
10
12
  };
@@ -1,10 +1,12 @@
1
+ export * from "./BusyNumeric.js";
1
2
  export * from "./CustomCollector.js";
2
- export * from "./GlitchText.js";
3
- export * from "./getRandomNumberInRange.js";
4
- export * from "./rangeToArray.js";
5
- export * from "./getRandomElementFromArray.js";
6
3
  export * from "./DotNotatedInterface.js";
7
4
  export * from "./ExtendedEnum/mod.js";
5
+ export * from "./getRandomElementFromArray.js";
6
+ export * from "./getRandomNumberInRange.js";
7
+ export * from "./GlitchText.js";
8
+ export * from "./LazySort/LazySort.build.js";
9
+ export * from "./rangeToArray.js";
8
10
  function omit(object, filter) {
9
11
  const entries = Object.entries(object).filter(([key, value], i) => filter(key, value, i));
10
12
  return Object.fromEntries(entries);
@@ -1 +1,9 @@
1
1
  export declare function binary_search(max: number, compare: (index: number) => number): number;
2
+ export declare const enum BinarySearchResultEnum {
3
+ NotFound = -1
4
+ }
5
+ export declare const enum BinarySearchCompareSpec {
6
+ Biggest = 1,
7
+ Equal = 0,
8
+ Smallest = -1
9
+ }
@@ -1,5 +1,8 @@
1
+ import assert from "node:assert";
1
2
  // Если большее, то идёт к меньшим
2
3
  export function binary_search(max, compare) {
4
+ assert(max >= 0);
5
+ assert(Number.isInteger(max));
3
6
  let min = 0;
4
7
  while (true) {
5
8
  const index = Math.floor((min + max) / 2);
@@ -1,6 +1,9 @@
1
- export * from "./TextTableBuilder.js";
1
+ export * from "./binary_search.js";
2
2
  export * from "./BracketsParser.js";
3
3
  export { CliParser } from "./CliParser.js";
4
+ export * from "./createDefaultPreventable.js";
5
+ export * from "./normalize.js";
6
+ export * from "./TextTableBuilder.js";
4
7
  interface IEndingOptions {
5
8
  unite?: (quantity: number, word: string) => string;
6
9
  }
@@ -1,6 +1,9 @@
1
- export * from "./TextTableBuilder.js";
1
+ export * from "./binary_search.js";
2
2
  export * from "./BracketsParser.js";
3
3
  export { CliParser } from "./CliParser.js";
4
+ export * from "./createDefaultPreventable.js";
5
+ export * from "./normalize.js";
6
+ export * from "./TextTableBuilder.js";
4
7
  function ending(quantity = 0, base, multiple, alone, double, options = {}) {
5
8
  if (isNaN(quantity))
6
9
  return NaN;
@@ -1 +1 @@
1
- export declare function normalize_to_integer(list: number[]): number[];
1
+ export declare function normalize_to_max_coefficient(list: number[]): number[];
@@ -1,5 +1,7 @@
1
- export function normalize_to_integer(list) {
2
- // (1 / 3) * 1e15 === 333 333 333 333 333.3
3
- const MIN_OPTIMAL_VALUE = 1e16;
4
- return list.map((x) => Math.floor(x * MIN_OPTIMAL_VALUE));
1
+ export function normalize_to_max_coefficient(list) {
2
+ // normalize_to_optimal(2, MAX_SAFE_INTEGER) will be coefficient 1:9007199254740990
3
+ // normalize_to_optimal(0.25, 3000) will be coefficient 750537393112:9006448717347879
4
+ const sum = list.reduce((acc, value) => acc + value, 0);
5
+ const multiplayer = Number.MAX_SAFE_INTEGER / sum;
6
+ return list.map((x) => Math.floor(x * multiplayer));
5
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zoodogood/utils",
3
3
  "type": "module",
4
- "version": "4.0.0-change.2617",
4
+ "version": "4.2.1-change.3358",
5
5
  "description": "",
6
6
  "main": "lib/index.js",
7
7
  "homepage": "https://zoodogood.github.io/utils",
@@ -66,7 +66,7 @@
66
66
  }
67
67
  },
68
68
  "scripts": {
69
- "test": "vitest --help",
69
+ "test": "vitest --run",
70
70
  "docs-build": "cd ./docs && retype build --output ./public",
71
71
  "docs-watch": "cd ./docs && retype watch",
72
72
  "build": "tsc",