1
0
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:
hexagonhexagon 2020-07-26 17:09:50 -04:00 committed by GitHub
parent 209fc76fc7
commit ef574c0bfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -513,57 +513,68 @@ export class ShapeDefinition extends BasicSerializableObject {
* @param {ShapeDefinition} definition * @param {ShapeDefinition} definition
*/ */
cloneAndStackWith(definition) { cloneAndStackWith(definition) {
const newLayers = this.internalCloneLayers();
if (this.isEntirelyEmpty() || definition.isEntirelyEmpty()) { if (this.isEntirelyEmpty() || definition.isEntirelyEmpty()) {
assert(false, "Can not stack entirely empty definition"); assert(false, "Can not stack entirely empty definition");
} }
// Put layer for layer on top const bottomShapeLayers = this.layers;
for (let i = 0; i < definition.layers.length; ++i) { const bottomShapeHighestLayerByQuad = [-1, -1, -1, -1];
const layerToAdd = definition.layers[i];
// On which layer we can merge this upper layer for (let layer = bottomShapeLayers.length - 1; layer >= 0; --layer) {
let mergeOnLayerIndex = null; const shapeLayer = bottomShapeLayers[layer];
for (let quad = 0; quad < 4; ++quad) {
// Go from top to bottom and check if there is anything intercepting it const shapeQuad = shapeLayer[quad];
for (let k = newLayers.length - 1; k >= 0; --k) { if (shapeQuad !== null && bottomShapeHighestLayerByQuad[quad] < layer) {
const lowerLayer = newLayers[k]; bottomShapeHighestLayerByQuad[quad] = layer;
}
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;
} }
} }
// If we can merge it, store it - since we go from top to bottom const topShapeLayers = definition.layers;
// we can simply override it const topShapeLowestLayerByQuad = [4, 4, 4, 4];
if (canMerge) {
mergeOnLayerIndex = k; 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;
}
} }
} }
if (mergeOnLayerIndex !== null) { /**
// Simply merge using an OR mask * We want to find the number `layerToMergeAt` such that when the top shape is placed at that
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) { * layer, the smallest gap between shapes is only 1. Instead of doing a guess-and-check method to
newLayers[mergeOnLayerIndex][quadrantIndex] = * find the appropriate layer, we just calculate all the gaps assuming a merge at layer 0, even
newLayers[mergeOnLayerIndex][quadrantIndex] || layerToAdd[quadrantIndex]; * 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]);
} }
} else { const smallestGapBetweenShapes = Math.min(...gapsBetweenShapes);
// Add new layer // Can't merge at a layer lower than 0
newLayers.push(layerToAdd); 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];
} }
} }
newLayers.splice(4); mergedLayers.splice(4);
return new ShapeDefinition({ layers: newLayers }); return new ShapeDefinition({ layers: mergedLayers });
} }
/** /**