mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Redo stacking algorithm (#138)
* Change stacking algorithm to keep shapes whole rather than splitting by layer. * Ensure that layerToMergeAt is not less than 0.
This commit is contained in:
parent
209fc76fc7
commit
ef574c0bfe
@ -513,57 +513,68 @@ export class ShapeDefinition extends BasicSerializableObject {
|
||||
* @param {ShapeDefinition} definition
|
||||
*/
|
||||
cloneAndStackWith(definition) {
|
||||
const newLayers = this.internalCloneLayers();
|
||||
|
||||
if (this.isEntirelyEmpty() || definition.isEntirelyEmpty()) {
|
||||
assert(false, "Can not stack entirely empty definition");
|
||||
}
|
||||
|
||||
// Put layer for layer on top
|
||||
for (let i = 0; i < definition.layers.length; ++i) {
|
||||
const layerToAdd = definition.layers[i];
|
||||
const bottomShapeLayers = this.layers;
|
||||
const bottomShapeHighestLayerByQuad = [-1, -1, -1, -1];
|
||||
|
||||
// On which layer we can merge this upper layer
|
||||
let mergeOnLayerIndex = null;
|
||||
|
||||
// Go from top to bottom and check if there is anything intercepting it
|
||||
for (let k = newLayers.length - 1; k >= 0; --k) {
|
||||
const lowerLayer = newLayers[k];
|
||||
|
||||
let canMerge = true;
|
||||
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
|
||||
const upperItem = layerToAdd[quadrantIndex];
|
||||
const lowerItem = lowerLayer[quadrantIndex];
|
||||
|
||||
if (upperItem && lowerItem) {
|
||||
// so, we can't merge it because two items conflict
|
||||
canMerge = false;
|
||||
break;
|
||||
}
|
||||
for (let layer = bottomShapeLayers.length - 1; layer >= 0; --layer) {
|
||||
const shapeLayer = bottomShapeLayers[layer];
|
||||
for (let quad = 0; quad < 4; ++quad) {
|
||||
const shapeQuad = shapeLayer[quad];
|
||||
if (shapeQuad !== null && bottomShapeHighestLayerByQuad[quad] < layer) {
|
||||
bottomShapeHighestLayerByQuad[quad] = layer;
|
||||
}
|
||||
|
||||
// If we can merge it, store it - since we go from top to bottom
|
||||
// we can simply override it
|
||||
if (canMerge) {
|
||||
mergeOnLayerIndex = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (mergeOnLayerIndex !== null) {
|
||||
// Simply merge using an OR mask
|
||||
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
|
||||
newLayers[mergeOnLayerIndex][quadrantIndex] =
|
||||
newLayers[mergeOnLayerIndex][quadrantIndex] || layerToAdd[quadrantIndex];
|
||||
}
|
||||
} else {
|
||||
// Add new layer
|
||||
newLayers.push(layerToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
newLayers.splice(4);
|
||||
const topShapeLayers = definition.layers;
|
||||
const topShapeLowestLayerByQuad = [4, 4, 4, 4];
|
||||
|
||||
return new ShapeDefinition({ layers: newLayers });
|
||||
for (let layer = 0; layer < topShapeLayers.length; ++layer) {
|
||||
const shapeLayer = topShapeLayers[layer];
|
||||
for (let quad = 0; quad < 4; ++quad) {
|
||||
const shapeQuad = shapeLayer[quad];
|
||||
if (shapeQuad !== null && topShapeLowestLayerByQuad[quad] > layer) {
|
||||
topShapeLowestLayerByQuad[quad] = layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to find the number `layerToMergeAt` such that when the top shape is placed at that
|
||||
* layer, the smallest gap between shapes is only 1. Instead of doing a guess-and-check method to
|
||||
* find the appropriate layer, we just calculate all the gaps assuming a merge at layer 0, even
|
||||
* though they go negative, and calculating the number to add to it so the minimum gap is 1 (ends
|
||||
* up being 1 - minimum).
|
||||
*/
|
||||
const gapsBetweenShapes = [];
|
||||
for (let quad = 0; quad < 4; ++quad) {
|
||||
gapsBetweenShapes.push(topShapeLowestLayerByQuad[quad] - bottomShapeHighestLayerByQuad[quad]);
|
||||
}
|
||||
const smallestGapBetweenShapes = Math.min(...gapsBetweenShapes);
|
||||
// Can't merge at a layer lower than 0
|
||||
const layerToMergeAt = Math.max(1 - smallestGapBetweenShapes, 0);
|
||||
|
||||
const mergedLayers = this.internalCloneLayers();
|
||||
for (let layer = mergedLayers.length; layer < layerToMergeAt + topShapeLayers.length; ++layer) {
|
||||
mergedLayers.push([null, null, null, null]);
|
||||
}
|
||||
|
||||
for (let layer = 0; layer < topShapeLayers.length; ++layer) {
|
||||
const layerMergingAt = layerToMergeAt + layer;
|
||||
const bottomShapeLayer = mergedLayers[layerMergingAt];
|
||||
const topShapeLayer = topShapeLayers[layer];
|
||||
for (let quad = 0; quad < 4; quad++) {
|
||||
bottomShapeLayer[quad] = bottomShapeLayer[quad] || topShapeLayer[quad];
|
||||
}
|
||||
}
|
||||
|
||||
mergedLayers.splice(4);
|
||||
|
||||
return new ShapeDefinition({ layers: mergedLayers });
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user