import { Num, Optional } from '@ephox/katamari'; export interface MatrixNavigationOutcome { readonly rowIndex: number; readonly columnIndex: number; readonly cell: A; } export type MatrixNavigationFunc = (matrix: A[][], startRow: number, startCol: number) => Optional>; const toCell = (matrix: A[][], rowIndex: number, columnIndex: number): Optional> => Optional.from(matrix[rowIndex]).bind((row) => Optional.from(row[columnIndex]).map((cell) => ({ rowIndex, columnIndex, cell }))); const cycleHorizontal = (matrix: A[][], rowIndex: number, startCol: number, deltaCol: number) => { const row = matrix[rowIndex]; const colsInRow = row.length; const newColIndex = Num.cycleBy(startCol, deltaCol, 0, colsInRow - 1); return toCell(matrix, rowIndex, newColIndex); }; const cycleVertical = (matrix: A[][], colIndex: number, startRow: number, deltaRow: number) => { const nextRowIndex = Num.cycleBy(startRow, deltaRow, 0, matrix.length - 1); const colsInNextRow = matrix[nextRowIndex].length; const nextColIndex = Num.clamp(colIndex, 0, colsInNextRow - 1); return toCell(matrix, nextRowIndex, nextColIndex); }; const moveHorizontal = (matrix: A[][], rowIndex: number, startCol: number, deltaCol: number) => { const row = matrix[rowIndex]; const colsInRow = row.length; const newColIndex = Num.clamp(startCol + deltaCol, 0, colsInRow - 1); return toCell(matrix, rowIndex, newColIndex); }; const moveVertical = (matrix: A[][], colIndex: number, startRow: number, deltaRow: number) => { const nextRowIndex = Num.clamp(startRow + deltaRow, 0, matrix.length - 1); const colsInNextRow = matrix[nextRowIndex].length; const nextColIndex = Num.clamp(colIndex, 0, colsInNextRow - 1); return toCell(matrix, nextRowIndex, nextColIndex); }; // return address(Math.floor(index / columns), index % columns); const cycleRight = (matrix: A[][], startRow: number, startCol: number): Optional> => cycleHorizontal(matrix, startRow, startCol, +1); const cycleLeft = (matrix: A[][], startRow: number, startCol: number): Optional> => cycleHorizontal(matrix, startRow, startCol, -1); const cycleUp = (matrix: A[][], startRow: number, startCol: number): Optional> => cycleVertical(matrix, startCol, startRow, -1); const cycleDown = (matrix: A[][], startRow: number, startCol: number): Optional> => cycleVertical(matrix, startCol, startRow, +1); const moveLeft = (matrix: A[][], startRow: number, startCol: number): Optional> => moveHorizontal(matrix, startRow, startCol, -1); const moveRight = (matrix: A[][], startRow: number, startCol: number): Optional> => moveHorizontal(matrix, startRow, startCol, +1); const moveUp = (matrix: A[][], startRow: number, startCol: number): Optional> => moveVertical(matrix, startCol, startRow, -1); const moveDown = (matrix: A[][], startRow: number, startCol: number): Optional> => moveVertical(matrix, startCol, startRow, +1); export { cycleRight, cycleLeft, cycleUp, cycleDown, moveLeft, moveRight, moveUp, moveDown };