Extract tile size change logic into a function
This commit is contained in:
parent
e99294c3f1
commit
4e35984900
1 changed files with 82 additions and 77 deletions
|
@ -236,6 +236,85 @@ const fillGaps = (g: Grid): Grid => {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cycleTileSize = (tileId: string, g: Grid): Grid => {
|
||||||
|
// TODO: When unenlarging tiles, do all this in reverse somehow (deleting
|
||||||
|
// rows and displacing tiles. pushing tiles outwards might be necessary)
|
||||||
|
|
||||||
|
const from = g.cells.findIndex(c => c?.item.id === tileId)
|
||||||
|
if (from === -1) return g // Tile removed, no change
|
||||||
|
const fromWidth = g.cells[from]!.columns
|
||||||
|
const fromHeight = g.cells[from]!.rows
|
||||||
|
const fromEnd = areaEnd(from, fromWidth, fromHeight, g)
|
||||||
|
|
||||||
|
const [toWidth, toHeight] = fromWidth === 1 && fromHeight === 1 ? [3, 2] : [1, 1]
|
||||||
|
const newRows = Math.ceil((toWidth * toHeight - fromWidth * fromHeight) / g.columns)
|
||||||
|
|
||||||
|
const candidateWidth = toWidth
|
||||||
|
const candidateHeight = toHeight - newRows
|
||||||
|
|
||||||
|
const nextScanLocations = new Set<number>([from])
|
||||||
|
const scanColumnOffset = Math.floor((toWidth - 1) / 2)
|
||||||
|
const scanRowOffset = Math.floor((toHeight - 1) / 2)
|
||||||
|
let to: number | null = null
|
||||||
|
|
||||||
|
const displaceable = (c: Cell | undefined, i: number): boolean => c === undefined || (c.columns === 1 && c.rows === 1) || inArea(i, from, fromEnd, g)
|
||||||
|
|
||||||
|
for (const scanLocation of nextScanLocations) {
|
||||||
|
const start = scanLocation - scanColumnOffset - g.columns * scanRowOffset
|
||||||
|
const end = areaEnd(start, candidateWidth, candidateHeight, g)
|
||||||
|
const startColumn = column(start, g);
|
||||||
|
const endColumn = column(end, g);
|
||||||
|
|
||||||
|
if (start >= 0 && end < g.cells.length && endColumn - startColumn + 1 === candidateWidth) {
|
||||||
|
if (allCellsInArea(start, end, g, displaceable)) {
|
||||||
|
to = start
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startColumn > 0) nextScanLocations.add(scanLocation - 1)
|
||||||
|
if (endColumn < g.columns - 1) nextScanLocations.add(scanLocation + 1)
|
||||||
|
nextScanLocations.add(scanLocation - g.columns)
|
||||||
|
nextScanLocations.add(scanLocation + g.columns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Don't give up on placing the tile yet
|
||||||
|
if (to === null) return g
|
||||||
|
|
||||||
|
const gappyGrid: Grid = {
|
||||||
|
...g,
|
||||||
|
generation: g.generation + 1,
|
||||||
|
cells: new Array(g.cells.length + newRows * g.columns),
|
||||||
|
}
|
||||||
|
|
||||||
|
const toRow = row(to, g)
|
||||||
|
|
||||||
|
for (let src = 0; src < g.cells.length; src++) {
|
||||||
|
if (g.cells[src]?.item.id !== tileId) {
|
||||||
|
const dest = row(src, g) > toRow + toHeight - 1 ? src + g.columns * newRows : src
|
||||||
|
gappyGrid.cells[dest] = g.cells[src]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const displacedTiles: Cell[] = []
|
||||||
|
const toEnd = areaEnd(to, toWidth, toHeight, g)
|
||||||
|
forEachCellInArea(to, toEnd, gappyGrid, (c, i) => {
|
||||||
|
if (c !== undefined) displacedTiles.push(c)
|
||||||
|
gappyGrid.cells[i] = {
|
||||||
|
item: g.cells[from]!.item,
|
||||||
|
slot: i === to,
|
||||||
|
columns: toWidth,
|
||||||
|
rows: toHeight,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let i = 0; displacedTiles.length > 0; i++) {
|
||||||
|
if (gappyGrid.cells[i] === undefined) gappyGrid.cells[i] = displacedTiles.shift()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fillGaps(gappyGrid)
|
||||||
|
}
|
||||||
|
|
||||||
export const NewVideoGrid: FC<Props> = ({
|
export const NewVideoGrid: FC<Props> = ({
|
||||||
items,
|
items,
|
||||||
disableAnimations,
|
disableAnimations,
|
||||||
|
@ -391,83 +470,9 @@ export const NewVideoGrid: FC<Props> = ({
|
||||||
const tileId = args[0] as string
|
const tileId = args[0] as string
|
||||||
|
|
||||||
if (tap) {
|
if (tap) {
|
||||||
// TODO: When unenlarging tiles, do this in reverse somehow (deleting
|
setGrid(g => cycleTileSize(tileId, g))
|
||||||
// rows and displacing tiles. pushing tiles outwards might be necessary)
|
} else {
|
||||||
setGrid(g => {
|
// TODO
|
||||||
const from = g.cells.findIndex(c => c?.item.id === tileId)
|
|
||||||
if (from === -1) return g // Tile removed, no change
|
|
||||||
const fromWidth = g.cells[from]!.columns
|
|
||||||
const fromHeight = g.cells[from]!.rows
|
|
||||||
const fromEnd = areaEnd(from, fromWidth, fromHeight, g)
|
|
||||||
|
|
||||||
const [toWidth, toHeight] = fromWidth === 1 && fromHeight === 1 ? [3, 2] : [1, 1]
|
|
||||||
const newRows = Math.ceil((toWidth * toHeight - fromWidth * fromHeight) / g.columns)
|
|
||||||
|
|
||||||
const candidateWidth = toWidth
|
|
||||||
const candidateHeight = toHeight - newRows
|
|
||||||
|
|
||||||
const nextScanLocations = new Set<number>([from])
|
|
||||||
const scanColumnOffset = Math.floor((toWidth - 1) / 2)
|
|
||||||
const scanRowOffset = Math.floor((toHeight - 1) / 2)
|
|
||||||
let to: number | null = null
|
|
||||||
|
|
||||||
const displaceable = (c: Cell | undefined, i: number): boolean => c === undefined || (c.columns === 1 && c.rows === 1) || inArea(i, from, fromEnd, g)
|
|
||||||
|
|
||||||
for (const scanLocation of nextScanLocations) {
|
|
||||||
const start = scanLocation - scanColumnOffset - g.columns * scanRowOffset
|
|
||||||
const end = areaEnd(start, candidateWidth, candidateHeight, g)
|
|
||||||
const startColumn = column(start, g);
|
|
||||||
const endColumn = column(end, g);
|
|
||||||
|
|
||||||
if (start >= 0 && end < g.cells.length && endColumn - startColumn + 1 === candidateWidth) {
|
|
||||||
if (allCellsInArea(start, end, g, displaceable)) {
|
|
||||||
to = start
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startColumn > 0) nextScanLocations.add(scanLocation - 1)
|
|
||||||
if (endColumn < g.columns - 1) nextScanLocations.add(scanLocation + 1)
|
|
||||||
nextScanLocations.add(scanLocation - g.columns)
|
|
||||||
nextScanLocations.add(scanLocation + g.columns)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Don't give up on placing the tile yet
|
|
||||||
if (to === null) return g
|
|
||||||
|
|
||||||
const gappyGrid: Grid = {
|
|
||||||
...g,
|
|
||||||
generation: g.generation + 1,
|
|
||||||
cells: new Array(g.cells.length + newRows * g.columns),
|
|
||||||
}
|
|
||||||
|
|
||||||
const toRow = row(to, g)
|
|
||||||
|
|
||||||
for (let src = 0; src < g.cells.length; src++) {
|
|
||||||
if (g.cells[src]?.item.id !== tileId) {
|
|
||||||
const dest = row(src, g) > toRow + toHeight - 1 ? src + g.columns * newRows : src
|
|
||||||
gappyGrid.cells[dest] = g.cells[src]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const displacedTiles: Cell[] = []
|
|
||||||
const toEnd = areaEnd(to, toWidth, toHeight, g)
|
|
||||||
forEachCellInArea(to, toEnd, gappyGrid, (c, i) => {
|
|
||||||
if (c !== undefined) displacedTiles.push(c)
|
|
||||||
gappyGrid.cells[i] = {
|
|
||||||
item: g.cells[from]!.item,
|
|
||||||
slot: i === to,
|
|
||||||
columns: toWidth,
|
|
||||||
rows: toHeight,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for (let i = 0; displacedTiles.length > 0; i++) {
|
|
||||||
if (gappyGrid.cells[i] === undefined) gappyGrid.cells[i] = displacedTiles.shift()
|
|
||||||
}
|
|
||||||
|
|
||||||
return fillGaps(gappyGrid)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ filterTaps: true, pointer: { buttons: [1] } }
|
{ filterTaps: true, pointer: { buttons: [1] } }
|
||||||
|
|
Loading…
Reference in a new issue