[프로젝트] 네모로직(노노그램) 게임 구현하기 04. 힌트 세팅 로직 구현

·2023년 3월 13일

프로젝트

목록 보기
3/9
post-thumbnail

힌트 세팅 기능 구현하기

네모로직에서 숫자로 보드 내 색칠해야할 칸을 알려주는 힌트 부분을 구현하려한다.

사용자의 문제풀이 화면에서는 힌트와 빈 테이블이 보여지고 힌트를 따라 셀을 채워가는 방식이지만 문제를 낼 때마다 힌트를 수기로 세어서 일일이 넣는 것이 굉장히 비효율적이기 때문에 보드판에 그림을 그린 후 배열 내 데이터를 바탕으로 힌트를 자동으로 만들어주도록 할 것이다. (이 후 기능이 확장된다면 사용자가 문제를 출제할 수도 있을 것이다.)


힌트(clue)의 레이아웃과 변수 명은 위 처럼 구성 된다.

1. clueContainer, clueArrBox 생성

//1) 힌트 컨테이너 만들기
const rowClueContainer = createClueContainer("row", ROWS);
const colClueContainer = createClueContainer("col", COLS);

//2) DOM요소에 선택자와 클래스로 활용 될 string type의 matrixName과 matrix 개수를 매개변수로 받는 함수 구현
function createClueContainer(matrixName, size) {
  
  //3) clue container element 선택
  const clueContainer = document.getElementById(`${matrixName}-clue`);
  
  //4) row 혹은 col의 개수에 따라 clue container element 안에 들어갈 clue box 생성
  for (let i = 0; i < size; i++) {
    const clueArrBox = document.createElement("div");
    clueArrBox.setAttribute("class", `${matrixName}${i} clue-container`);
    clueContainer.appendChild(clueArrBox);
  
  //5) clue box들이 속한 clueContainer 요소를 리턴
  return clueContainer;
}

힌트 컨테이너 dom요소를 만들 때 로우/칼럼의 개수, 선택할 DOM 요소 외 기능은 동일하기 때문에 함수로 구현하였다.

2. 셀 클릭 시 힌트 세팅


만일 붉은 부분의 셀을 클릭했다고 가정한다면, 노란색 부분의 로우와 칼럼 배열을 순회하여 힌트를 업데이트 하는 방식으로 구현하였다.

//클릭 시 셀배열 체크
function checkCellArr(e) {
   //클릭한 셀의 위치 값 찾기
  const thisRow = parseInt(e.target.getAttribute("data-row"));
  const thisCol = parseInt(e.target.getAttribute("data-col"));
  ...
  //힌트 세팅 (문제출제용)
  clueSetting(thisRow, thisCol);
}

체크 된 셀에 따라 힌트의 숫자가 세팅되어야하기 때문에 이전에 작성했었던 checkCellArr() 함수가 실행될 때 clueSetting() 함수를 실행시킨다.

위에서 말했던 것 처럼 클릭한 셀의 로우와 칼럼 배열을 순회하여야 하므로 thisRow, thisCol을 인자로 받는clueSetting()함수는 다음과 같이 구현된다.

//clue 세팅
function clueSetting(thisRow, thisCol) {
  
  //1) 클릭한 셀이 속한 로우/칼럼을 순회하여 변경된 clueArr 받기
  const rowClueArr = countTasks("row", COLS, thisRow);
  const colClueArr = countTasks("col", ROWS, thisCol);
  
}

clueSetting이 실행되면 클릭한 로우 인덱스 값클릭한 칼럼 인덱스 값을 인자로 받아 clueArr를 리턴 받는 countTasks()함수가 실행된다.

3. countTasks()함수 - 클릭 된 셀을 기준으로 로우 혹은 칼럼을 순회하여 clueArr 생성

1) 네모로직의 clue 특징

네모로직 힌트는 연속으로 칠해진 셀의 숫자가 작성된다는 것이 특징이다. 칠해진 셀(true)과 셀 사이에 빈 셀(false)이 있다면 그 다음의 칠해진 셀의 숫자는 다음 칸에 작성된다.

clueArr를 만들 때 위의 특징을 유념하여 알고리즘을 구현해야 한다.

2) 로직 구현

이미지 처럼 클릭한 셀의 로우를 인덱스 0 - 9를 순회하며 true를 만났을 때는 taskCount가 증가하고 false를 만났을 때는 이전까지 증가시켰던 taskCount를 clueArr에 넣는 방식으로 구현했다.

//1) 이 카운팅이 row를 기준으로 카운팅하는 것인지 col을 기준으로 카운팅하는 것인지 정하기 위해 matrixName, size, thisCell을 인자로 받는다.
function countTasks(matrixName, size, thisCell) {
  let clueArr = [];
  let taskCount = 0;

  //2) row 혹은 col의 개수 만큼 셀 순회
  for (let i = 0; i < size; i++) {
    
    //3) row열을 순회하는거라면 cells[thisCell][i]형태로 순회
    if (matrixName === "row" && cells[thisCell][i] === true){
      
      	//셀이 true인 경우 카운트가 1씩 증가
      	taskCount += 1;
      
      	// *만일 해당 셀이 마지막 인덱스일 경우 지금까지 카운트했던 task를 clueArr에 push한다.
      	if (i === size - 1) {
        clueArr.push(taskCount);
      	}
   	} else {
      	//true가 아니라면 지금까지 카운트 된 셀은 clueArr에 담고 카운트 초기화
        taskCount && clueArr.push(taskCount);
        taskCount = 0;
    }
  }

  //4) clueArr 리턴
  return clueArr;
}


칼럼 힌트도 세팅하기 위해 matrixName"col"이라면 cell[i][thisCell] 형태로 순회하는 조건도 넣어주었다.

function countTasks(matrixName, size, thisCell) {
  let clueArr = [];
  let taskCount = 0;

  for (let i = 0; i < size; i++) {
    if (matrixName === "row" && cells[thisCell][i] === true) {
      taskCount += 1;
      if (i === size - 1) {
        clueArr.push(taskCount);
      }
    } else if (matrixName === "col" && cells[i][thisCell] === true) {
      taskCount += 1;
      if (i === size - 1) {
        clueArr.push(taskCount);
      }
    } else {
      taskCount && clueArr.push(taskCount);
      taskCount = 0;
    }
  }

  return clueArr;
}

4. clueArr 페인팅

function clueSetting(thisRow, thisCol) {
  
  const rowClueArr = countTasks("row", COLS, thisRow);
  const colClueArr = countTasks("col", ROWS, thisCol);

  //1) querySelector로 해당 로우/칼럼 컨테이너 dom요소를 선택해서 페인팅하기
  const rowClueContainer = document.querySelector(`#row-clue .row${thisRow}`);
  rowClueContainer.innerHTML = rowClueArr
    .map((count) => `<p>${count}</p>`)
    .join("");

  const colClueContainer = document.querySelector(`#col-clue .col${thisCol}`);
  colClueContainer.innerHTML = colClueArr
    .map((count) => `<p>${count}</p>`)
    .join("");
}

위에서 생성했던 clueSetting() 함수에 rowClueArrcolClueArr를 활용하여 map매서드로 화면에 페인팅한다.

뒤에 .join("")을 넣은 이유는 배열 형태로 html요소가 추가되었기 대문에 ','가 표기되어 join으로 콤마를 없앴다.

확인

=>
초반에는 막막했지만 이 로직을 나 혼자 구현했다니! 너무 뿌듯하다..
로직을 구현하는 것 자체는 오래걸리지 않았지만 설명하려고 하니 쉽지 않구만..

0개의 댓글