この解答例はChatGPTによって生成されています,正しいかは自己判断で。

BFE.devでのAI解答例 - JavaScript コーディング問題
174. CSS Grid Layout auto-placement algorithm - sparse

type Grid = Array<Array<number>>
type Item = {
  id: number,
  style?: {
    gridRowStart?: number | string,
    gridRowEnd?: number | string,
    gridColumnStart?: number | string
    gridColumnEnd?: number | string
  }
}

function layout(rows: number, columns: number, items: Array<Item>): Grid {
  const grid = Array.from({ length: rows }, () => new Array(columns).fill(0)); // initialize the grid with 0
  let currentItemIndex = 0;
  for (let rowIndex = 1; rowIndex <= rows; rowIndex++) {
    for (let columnIndex = 1; columnIndex <= columns; columnIndex++) {
      // check if current cell is unoccupied
      if (grid[rowIndex - 1][columnIndex - 1] === 0) {
        // check if there are remaining items to place
        if (currentItemIndex >= items.length) {
          return grid; // all items are placed
        }
        const currentItem = items[currentItemIndex];
        let itemRowStart, itemRowEnd, itemColStart, itemColEnd;
        // extract start and end values for item's row and column
        if (currentItem.style) {
          const { gridRowStart, gridRowEnd, gridColumnStart, gridColumnEnd } = currentItem.style;
          if (gridRowStart || gridColumnStart) {
            itemRowStart = gridRowStart ? getStartIndex(gridRowStart) : rowIndex;
            itemRowEnd = gridRowEnd ? getEndIndex(gridRowEnd, rows) : itemRowStart;
            itemColStart = gridColumnStart ? getStartIndex(gridColumnStart) : columnIndex;
            itemColEnd = gridColumnEnd ? getEndIndex(gridColumnEnd, columns) : itemColStart;
          } else {
            itemRowStart = rowIndex;
            itemRowEnd = rowIndex;
            itemColStart = columnIndex;
            itemColEnd = columnIndex;
          }
        } else {
          itemRowStart = rowIndex;
          itemRowEnd = rowIndex;
          itemColStart = columnIndex;
          itemColEnd = columnIndex;
        }
        // check if the item fits inside the grid
        if (itemRowStart > rows || itemRowEnd > rows 
            || itemColStart > columns || itemColEnd > columns) {
          throw new Error('Item does not fit inside the grid');
        }
        // check if the item overlaps with any earlier items
        for (let i = itemRowStart - 1; i < itemRowEnd; i++) {
          for (let j = itemColStart - 1; j < itemColEnd; j++) {
            if (grid[i][j] !== 0) {
              throw new Error('Item overlaps with earlier placed items');
            }
          }
        }
        // place the item
        for (let i = itemRowStart - 1; i < itemRowEnd; i++) {
          for (let j = itemColStart - 1; j < itemColEnd; j++) {
            grid[i][j] = currentItem.id;
          }
        }
        currentItemIndex++;
      }
    }
  }
  return grid;
}

// helper function to extract start index from grid line value
function getStartIndex(line: string | number): number {
  if (typeof line === 'number') {
    return line;
  }
  const match = line.match(/\d+/);
  if (!match) {
    throw new Error('Invalid value for grid line');
  }
  return parseInt(match[0]);
}

// helper function to extract end index from grid line value
function getEndIndex(line: string, max: number): number {
  if (line === 'span') {
    throw new Error('Invalid value for grid line');
  }
  const match = line.match(/\d+/);
  if (!match) {
    throw new Error('Invalid value for grid line');
  }
  return Math.min(parseInt(match[0]), max);
}

Explanation:

  • We first initialize the grid with all 0's, where rows and columns give the dimensions of the grid.
  • We then create two nested loops that iterate over each cell of the grid.
  • For each unoccupied cell, we check if there are remaining items to place. If there are no more items to place, we return the resulting grid.
  • If there are more items to place, we get the details of the next item and extract the start and end values for the item's row and column, based on the specified gridRowStart, gridRowEnd, gridColumnStart, and gridColumnEnd values. If these values are not specified, we assume that the item occupies a single cell.
  • If the calculated row and column values for the item lie outside of the grid dimensions, we throw an error.
  • We then check if the item overlaps with any earlier placed items. If it does, we also throw an error.
  • If the item does not overlap with any earlier placed items, we place the item in the grid.
  • Finally, we increment the currentIndex so that we move to the next item in the items array.