Я думаю, что проблема может быть проще, если массив, представляющий игровое поле, заполнен полностью, а у Рыцарей и Героев есть уникальные идентификаторы, чтобы было легче определить группу ячеек, принадлежащих одному герою.
Затем воспользуйтесь функцией, которая будет проходить по строкам, начиная со второго до последнего, ища пустые ячейки под Рыцарями и Героями, чтобы определить, могут ли они выпасть в ряд ...
Посмотрите в следующем примере кода. В первом тесте ничего не может упасть, поэтому результат остается прежним. Во втором тесте рыцарь был удален (ID 1006), и результат отражает рыцарей и героев, которые могут упасть ...
function shiftCells( board ) {
let rowCount = board.length;
let colCount = board[0].length;
for ( row = rowCount - 2; 0 <= row; row-- ) {
let test = new Map();
for ( col = 0; col < colCount; col++ ) {
// Check if there is an ID in the cell...
if ( board[ row ][ col ] ) {
// ...and if so, then accumulate whether all cells below this ID are empty.
let currentTest = test.get( board[ row ][ col ] ) == undefined ? true : test.get( board[ row ][ col ] );
test.set( board[ row ][ col ], currentTest && ( board[ row + 1 ][ col ] === null ) );
}
}
// Now, loop through the test list to see if we need to drop any cells down.
for ( col = 0; col < colCount; col++ ) {
// Again, check if there is an ID in the cell...
if ( board[ row ][ col ] ) {
// ...and if so, then were all the cells below this ID empty?
if ( test.get( board[ row ][ col ] ) ) {
// If so, then move the ID down a row.
board[ row + 1 ][ col ] = board[ row ][ col ];
board[ row ][ col ] = null;
}
}
}
}
}
function printBoard( message, board ) {
console.log( message )
for ( row = 0; row < board.length; row++ ) {
let rowText = '';
for ( col = 0; col < board[0].length; col++ ) {
rowText += board[ row ][ col ] + ' ';
}
console.log( rowText );
}
console.log( '\n' );
}
var myBoard;
myBoard = [
[ null, null, null, null, 1000, null, null, null ],
[ null, null, null, 2000, 2000, null, null, null ],
[ null, null, 1001, 2000, 2000, null, null, null ],
[ null, null, 2001, 2001, null, null, null, null ],
[ null, 1002, 2001, 2001, 1003, null, 1004, null ],
[ null, 1005, null, 1006, 1007, null, 1008, 1009 ]
];
printBoard( 'Test 1', myBoard );
shiftCells( myBoard );
printBoard( 'Test 1 results', myBoard );
myBoard = [
[ null, null, null, null, 1000, null, null, null ],
[ null, null, null, 2000, 2000, null, null, null ],
[ null, null, 1001, 2000, 2000, null, null, null ],
[ null, null, 2001, 2001, null, null, null, null ],
[ null, 1002, 2001, 2001, 1003, null, 1004, null ],
[ null, 1005, null, null, 1007, null, 1008, 1009 ]
];
printBoard( 'Test 2', myBoard );
shiftCells( myBoard );
printBoard( 'Test 2 results', myBoard );
Надеюсь, это поможет ...
РЕДАКТИРОВАТЬ: у приведенного выше кода был недостаток в том, что он будет сдвигать фигуру только на одну строку вниз, в то время как в некоторых случаях удаление фигуры требует, чтобы некоторые фигуры отбрасывали более одной ячейки. Многократный запуск вышеуказанного алгоритма на одной и той же плате - это хак, который работает, но неоптимально. Следующая версия использует другой подход ...
Основное отличие состоит в том, что эта версия отслеживает фигуры и строит доску на лету. При этом после удаления фигуры алгоритм просматривает список фигур, начиная с самой нижней строки, чтобы определить, является ли строка под рисунком пустой, и, если это так, отбрасывает фигуру в строку. Он продолжает проверять, может ли фигура продолжать отбрасывать другой ряд, прежде чем перейти к следующему рисунку ...
function printBoard( message, board ) {
console.log( message )
for ( row = 0; row < board.length; row++ ) {
let rowText = '';
for ( col = 0; col < board[0].length; col++ ) {
rowText += board[ row ][ col ] + ' ';
}
console.log( rowText );
}
console.log( '\n' );
}
function buildBoardFromFigures( figures ) {
let board = [];
for ( let row = 0; row < boardHeight; row++ ) {
board[ row ] = [];
for ( let col = 0; col < boardWidth; col++ ) {
board[ row ][ col ] = null;
}
}
for ( let id of Object.keys( figures ) ) {
for ( let row = figures[ id ].row; row < figures[ id ].row + figures[ id ].height; row++ ) {
for ( let col = figures[ id ].col; col < figures[ id ].col + figures[ id ].width; col++ ) {
board[ row ][ col ] = id;
}
}
}
return board;
}
function shiftDown( figures ) {
let bottomFirst = Object.keys( figures ).sort( ( a, b ) => figures[ b ].row - figures[ a ].row );
let board = buildBoardFromFigures( figures );
let rowCount = board.length;
for ( let id of bottomFirst ) {
let emptyBelow = true;
while ( emptyBelow ) {
let rowToCheck = figures[ id ].row + figures[ id ].height;
for ( let col = figures[ id ].col; col < figures[ id ].col + figures[ id ].width; col++ ) {
emptyBelow = emptyBelow && ( rowToCheck < rowCount && board[ rowToCheck ][ col ] == null );
}
if ( emptyBelow ) {
for ( let col = figures[ id ].col; col < figures[ id ].col + figures[ id ].width; col++ ) {
board[ figures[ id ].row ][ col ] = null;
board[ figures[ id ].row + figures[ id ].height ][ col ] = id;
}
figures[ id ].row++;
}
}
}
return board;
}
var boardHeight = 6;
var boardWidth = 8;
var myFigures;
myFigures = {
"1000": { type: "knight", row: 0, col: 4, width: 1, height: 1 },
"2000": { type: "hero", row: 1, col: 3, width: 2, height: 2 },
"1001": { type: "knight", row: 2, col: 2, width: 1, height: 1 },
"2001": { type: "hero", row: 3, col: 2, width: 2, height: 2 },
"1002": { type: "knight", row: 4, col: 1, width: 1, height: 1 },
"1003": { type: "knight", row: 4, col: 4, width: 1, height: 1 },
"1004": { type: "knight", row: 4, col: 6, width: 1, height: 1 },
"1005": { type: "knight", row: 5, col: 1, width: 1, height: 1 },
"1006": { type: "knight", row: 5, col: 3, width: 1, height: 1 },
"1007": { type: "knight", row: 5, col: 4, width: 1, height: 1 },
"1008": { type: "knight", row: 5, col: 6, width: 1, height: 1 },
"1009": { type: "knight", row: 5, col: 7, width: 1, height: 1 }
};
printBoard( 'Test 1', buildBoardFromFigures( myFigures ) );
shiftDown( myFigures );
printBoard( 'Test 1 Result', buildBoardFromFigures( myFigures ) );
delete myFigures[ "2000" ];
printBoard( 'Test 2', buildBoardFromFigures( myFigures ) );
shiftDown( myFigures );
printBoard( 'Test 2 Result', buildBoardFromFigures( myFigures ) );
Этот второй ответ чище, чем первый, но может привести к большему пересмотру вашего приложения ...