0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00
server/project/src/helpers/ContainerHelper.ts

150 lines
4.7 KiB
TypeScript
Raw Normal View History

2023-03-03 15:23:46 +00:00
import { injectable } from "tsyringe";
export class FindSlotResult {
constructor(
public success = false,
public x?: number,
public y?: number,
public rotation = false,
) {}
2023-03-03 15:23:46 +00:00
}
@injectable()
export class ContainerHelper {
2023-07-24 15:52:55 +01:00
/**
* Finds a slot for an item in a given 2D container map
* @param container2D Array of container with slots filled/free
* @param itemWidth Width of item
* @param itemHeight Height of item
* @returns Location to place item in container
2023-03-03 15:23:46 +00:00
*/
public findSlotForItem(container2D: number[][], itemWidth: number, itemHeight: number): FindSlotResult {
2023-03-03 15:23:46 +00:00
let rotation = false;
const minVolume = (itemWidth < itemHeight ? itemWidth : itemHeight) - 1;
const containerY = container2D.length;
const containerX = container2D[0].length;
const limitY = containerY - minVolume;
const limitX = containerX - minVolume;
// Every x+y slot taken up in container, exit
if (container2D.every((x) => x.every((y) => y === 1))) {
return new FindSlotResult(false);
}
// Down
for (let y = 0; y < limitY; y++) {
// Across
if (container2D[y].every((x) => x === 1)) {
// Every item in row is full, skip row
continue;
}
for (let x = 0; x < limitX; x++) {
2023-03-03 15:23:46 +00:00
let foundSlot = this.locateSlot(container2D, containerX, containerY, x, y, itemWidth, itemHeight);
// Failed to find slot, rotate item and try again
if (!foundSlot && itemWidth * itemHeight > 1) {
// Bigger than 1x1
foundSlot = this.locateSlot(container2D, containerX, containerY, x, y, itemHeight, itemWidth); // Height/Width swapped
if (foundSlot) {
// Found a slot for it when rotated
2023-03-03 15:23:46 +00:00
rotation = true;
}
}
if (!foundSlot) {
// Didn't fit this hole, try again
2023-03-03 15:23:46 +00:00
continue;
}
return new FindSlotResult(true, x, y, rotation);
}
}
// Tried all possible holes, nothing big enough for the item
return new FindSlotResult(false);
2023-03-03 15:23:46 +00:00
}
2023-07-24 15:52:55 +01:00
/**
* Find a slot inside a container an item can be placed in
* @param container2D Container to find space in
* @param containerX Container x size
* @param containerY Container y size
* @param x ???
* @param y ???
* @param itemW Items width
* @param itemH Items height
* @returns True - slot found
*/
2023-11-15 20:35:05 -05:00
protected locateSlot(
container2D: number[][],
containerX: number,
containerY: number,
x: number,
y: number,
itemW: number,
itemH: number,
): boolean {
2023-07-24 15:52:55 +01:00
let foundSlot = true;
for (let itemY = 0; itemY < itemH; itemY++) {
if (foundSlot && y + itemH - 1 > containerY - 1) {
2023-07-24 15:52:55 +01:00
foundSlot = false;
break;
}
// Does item fit x-ways across
for (let itemX = 0; itemX < itemW; itemX++) {
if (foundSlot && x + itemW - 1 > containerX - 1) {
2023-07-24 15:52:55 +01:00
foundSlot = false;
break;
}
if (container2D[y + itemY][x + itemX] !== 0) {
2023-07-24 15:52:55 +01:00
foundSlot = false;
break;
}
}
if (!foundSlot) {
2023-07-24 15:52:55 +01:00
break;
}
}
return foundSlot;
}
/**
* Find a free slot for an item to be placed at
* @param container2D Container to place item in
* @param x Container x size
* @param y Container y size
* @param itemW Items width
* @param itemH Items height
* @param rotate is item rotated
*/
2023-11-15 20:35:05 -05:00
public fillContainerMapWithItem(
container2D: number[][],
x: number,
y: number,
itemW: number,
itemH: number,
rotate: boolean,
): void {
// Swap height/width if we want to fit it in rotated
2023-03-03 15:23:46 +00:00
const itemWidth = rotate ? itemH : itemW;
const itemHeight = rotate ? itemW : itemH;
for (let tmpY = y; tmpY < y + itemHeight; tmpY++) {
for (let tmpX = x; tmpX < x + itemWidth; tmpX++) {
if (container2D[tmpY][tmpX] === 0) {
// Flag slot as used
2023-03-03 15:23:46 +00:00
container2D[tmpY][tmpX] = 1;
} else {
throw new Error(`Slot at (${x}, ${y}) is already filled. Cannot fit a ${itemW} by ${itemH}`);
2023-03-03 15:23:46 +00:00
}
}
}
}
2023-11-15 20:35:05 -05:00
}