토이프로젝트: 보드게임 코드네임 정답지 랜덤 출력기

사월·2023년 4월 28일
0

토이 프로젝트

목록 보기
1/2

Why?

이번 주말, 오랜만에 대학시절 동아리의 동기선후배들과 함께, 아직 해당 대학에 재학중이고 동아리 회원인 아이들을 만나러 가기로 하였다. 그러면서 해당 모임을 주최한 동기가 평소 보드게임을 좋아하던 나에게 요청을 한 것이다. 동아리의 졸업 멤버와 현직 멤버가 팀을 나눠서 할 수 있는 간단한 보드게임이 없냐고.

뭐 요청만 하면 나한테서 적당한 보드게임이 뚝딱 나오냐고도, 그건 보드게임보단 레크레이션을 찾아야 하지 않냐고도 하고 싶었지만 마침 생각나는 보드게임이 하필 있었다. 그것이 코드네임. 두 팀으로 나뉘어 한 명씩 문제를 내는 사람을 선발해 앞쪽에 앉히면 그 사람이 답지를 보고 나머지 사람들이 자기 팀의 색깔에 알맞는 코드네임을 댈 수 있도록 힌트를 주는 게임이다.

그런데 난 안 가지고 있었다. 머글들은 보드게임 카페를 차리려 하는 거냐는 질문을 던지는 책장을 가지고 있지만, 같은 보드게이머들 사이에서는 별로 안 가지고 있다고 자신할법한 정도밖엔 안돼서, 생각나는 게임을 바로 대령하기엔 세상에 보드게임은 많고 재밌는 게임도 많고 내 돈은 제한된 것이다. 안그래도 코드네임을 구매할 생각은 하고 있었지만, 이미 시간은 목요일 저녁. 남은 시일은 대충 하루. 그리고 나는 코드네임을 만들어 쓰기로 결심한다.

사실 코드네임의 구성물은 간단하다. 단어 카드와 그 위를 덮을 답을 체크하는 카드는 그냥 화이트보드에 단어를 같이 채우고 파란색 혹은 빨간색 보드마커 펜으로 동그라미를 쳐주는 식이면 될 것 같았다. 문제는 답지카드. 그런데 어... 이거 코딩으로 만들 수 있을 것 같은데? 그래서 만들었습니다.

How?

HTML+CSS+javascript

디자인은 별도의 스케치 없이 대충 손 가는대로 css를 쳤다. 타겟 사용자는 이번 주말 나와 함께 모이는 동아리 사람들이고 만일 디자인으로 태클을 걸면 바로 응징할것이다.

코드도 일단 무작정 쳤다. 다음처럼 단 두개의 함수만을 가진 동작하는 코드가 완성되었다.

//주요 node들을 불러옵니다.
...

//해당 프로그램의 핵심인 codenames의 데이터입니다.
const spy = -1;
const redAgent = 1;
const blueAgent = 2;
const citizen = 0;
  
const array = [
  ...pushAgent(spy, 1),
  ...pushAgent(doubleAgent, 1),
  ...pushAgent(redAgent, 7),
  ...pushAgent(blueAgent, 7),
  ...pushAgent(citizen, tableList.length - 16),
];
  
//shuffle버튼의 클릭을 감지합니다.
shuffleBtn.addEventListener("click", shuffle);

function shuffle() {
  const doubleAgent = Math.floor(Math.random() * 2) + 1;
  if (doubleAgent === redAgent) {
    container.classList.remove("blue");
    container.classList.add("red");
    header.classList.remove("blue");
    header.classList.add("red");
  } else {
    container.classList.remove("red");
    container.classList.add("blue");
    header.classList.remove("red");
    header.classList.add("blue");
  }

  for (let index = array.length - 1; index > 0; index--) {
    const randomPosition = Math.floor(Math.random() * (index + 1));
    const temporary = array[index];
    array[index] = array[randomPosition];
    array[randomPosition] = temporary;
  }

  for (let i = 0; i < tableList.length; i++) {
    tableList.item(i).classList.remove("spy", "red", "blue");
    if (array[i] === spy) {
      tableList.item(i).classList.add("spy");
    } else if (array[i] === redAgent) {
      tableList.item(i).classList.add("red");
    } else if (array[i] === blueAgent) {
      tableList.item(i).classList.add("blue");
    }
  }
}

//피셔-예이츠 셔플 방법을 이용해 array를 랜덤 셔플합니다.
function pushAgent(agent, number) {
  ...
}

그런데... 너무 지저분해보였다. 제대로 된 모듈화를 살펴본 적도 없지만 무언가 나도 모듈 식으로 코드를 분할하고 싶었다.

//주요 node들을 불러옵니다.
...

//해당 프로그램의 핵심인 codenames의 데이터를 저장, 수정하는 객체입니다.
const codenames = {
  size: tableList.length,
  team: {
    spy: -1,
    redAgent: 1,
    blueAgent: 2,
    citizen: 0,
    doubleAgent: {
      value: 0,
      shuffle() {
        codenames.team.doubleAgent.value = randomOneTwo();
      },
    },
  },
  array: {
    value: [],
    setting: () => {
      codenames.array.value = [
        ...pushArr(codenames.team.spy, 1),
        ...pushArr(codenames.team.doubleAgent.value, 1),
        ...pushArr(codenames.team.redAgent, 7),
        ...pushArr(codenames.team.blueAgent, 7),
        ...pushArr(codenames.team.citizen, codenames.size - 16),
      ];
    },
    shuffle: () => {
      codenames.array.setting();
      codenames.array.value = arrayShuffle(codenames.array.value);
      return codenames.array.value;
    },
  },
  shuffle: () => {
    codenames.team.doubleAgent.shuffle();
    return codenames.array.shuffle();
  },
};

//shuffle버튼의 클릭을 감지합니다.
shuffleBtn.addEventListener("click", clickShuffle);

function clickShuffle() {
  paintTable(codenames.shuffle());
  sirenFirstTurn(codenames.team.doubleAgent.value);
}

//정렬 내에 agent를 number만큼 반복 삽입합니다.
function pushArr(agent, number) {
  ...
}

//1 또는 2를 랜덤 출력합니다.
function randomOneTwo() {
  ...
}

//피셔-예이츠 셔플 방법을 이용해 array를 랜덤 셔플합니다.
function arrayShuffle(array) {
  ...
}

//whoIs(doubleAgent)의 값이 redAgent/blueAgent인지 확인 후 화면에 강조 표시를 띄웁니다.
function sirenFirstTurn(whoIs) {
  ...
}

//화면의 table을 array내 값에 따라 색칠합니다.
function paintTable(array) {
  ...
}

result

배포: http://april0ys.dothome.co.kr/boardgame-codenames/
깃허브: https://github.com/april35592/shuffle_codenames_answer/tree/main

아무튼, 어느쪽이든 잘 동작한다.
성공적인 모임이 되길 기원해달라.

After?

!!clean code
!모듈화

사실 좋은 코드와 나쁜 코드에 대해서 전혀 모른다. 클린 코드와 좋은 모듈화에 대해 좀더 공부해볼 계기가 된 것 같다.

사실 나는 며칠전까지 전혀 다른 직종에 근무하고 있었고(3월 20일 퇴사했다.) 코딩에 대해선 몇년 전 취미로 가볍게 한 게 다였기때문에 당연한 것일 수 있지만, 개발자를 내 업으로 삼기로 결심하고 도전중인 이상 이전처럼 게으르게 공부할 수만도 없다.

덧으로, 보드게임 코드네임은 따로 주문 넣어놓았다. 게임을 구매하는 것은 게임 제작진들에 대한 리스펙이기도 하다고 생각하기 때문에.

때문에 혹시나 위에 기술한 방법으로 코드네임을 플레이하시게 된 분이 계신다면 하나쯤 구매 또한 고려해달라 하고싶다.

0개의 댓글