[Refac] 보드게임 BLOKUS 리팩터링하기 - 0

este·2024년 10월 26일
0

BLOKUS-SvelteKit

목록 보기
1/8
export const putBlockOnBoard = (
  board: (string | number)[][],
  newBlock: number[][],
  position: number[],
  rotation: number,
  player: string,
  flip = false,
): (string | number
)[][] => {
  if (position.length !== 2) {
    throw new Error('position length must be 2');
  }
  if (/0-3/.test(rotation.toString())) {
    throw new Error('rotation must be included in 0-3');
  }
  let rotatedBlock = rotation === 0 ? newBlock : rotateBlock(newBlock, rotation);
  if (flip) {
    rotatedBlock = flipBlock(rotatedBlock);
  }
  const currentBoard = board;
  if (isAvailableArea(currentBoard, rotatedBlock, position, player)) {
    const x = rotatedBlock[0].length;
    const y = rotatedBlock.length;
    for (let i = 0; i < y; i += 1) {
      for (let j = 0; j < x; j += 1) {
        if (currentBoard[position[0] + i][position[1] + j] === 0 && rotatedBlock[i][j] === 1) {
          currentBoard[position[0] + i][position[1] + j] = player;
        }
      }
    }
  }
  return currentBoard;
};

우선 첫 취업 전후 및 0년차 햇병아리 시절 퇴사 이후 지원했던 회사의 신입 뽑던 실무자 분들께 사과의 말씀을 전해드리고 싶다. 당시 전념하던 팀 사이드 프로젝트 진행 중 어렸을 적 좋아하던 Blokus란 보드게임을 짬날 때마다 조금씩 구현하고 있었는데, 지금 돌아보니 참 그 누구도 읽고 싶지 않은 코드가 아닐 수가 없다. 이것이 내 서류 100탈의 비결이다.


export const isAvailableArea = (
  board: (string | number)[][], block: number[][], position: number[], player: string,
): boolean => {
  if (position[1] + block[0].length > 20 || position[0] + block.length > 20) {
    throw new Error('range out');
  }
  const x = block[0].length;
  const y = block.length;
  const affectedArea: (number | string)[][] = [];
  const regExpY = new RegExp(`0|${20 - y}`);
  const regExpX = new RegExp(`0|${20 - x}`);
  if (regExpY.test(position[0].toString()) && regExpX.test(position[1].toString())) {
    if (((position[0] === 0
      && ((player === 'a' && position[1] === 0 && block[0][0] === 1)
        || (player === 'd' && position[1] === 20 - x && block[0][block[0].length - 1] === 1)))
      || (position[0] === 20 - y
        && ((player === 'b' && position[1] === 0 && block[block.length - 1][0] === 1)
          || (player === 'c' && position[1] === 20 - x && block[block.length - 1][block[0].length - 1] === 1))))) {
      return true;
    }
    if (((position[0] === 0
      && ((player === 'a' && position[1] === 0 && block[0][0] !== 1)
        || (player === 'd' && position[1] === 20 - x && block[0][block[0].length - 1] !== 1)))
      || (position[0] === 20 - y
        && ((player === 'b' && position[1] === 0 && block[block.length - 1][0] !== 1)
          || (player === 'c' && position[1] === 20 - x && block[block.length - 1][block[0].length - 1] !== 1))))) {
      throw new Error('no block on vertex');
    }
  }
  for (let i = position[0] - 1; i <= position[0] + y; i += 1) {
    for (let j = position[1] - 1; j <= position[1] + x; j += 1) {
      if ((i - position[0] === -1 && position[0] === 0)
        || i === 20) {
        continue;
      }
      if (!affectedArea[i - position[0] + 1]) {
        affectedArea[i - position[0] + 1] = [];
      }
      affectedArea[i - position[0] + 1][j - position[1] + 1] = board[i][j];

      if (i - position[0] >= 0 && j - position[1] >= 0
        && i - position[0] < block.length && j - position[1] < block[0].length
        && block[i - position[0]][j - position[1]] === 1
        && affectedArea[i - position[0] + 1][j - position[1] + 1] !== 0) {
        throw new Error('blocks folded');
      }
      if (i - position[0] >= 0 && j - position[1] >= 0
        && i - position[0] < block.length && j - position[1] < block[0].length
        && block[i - position[0]][j - position[1]] === 1
        && affectedArea[i - position[0] + 1][j - position[1] + 1] === 0) {
        affectedArea[i - position[0] + 1][j - position[1] + 1] = 'n';
      }
    }
  }
  if (!affectedArea[0]) {
    affectedArea.shift();
  }
  let flag = false;
  for (let i = 0; i < affectedArea.length; i += 1) {
    for (let j = 0; j < affectedArea[0].length; j += 1) {
      if (affectedArea[i][j] === 'n'
        && ((i > 0
          && (affectedArea[i - 1][j - 1] === player
            || affectedArea[i - 1][j + 1] === player))
          || (i < affectedArea.length - 1
            && (affectedArea[i + 1][j + 1] === player
              || affectedArea[i + 1][j - 1] === player)))) {
        flag = true;
      }
      if (affectedArea[i][j] === 'n' && (
        (position[0] !== 0 && affectedArea[i - 1][j] === player)
        || affectedArea[i][j - 1] === player
        || (position[0] + y !== 20 && affectedArea[i + 1][j] === player)
        || affectedArea[i][j + 1] === player)) {
        throw new Error('no adjacent block');
      }
    }
  }
  if (!flag) {
    throw new Error('no block connected');
  }
  return true;
};

지금도 이 두 함수만 보더라도 도무지 손댈 엄두가 나지 않는다. 당시에는 저렇게 작성한 게임 로직을 가지고 SvelteKit을 통해 웹 서비스를 구현해보려고 했다. 1년 이상의 프리랜스 경험이 쌓인 지금의 나는 어떻게 달라졌는지 확인해보고자 벨로그에 글을 남기고자 한다.

profile
este / 에스테입니다.

0개의 댓글