javascript - 지뢰찾기

김동하·2020년 10월 15일
0

1번

css

start button

background, color, box-shaow, text-shadow의 조합으로 만든다. box-shahow는 insetdmf 4번 줘서 입체감을 준다.

board

마찬가지로 background-color, border,box-shadow로 틀을 만든다. before,after로 귀퉁이에 입체감을 주는데 box-shadow를 줄 때 boardSize를 계산해서 줘야한다.

tile

타일도 background-color, box-shadow을 준다.

js

세팅

처음에 변수를 정하는 것들이 어렵다. 일단 size(width)가 있어야 한다. size * size는 전체 board의 크기니까. 그리고 tile 하나의 사이즈도 있어야 하고(tileSize) tiles랑 boardSize는 그냥 선언만 해둔다.

for문으로 돌리면 이제 setProperty를 해줘야 한다. tiles는 tile 전체고 boradSize는 tiles.length의 sqrt로 정한다. board의 width는 boardSize * tileSize다. 이제 setProperty로 tileSize, boardSize를 준다. document.documentElement.style.setProperty로 해주면 됨!

tile 뿌리기

x,y 변수를 선언하고 forEach로 tiles를 뿌린다. setAttribute로 x,y정해주고 bomb를 만들어야 하는데 random_boolean으로 bomb 변수보다 random()이 작으면 true가 나온다. 이제 true의 경우, 즉 bomb을 심어줘야 한다. numbers랑 bombs 배열을 만들고 bombs에 x,y좌표를 추가한다. 그럼 bombs 배열엔 폭탄이 있는 좌표들이 str으로 담긴다. 즉 ["0,0", "0,0"] 이런 식! 이제 폭탄 주위에 number를 넣어줘야 한다. x,y가 폭탄이 있는 곳이니까 주변 8칸은 숫자가 표시되어야 한다.

주변 8칸 로직

북서 x > 0 && y > 0 일 때 y > 0 일 때 북동 y > 0 && x < boardSize - 1 일 때

x > 0 일 때 폭탄 위치 {x, y} x < boardSize - 1 일 때

남서 x > 0 && y < boardSize - 1 일 때 y < boardSize - 1 남동 x < boardSize - 1 && y < boardSize - 1 일 때

위의 경우일 때 각각 numbers에 추가한다. 그럼 bombs를 기준으로 numbers 배열에 좌표가 담긴다. 이제 이걸 forEach가 한 칸 한 칸 돌면서 검사해야 하니까 x++를 해준다. 만약 x가 boardSize보다 같거나 크다는 것은 한 줄을 다 채웠다는 뜻이니까 x=0, y+1를 해준다.

numbers 조지기

이제 numbers에 forEach를 한다. coord라는 변수 만들어서 배열화시킨다. 그리고 coord[0], coord[1]를 이용해서 tile을 새롭게 정의하는데 그렇데 되면 coord는 ["x", "y"] tile은 그 해당 div다. 여기서 coord[0]은 string이니까 숫자로 바꾼다. 이제 겹치는 번호를 더해줘야 하는데 data-number 변수를 만들어서 getAttribute한다. 만약 data-number가 없으면 0이고 set을 해줘서 data-number+1로 중첩한다. type을 신경쓰자 data-number는 numbers, bombs 모두 뿌려진다.

click 과 check

두 이벤트 리스너는 처음 tiles forEach 안에 있어야 함. 오른쪽 누르면 flag, 왼쪽 누르면 click으로 함수 실행한다. 먼저 click은 폭탄이 있으면 폭탄, 없으면 주변 폭탄 숫자가 나타난다. 만약 game over면 리턴, checked or flagged면 리턴이다.

클릭하면 이렇게 tile정보가 있다. coordinate 변수가 필요하다. date-tile을 get한다. 즉, 좌표를 겟한다. 이제 우리에겐 numbers, bombs 두 좌표 배열이 있는데 만약 지금 클릭한 타일의 coordinate가 bombs에 있다면 게임 끝이다. 아니라면 두 가지 경우가 있는데 tile 주변에 폭탄이 있는 경우와 없는 경우. 그럼 폭탄이 없는 경우, 즉 data-number가 null이 아닌 경우 이제 재귀로 칸을 오픈해야 한다. tile--checke 클래스 추가하고 innerHTML와 style 조지기. setTimeout으로 vitctory 함수 실행하고 return한다.

폭탄이 없는 경우 재귀로 오픈해야 하니까 check()에 tile과 coordinate를 인자로 준다. 이제 check 함수에서 인자로 받은 coordinate를 coord로 만들어준다. coordinate는 "2,0" coord는 ["2"],["0"] 그리고 coord로 x,y좌표를 잡고 아까 numbers를 준것처럼 8개 방을 다 오픈해야 한다. setTimeout을 열어주고 새로운 타겟이 필요하다. 아까처럼 8개의 경우에 각 경우에 해당하는 변수를 만든다. 예를 들어 x > 0보다 클 때는 왼쪽에 있는 tile이니까

  if (x > 0) {
            let targetW = document.querySelectorAll(`[data-tile="${x-1},${y}"]`)[0]
            clickTile(targetW, `${x-1},${y}`);
        }

그리고 click()에 새로운 타겟과 새로운 좌표를 보낸다.

flag

flag 함수에 tile을 인자로 준다. if로 checked인지 판별하면 된다.

end game

폭탄을 클릭하면 end game 함수로 보낸다 end game은 tiles를 forEach해서 새로운 coordinate를 겟하는데 bombs 배열에 그 좌표가 있으면 tile-bomb과 checked를 add 한다.

victory

똑같이 tiles forEach하고 coordinate를 새롭게 get하는데 if로 checked랑 bomb이 아닌지 판별. 아니라면 win = false. win true면 gaveover도 true

restart

다 초기화하고 forEach로 remove한다.

2번

css

일단 class가 valid, checked, bomb이 있는데 border, border-color로 입체감을 준다. box-sizing이 border-box.

js

세팅

일단 width를 변수로 만들고 for문으로 square(=tile)을 만든다. 각 square에 setAttribute로 id를 할당한다. 이제 bombsArray랑 emptyArray 를 만든면 된다. 그리고 각각 bombs amount 만큼 bomb과 그것을 뺀 나머지 만큼 valid로 채운다. 그리고 그 둘을 합치고 sort로 섞으면 완성. 이제 for문 안에서 각 square에 class list를 추가해야 하는데 shuffledArray에 담긴 스트링("valid", "bombs")를 각 추가해주면 된다. 폭탄 나누기와 지정을 한꺼번에 다 해버림..그리고 squares에 담는다.

for문 안에서 square은 이렇게 출력되고

squares 는 이렇게 된다. 이제 grid에 달고 왼쪽 오른쪽 클릭 이벤트 하면 되는데 그건 나중에 하고 일단 for문 탈출. number를 부여하는 for문을 만든다. total을 선언하고 left edge, right edge를 정하는데 left edge는 i % width가 0인 것, (x=0일 때) 그리고 right edge는 i % width === width - 1 (x=width-1) 그리고 valid인 경우에 주변 폭탄 갯수를 세어야 하니까 8개의 경우를 구한다.

주위 8개 구하기 로직


i > 0 && !isLeftEdge && squares[i - 1].classList.contains("bomb")


i > 10 && squares[i - width].classList.contains("bomb")


i < 98 && !isRightEdge && squares[i + 1].classList.contains("bomb")


i < 89 && squares[i + width].classList.contains("bomb")

북서
i > 11 && !isLeftEdge && squares[i - 1 - width].classList.contains("bomb")

북동
i > 9 && !isRightEdge && squares[i + 1 - width].classList.contains("bomb")

남동
i < 88 && !isRightEdge && squares[i + 1 + width].classList.contains("bomb")

남서
i < 90 && !isLeftEdge && squares[i - 1 + width].classList.contains("bomb")

8가지 경우에 각각 total을 해준다. 그리고 각 square에 set으로 data를 클래스로 total을 준다. 정말 간단하다...

click

click과 addflag 둘 다 square를 받는다. click은 square의 id가 필요하다. if로 일단 game over거나 checked, flag면 리턴 그리고 bomb이면 게임 오버. 그게 아니라면 getAttri bute해서 total을 구하고 total이 0이 아닐 때 checked하고 색깔을 넣어준다. 여기서 중요한 건 return으로 if문 종료. 그리고 check함수에 square랑 id를 보낸다.

check

left edge, right edge를 구하고 주위 8개 칸의 위치 정보를 가져온다. 순차적으로 파파팍 열려야 하니까 setTimeout! currentId와 left/right edge를 이용해서 new Id와 new square를 구하는데 여기서 new square는 getElementById에 new Id로 구해서 다시 click 함수에 보낸다. 재귀적으로!

game over와 win

game over는 squares를 돌면서 bomb 을 포함하고 있는지 확인하면 된다. 클레스 추가하고 삭제하는 게 살짝 헷갈림. wind은 matches라는 변수를 만들어서 for 문 돌면서 flag랑 bomb이 동일한가 찾고 만약 두개가 같으면 게임 종료.

profile
프론트엔드 개발

0개의 댓글