바닐라코딩

2주차 과제 틱택토(tick-tack-toe)

단점이없어지고싶은개발자 2021. 7. 31. 11:25
반응형

틱택토는 삼목게임이다.

이런식으로 상대방과 O, X를 번갈아 놓으면서 먼저 한 줄로 놓으면 승리하게 된다.

구현해야 될 것들.

1. 화면을 클릭한다.

2. 클릭된 화면에 O가 나온다

3. 그 다음 클릭에서는 X가 나오고 계속 반복된다.

4. 만약 한 줄로 만들었다면 누가 승리했는지 알 수 있어야한다.

5. 게임이 끝나면 다시하기버튼이 나와서 클릭시 다시 처음부터 게임을 시작하게 한다.

<body>
  <img class="main-logo" src="./images/vc.png" alt="Vanilla Coding Logo" />
  <h1>Tick Tack Toe</h1>

  <form action="" class="start-button">
    <button>게임시작</button>
  </form>

  <div class="check-box">
    <div class="check-o">⭕️ 차례</div>
    <div class="check-x">❌ 차례</div>
  </div>

  <form action="" class="reset-button">
    //<button onclick="location.reload()">다시시작</button> js파일로 옮겨서 이벤트처리로 변경
    <button>다시시작</button>
  </form>

  <section>
    <div class="board">
    </div>
  </section>

  <script src="./app/index.js"></script>
</body>

html에서 특별한 부분은 없다. 저렇게 삼목이 나오는 부분은 table로 해서 만들어 줬는데 자바스크립트에서 DOM으로 작업을 했다. 그리고 승리하는 사람이 나오거나 무승부가 되면은 다시하기가 나와야되서 그 부분을 onClick을 줘서 페이지를 reload하게 해주었다. 더 나은 방법이 없나 고민해보자. 


table {
  border-collapse: collapse;
}

td {
  width: 200px;
  height: 200px;
  border: 1px solid black;
  text-align: center;
}

.start-button {
  text-align: center;
  margin-bottom: 20px;
}

.start-button button {
  width: 75px;
  height: 50px;
}

.reset-button {
  display: none;
}

.check-o,
.check-x {
  display: none;
}

.active {
  font-size: 45px;
  text-align: center;
  margin: 10px;
}

display: none은 아예 안보인다. 그 안에 어떤 효과를 넣어줘도 display: none이기 때문에 화면에 보이지 않는다. 자바스크립트에서 클래스를 지웠다가, 넣었다가 할 수 있는게 있는데 Classlist.add() / Classlist.remove()로 클래스를 지우기도, 다시 추가해주기도 할 수 있다.  두 개의 키워드를 이용해 O, X를 누가 누를지에 대해 화면에 나오게 하는 부분을 구현해주었다.


const startButton = document.querySelector(".start-button");

function hadnleGameStart(event) {
  event.preventDefault();
  //게임버튼을 눌러야 게임이 시작, 그전에 칸을 눌러도 아무런 동작을 하지 않는다.
  if (event.target.textContent === "게임시작") {
    onFirstTurn.classList.remove(first);
    onFirstTurn.classList.add(active);
    startButton.classList.add(first);
    table.addEventListener("click", handleCheck);
  }
}

let myTurn = "⭕️";
let rows = [];
let squares = [];
const first = "check-o";
const second = "check-x";
const active = "active";

const whiteBoard = document.querySelector(".board");
const onFirstTurn = document.querySelector(".check-o");
const onSecondTurn = document.querySelector(".check-x");
const checkBox = document.querySelector(".check-box");
const resetBox = document.querySelector(".reset-button");

const table = document.createElement("table");
const result = document.createElement("div");

//이중반복문의 가장 기초적인부문, rows의 cells을 넣어주고, cells의 td를 넣어준다
//rows 줄, cells 칸
for (let i = 0; i < 3; i++) {
  let cells = [];
  rows.push(cells);
  const tr = document.createElement("tr");
  table.append(tr);
  for (let j = 0; j < 3; j++) {
    const td = document.createElement("td");
    cells.push(td);
    tr.append(td);
  }
}

whiteBoard.append(table);
checkBox.append(result);

const oneRows = rows.flat();
let count = 0;

function finishMessage() {
  result.classList.add(active);
  table.removeEventListener("click", handleCheck);
  onFirstTurn.classList.add(first);
  onSecondTurn.classList.add(second);
  resetBox.classList.remove("reset-button");
  resetBox.classList.add("start-button");
  return;
}
function handleCheck(event) {
  if (event.target.textContent !== "") {
    return;
  }
  event.target.textContent = myTurn;

  for (let i = 0; i < oneRows.length; i++) {
    squares[i] = oneRows[i].textContent;
  }
// for문을 이용해 oneRows의 요소들을 squares라는 변수에 넘겨주고 
// O, X가 몇 번째 칸에 있는지를 알 수 있게한다.
// 또는 map 메소드를 이용해서 
// const squares = oneRows.map((el) => {
//	return el.textContent
// });

  const whoIsWin = calculateWinner(squares);
  if (whoIsWin) {
    result.textContent = `${myTurn}님의 승리!!`;
    finishMessage();
  }
  if (count !== 9) {
    count += 1;
    if (count === 9) {
      result.textContent = `무승부입니다.`;
      finishMessage();
    }
  }
  if (myTurn === "⭕️") {
    myTurn = "❌";
    onFirstTurn.classList.add(first);
    onFirstTurn.classList.toggle(active);
    onSecondTurn.classList.remove(second);
    onSecondTurn.classList.toggle(active);
  } else {
    myTurn = "⭕️";
    onFirstTurn.classList.remove(first);
    onFirstTurn.classList.toggle(active);
    onSecondTurn.classList.add(second);
    onSecondTurn.classList.toggle(active);
  }
}

startButton.addEventListener("click", hadnleGameStart);

resetButton.addEventListener("click", () => {
  window.location.reload();
});

calculatorWinner()함수가 없는데 따로 구현되어 있는 부분을 가지고와서 작업했던거라 그 부분은 뺐다.
이번 과제에서 가장 어려웠던 부분은

1. 클릭 했을 때, 내가 몇 번째 칸을 클릭했는가

2. 클릭이 되었다면 O가 들어가고 그 다음에 X가 나오게하고 번갈아 들어가게 하는 것

3. for문과 map을 이용해서 작업했던 클릭을 했다면 그것을 배열에 넣어서 배열안에 요소들을 알 수 있는 법
3번이 특히나 어려웠다. 그 문제로 삼일은 끙끙 앓았던 것 같다. 배열과 문자열에 대한 공부가 많이 부족해서 생긴 문제였기도 했다. 정답을 찾으려는 것보다 정답을 찾아가는 길을 잘 알아보자 계속 그 문제 때문에 문제를 겪고 있으니.. 누군가에게 물어 볼 때도 문제에 대한 인식과 문제를 찾아가는 방향에 대해서 묻자


코드리뷰
1. event.target - event.currentTarget 에 대한 차이점
- event.target은 부모로부터 이벤트가 위임되어 발생하는 자식의 위치, 내가 클릭한 자식요소를 반환 / 가장 마지막 위치한 최하위의 요소를 반환

- event.currentTarget 이벤트가 부착된 부모의 위치를 반환한다.

 

2. Inlin으로 로직을 작성하는 것보다는 스트립트 로직은 js 파일 내에서 사용하는게 좋다.

 - location.reload()를 html에서 넣어줬던 부분을 빼서, js에서 이벤트로 처리로 변경

 

3. 변수명은 늘 명확하게! 숫자를 사용할 때는 불분명하게 사용되면 매직 넘버라고 불리는 안티 패턴이다! 변수 선언해서 사용!

 - 변수명 변경 및 숫자를 spaceNumber로 변경 

 

4. html태그네임을 사용할 때는 명확하게 지어주자

 - 태그들 앞에 $를 붙여줬음

 

5. 메소드의 사용법을 익히는 방법은 기초 알고리즘을 많이 풀자 ! 

 

6. 무승부를 이용해줄 때 count 를 if문을 중첩해주었는데 그것보다는 count 를 먼저 1을 더해주고 9가 되었을 때 로직이 돌아가게 되고 reutrn 을 이용해 early return을 사용해서 중첩된 if문을 줄이자 ! 

7. reset 을 페이지가 새로고침되게 해주었는데 내가 필요한 부분만 초기화시키는 함수 로직을 만들어서 사용해보자. (8월 2주 수정할 예정)

반응형

'바닐라코딩' 카테고리의 다른 글

3주차 과제 카드퀴즈만들기  (0) 2021.08.11
3주차 강의 ES2015 & beyond  (0) 2021.08.07
2주차 강의  (0) 2021.07.25
1주 - 첫 과제  (0) 2021.07.23
1주차 JavaScript Review  (0) 2021.07.20