본문 바로가기
Web/Frontend

[리액트] 지뢰찾기 만들기

by r4bb1t 2022. 7. 31.
반응형

우선 맵을 만들어봅시다.

const sz = 9;
const [mp, setMp] = useState(Array.from({ length: sz }, () => Array.from({ length: sz }, () => 0)));
const [ms, setMs] = useState(Array.from({ length: sz }, () => Array.from({ length: sz }, () => 0)));

지뢰가 있는 위치를 설정할 mp변수와 근처 지뢰의 개수를 설정할 ms변수를 만들었습니다.

const setMap = () => {
  const initMp = Array.from(mp);
  initMp[0][2] = 1;
  initMp[2][1] = 1;
  initMp[2][2] = 1;
  initMp[1][0] = 1;
  initMp[1][1] = 1;
  initMp[3][5] = 1;
  initMp[7][6] = 1;
  initMp[1][9] = 1;
  setMp(initMp);
};

const setMineswiper = () => {
  const dir = [
    [1, 0],
    [0, 1],
    [-1, 0],
    [0, -1],
    [1, -1],
    [1, 1],
    [-1, 1],
    [-1, -1],
  ];
  const initMs = Array.from(ms);
  for (let i = 0; i < sz; i++) {
    for (let j = 0; j < sz; j++) {
      let f = 0;
      for (let k = 0; k < 8; k++) {
        if (i + dir[k][0] < 0 || i + dir[k][0] >= sz || j + dir[k][1] < 0 || j + dir[k][1] >= sz) continue;
        if (mp[i + dir[k][0]][j + dir[k][1]]) f++;
      }
      initMs[i][j] = f;
    }
  }
  setMs(initMs);
};

useEffect(() => {
  setMap();
  setMineswiper();
}, []);

일단 지정된 위치에 지뢰를 넣고, 각 칸마다 근처 지뢰 수를 계산했습니다.

const setMap = () => {
  const initMp = Array.from(mp);
  for (let i = 0; i < sz; i++) {
    let x = Math.floor(Math.random() * sz);
    let y = Math.floor(Math.random() * sz);
    while (initMp[x][y] !== 1) {
      x = Math.floor(Math.random() * sz);
      y = Math.floor(Math.random() * sz);
      initMp[x][y] = 1;
    }
  }
  setMp(initMp);
};

랜덤한 위치에 sz변수만큼의 지뢰를 깔아놓습니다. 맨 가운데 칸은 무조건 비워둡니다.

const setMineswiper = () => {
  const initMs = Array.from(ms);
  for (let i = 0; i < sz; i++) {
    for (let j = 0; j < sz; j++) {
      let f = 0;
      for (let k = 0; k < 8; k++) {
        if (i + dir[k][0] < 0 || i + dir[k][0] >= sz || j + dir[k][1] < 0 || j + dir[k][1] >= sz) continue;
        if (mp[i + dir[k][0]][j + dir[k][1]] === 1) {
          f++;
        }
      }
      initMs[i][j] = f;
    }
  }
  setMs(initMs);
};

ms 변수에 각 칸마다 주변에 있는 지뢰의 수를 체크하여 넣습니다.

const open = (xx: number, yy: number) => {
  const a = [[xx, yy]];
  const initMo = Array.from(mo);
  if (mo[a[0][0]][a[0][1]]) return;
  initMo[a[0][0]][a[0][1]] = true;

  if (mp[a[0][0]][a[0][1]] === 0 && ms[a[0][0]][a[0][1]] === 0)
    while (a.length > 0) {
      let x = a[0][0],
        y = a[0][1];
      a.splice(0, 1);
      for (let k = 0; k < 4; k++) {
        if (x + dir[k][0] < 0 || x + dir[k][0] >= sz || y + dir[k][1] < 0 || y + dir[k][1] >= sz) continue;
        if (initMo[x + dir[k][0]][y + dir[k][1]]) continue;

        initMo[x + dir[k][0]][y + dir[k][1]] = true;
        if (ms[x + dir[k][0]][y + dir[k][1]] === 0) a.push([x + dir[k][0], y + dir[k][1]]);
      }
    }
  setMo(initMo);
};

주변에 지뢰가 없을 경우 주변 4방향 칸을 열고, 열린 칸 중 또 주변에 지뢰가 없는 칸이 있다면 a에 push하여 돌립니다.

이제 예쁘게 디자인을 입혀 봅니다.

그럴싸하죠?

반응형

댓글