bind
и вызывать его. applySmallHeader
(когда позиция скролла по вертикали больше 80 пикселей) и applyNormalHeader
(когда позиция скролла по вертикали меньше или равна 80 пикселям). Функция scrollFunction
была переименована в onPageScroll
, в которой мы вызываем уже ранее описанные функции. При вводе доп. проверки на ширину экрана необходимо учесть следующие вещи:/**
* @typedef Piece
* @type {object}
* @property {number} id
* @property {PieceEdges} edges
*/
/**
* @typedef PieceEdges
* @type {object}
* @property {PieceEdge|null} top
* @property {PieceEdge|null} right
* @property {PieceEdge|null} bottom
* @property {PieceEdge|null} left
*/
/**
* @typedef PieceEdge
* @type {object}
* @property {number} edgeTypeId
* @property {'inside'|'outside'} type
*/
const order = ['top', 'right', 'bottom', 'left'];
const Direction = {
Right: 1,
Bottom: 2,
Left: 3,
};
/**
* @param {Piece} piece
*/
const rotatePiece = piece => {
[piece.edges.top, piece.edges.right, piece.edges.bottom, piece.edges.left] = [
piece.edges.left,
piece.edges.top,
piece.edges.right,
piece.edges.bottom,
];
return piece;
};
/**
* @param {string} edge
*/
const oppositeEdge = edge => {
switch (edge) {
case 'top':
return 'bottom';
case 'right':
return 'left';
case 'bottom':
return 'top';
case 'left':
return 'right';
}
};
/**
* @param {Piece[]} pieces
*/
const fixFirstPiece = pieces => {
const piece = pieces[0];
while (piece.edges.right === null || piece.edges.bottom === null) {
rotatePiece(piece);
}
};
/**
* @param {Piece[]} pieces
* @returns {Map<number, Piece>}
*/
const linkPieces = pieces => {
const store = pieces.reduce((accumulator, piece) => {
accumulator.set(piece.id, {
id: piece.id,
edges: {
top: null,
right: null,
bottom: null,
left: null,
},
});
return accumulator;
}, new Map());
fixFirstPiece(pieces);
const usedPieces = new Set();
const queuedPieces = new Set();
const currentPieces = [pieces[0]];
while (currentPieces.length > 0) {
const piece = currentPieces.shift();
const storedPiece = store.get(piece.id);
for (const edge in piece.edges) {
if (piece.edges[edge] !== null) {
const { edgeTypeId, type } = piece.edges[edge];
const neighbor = pieces.find(otherPiece =>
Object.values(otherPiece.edges).some(edge =>
edge !== null
? edge.edgeTypeId === edgeTypeId && edge.type !== type
: false
)
);
const edgeIndex = Object.values(neighbor.edges).findIndex(edge =>
edge !== null ? edge.edgeTypeId === edgeTypeId : false
);
let rotateCount = order.indexOf(oppositeEdge(edge)) - edgeIndex;
if (rotateCount < 0) {
rotateCount += order.length;
}
for (let index = 0; index < rotateCount; index++) {
rotatePiece(neighbor);
}
if (storedPiece.edges[edge] === null) {
storedPiece.edges[edge] = store.get(neighbor.id);
if (!usedPieces.has(neighbor.id) && !queuedPieces.has(neighbor.id)) {
currentPieces.push(neighbor);
queuedPieces.add(neighbor.id);
}
}
}
}
usedPieces.add(piece.id);
queuedPieces.delete(piece.id);
}
return store;
};
/**
* @param {Piece[]} pieces
* @returns {number[]}
*/
const solvePuzzle = pieces => {
const linkedPieces = linkPieces(pieces);
const length = pieces.length;
const result = new Array(length);
const size = Math.sqrt(length);
const position = { x: 0, y: 0 };
let direction = Direction.Right;
let piece = linkedPieces.get(pieces[0].id);
let index = 0;
while (index < length) {
result[position.x + position.y * size] = piece.id;
index++;
if (direction === Direction.Right) {
if (piece.edges.right !== null) {
piece = piece.edges.right;
position.x++;
} else {
direction = Direction.Down;
}
}
if (direction === Direction.Left) {
if (piece.edges.left !== null) {
piece = piece.edges.left;
position.x--;
} else {
direction = Direction.Down;
}
}
if (direction === Direction.Down) {
piece = piece.edges.bottom;
position.y++;
if (position.x === 0) {
direction = Direction.Right;
} else {
direction = Direction.Left;
}
}
}
return result;
};
(10.1).toLocaleString('ru-RU'); // 10,1