Вопрос или проблема
Я хочу, чтобы новые тетромино появлялись в игре по мере увеличения времени игры, но это не работает. Они создаются, но фигуры не центрированы, они не непрерывны (например, фигура может выглядеть как две фигуры, потому что они не касаются друг друга), и иногда добавляется фигура, которая уже является частью массива фигур. Каждая фигура имеет максимум 12 квадратов и должна помещаться в пространство 4×4.
Вот мой код на данный момент:
function randomShape(score) {
const maxSize = 12; // Максимальное количество квадратов в фигуре
const centerOffset = 1; // Смещение для центрирования фигуры
const maxComplexity = Math.min(Math.floor(score / 100), 6); // Максимальная сложность на основе счета
let shape;
do {
shape = Array.from({ length: 4 }, () => Array(4).fill(0)); // Создать пустую фигуру 4x4
const size = Math.max(1, Math.floor(Math.random() * (maxComplexity + 1))); // Размер фигуры варьируется в зависимости от сложности
let squaresToPlace = Math.min(size, maxSize); // Ограничить количество размещаемых квадратов до maxSize
// Заполнение фигуры случайными позициями 1 в зависимости от размера
while (squaresToPlace > 0) {
const x = Math.floor(Math.random() * 4);
const y = Math.floor(Math.random() * 4);
// Размещать 1 только если место пустое
if (shape[y][x] === 0) {
shape[y][x] = 1;
squaresToPlace--;
}
}
} while (!shape.flat(5).includes(1)); // Повторить попытку, если фигура пустая
// Логика центрирования
const centeredShape = Array.from({ length: 4 }, () => Array(4).fill(0));
// Получить позиции всех заполненных ячеек
const filledPositions = [];
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
if (shape[r][c] === 1) {
filledPositions.push({ r, c });
}
}
}
let amount = 0;
shape.flat(5).forEach((s) => {
if (s === 1) amount++;
});
if (amount === 1) {
return [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 0],
];
}
// Определение, как центрировать фигуру
const minRow = Math.min(...filledPositions.map((p) => p.r));
const maxRow = Math.max(...filledPositions.map((p) => p.r));
const minCol = Math.min(...filledPositions.map((p) => p.c));
const maxCol = Math.max(...filledPositions.map((p) => p.c));
// Вычисление смещений, необходимых для центрирования фигуры
const height = maxRow - minRow + 1;
const width = maxCol - minCol + 1;
// Вычисление вертикальных и горизонтальных смещений
const rowOffset = Math.floor((4 - height) / 2); // Центрировать вертикально
const colOffset = Math.floor((4 - width) / 2); // Центрировать горизонтально
// Размещение фигуры в центрированном положении
filledPositions.forEach(({ r, c }) => {
// Убедиться, что мы размещаем элемент в границах
const newRow = r + rowOffset;
const newCol = c + colOffset;
if (newRow >= 0 && newRow < 4 && newCol >= 0 && newCol < 4) {
centeredShape[newRow][newCol] = 1;
}
});
return centeredShape;
}
Я пытался добавить новые случайные фигуры, которые должны были выглядеть нормально и быть центрированными, но они были сломаны и не центированы, а иногда дубликаты.
Ответ или решение
Чтобы создать новые случайные фигуры для игры, похожей на Тетрис, необходимо решить несколько ключевых проблем, связанных с центровкой, непрерывностью и дублированием фигур. Давайте рассмотрим оптимизированный и более эффективный подход к этой задаче, учитывая ваши текущие сложности с кодом.
Problemas y Recomendaciones
-
Центровка формы: Ваша логика по центровке может быть более упрощена с использованием простых вычислений для смещения. Все заполненные позиции должны быть перемещены так, чтобы они располагались в пределах 4×4.
-
Непрерывные формы: Мы должны убедиться, что созданные фигуры являются непрерывными. Это значит, что все квадраты должны быть связаны так, что можно построить фигуру без разрывов.
-
Избежание дубликатов: Нужно хранить уже созданные формы, чтобы избежать повторного появления тех же самых фигур.
Оптимизированный код
function randomShape(score, existingShapes) {
const maxSize = 12; // Максимальное количество клеточек в фигуре
const maxComplexity = Math.min(Math.floor(score / 100), 6); // Максимальная сложность на основе счета
const shapeSet = new Set(existingShapes.map(JSON.stringify)); // Для избежания дубликатов
let shape;
let isValidShape = false;
while (!isValidShape) {
shape = Array.from({ length: 4 }, () => Array(4).fill(0));
const size = Math.max(1, Math.floor(Math.random() * (maxComplexity + 1))); // Генерация размера фигуры
let squaresToPlace = Math.min(size, maxSize);
// Размещение клеточек в фигуре
while (squaresToPlace > 0) {
const x = Math.floor(Math.random() * 4);
const y = Math.floor(Math.random() * 4);
if (shape[y][x] === 0) {
shape[y][x] = 1;
squaresToPlace--;
}
}
// Проверка непрерывности
if (checkContinuity(shape)) {
const centeredShape = centerShape(shape);
const shapeString = JSON.stringify(centeredShape);
if (!shapeSet.has(shapeString)) {
shapeSet.add(shapeString);
isValidShape = true;
return centeredShape;
}
}
}
}
// Функция для проверки непрерывности фигуры
function checkContinuity(shape) {
const filledPositions = [];
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
if (shape[r][c] === 1) {
filledPositions.push({ r, c });
}
}
}
if (filledPositions.length === 0) return false;
const visited = new Set();
function dfs(pos) {
const stack = [pos];
while (stack.length > 0) {
const { r, c } = stack.pop();
if (visited.has(`${r},${c}`)) continue;
visited.add(`${r},${c}`);
for (const [dr, dc] of [[-1, 0], [1, 0], [0, -1], [0, 1]]) {
const newRow = r + dr;
const newCol = c + dc;
if (newRow >= 0 && newRow < 4 && newCol >= 0 && newCol < 4 && shape[newRow][newCol] === 1) {
stack.push({ r: newRow, c: newCol });
}
}
}
}
dfs(filledPositions[0]);
return filledPositions.length === visited.size;
}
// Функция для центровки фигуры
function centerShape(shape) {
const filledPositions = [];
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
if (shape[r][c] === 1) {
filledPositions.push({ r, c });
}
}
}
if (filledPositions.length === 0) return shape;
const minRow = Math.min(...filledPositions.map(pos => pos.r));
const minCol = Math.min(...filledPositions.map(pos => pos.c));
const centeredShape = Array.from({ length: 4 }, () => Array(4).fill(0));
filledPositions.forEach(({ r, c }) => {
centeredShape[r - minRow][c - minCol] = 1;
});
return centeredShape;
}
Объяснение кода
- Функция
randomShape
: Основная логика, где создаются случайные фигуры, которые проверяются на непрерывность и дубликаты. - Функция
checkContinuity
: Использует DFS для проверки, что все заполненные клетки связаны друг с другом. - Функция
centerShape
: Принимает фигуру и центрует ее, переставляя заполненные клетки на минимальные индексы.
Заключение
Эта реализация предоставит вам новые фигуры для вашей игры Тетрис, которые будут нормально распределены, непрерывными и уникальными. Не забудьте обновить массив existingShapes
при добавлении новых фигур, чтобы сохранить уникальность.