[HTML mini Project] 오목 - 2

DooDuZ·2022년 12월 22일
0
post-thumbnail

요상한 오목을 만들고 2차원 배열도 써볼겸 기존 단점 보완도 할 겸 시작한 오목 프로젝트 씨즌 투,,. 결론만 먼저 말하면 사실상 실패에 가까웠는데, 시간부터가 배열을 쓰지 않고 구현한 버전은 2시간 만에 만든 반면 이놈은 거의 4시간 가까이 걸렸다. 게다가 세부 룰 구현을 해보겠다는 목표는 몇 번의 테스트 후 포기해버렸다...

여튼 이번 오목의 출발점은

  1. 배열에 모든 데이터를 담는다.
  2. 그 데이터를 그대로 읽어 HTML에 출력한다.
 const board = document.querySelector('#board');
 	
 let gameboard = [];
 
 let turn = 0;
 let count = 0;
 
 function start_game(){
	gameboard = [];
	turn = 0;
	for(let y = 19 ; y>=1 ; y--){
		let board_cols = [];
		for(let x = 1; x<=19; x++){	
			board_cols.push('');
		}
		gameboard.push(board_cols);
	}
	
	let storage = ''; 
	
	for(let i = 0 ; i<19 ; i++){
		
		storage += '<div class="line">';
		
		for(let j = 0 ; j<19 ; j++){
			storage += '<div class=cell onclick=click_btn('+i+','+j+')>'+gameboard[i][j]+'</div>';		
		}
		storage += '</div>';
	}
	board.innerHTML = storage;	
}

보드를 그린 방법부터 사뭇 다르다. 먼저 배열 하나를 선언한 뒤, 모든 엘리먼트를 공백으로 설정해서 cols배열에 넣어주고 그걸 다시 gameboard에 push해서 그대로 HTML에 값을 뿌렸다.

19*19 보드에서 내가 보는 값 = 해당 좌표의 배열 내부 값

으로 만들고 싶었기 때문이다.

function check_win(x,y){
	let win_count = 0;
	for(let i = 0 ; i<18 ; i++){
		if(gameboard[i][y]!=''&&gameboard[i][y]==gameboard[i+1][y]){
			win_count++;
			if(win_count==4){
				return true;
			}
		}else{
			win_count = 0;
		}
	}
    // 더 
    // 많은
    // 코드
    win_count = 0;
	for(let i = -4 ; i < 4 ; i++){
		if(x+i<0 || y+i<0 || x+i>17 || y+i>17){
			continue;
		}else if(gameboard[x+i][y+i]!='' && gameboard[x+i][y+i]==gameboard[x+i+1][y+i+1]){
			win_count++
			if(win_count==4){
				return true;
			}
		}else{
			win_count = 0;
		}
	}
    // 또 다시
    // 코드
}

승리 조건도 연산 횟수가 굉장히 줄어들었다. 다만 대각선 조건을 구현하는데 있어서 인덱스가 계속 배열 길이를 넘어가는 문제가 생겨서 해당 부분을 구현하는데 애를 좀 먹었다. 2차원 배열의 대각선 좌표 표현은 내가 지금까지도 다소 어려워하는 부분중 하나다.

if( x-y == data ){ ... }
if( x+y == data ){ ... }

지금은 이렇게 판단하기도 하는데 활용까지 가는 길은 여전히 요원하다.

여하튼 다시 오목으로 돌아가면 저 대각선 외에도 문제가 생기는데

function click_btn(x,y){	
	if(turn==2){ alert('게임을 다시 시작해주세요.'); return; }
	
	if(gameboard[x][y]=='<img src="흑돌.png">' || gameboard[x][y]=='<img src="백돌.png">'){	alert('이미 둔 자리입니다.'); return; }
	
	if(turn==0){ gameboard[x][y] = '<img src="흑돌.png">'; turn++; }
    else if(turn==1){ gameboard[x][y] = '<img src="백돌.png">'; turn--; }
	
	let storage = ''; 
	for(let i = 0 ; i<19 ; i++){
		storage += '<div class="line">';
		for(let j = 0 ; j<19 ; j++){
			storage += '<div class=cell onclick=click_btn('+i+','+j+')>'+gameboard[i][j]+'</div>';
		}
		storage += '</div>';
	}
	board.innerHTML = storage;
	
	if(check_win(x,y)){
		if(turn==1){ alert('흑돌 승리'); turn=2; return; }
        else if(turn==0){ alert('백돌 승리'); turn=2; return; }
	}
    
	count++;
    
	if(count==361){
		turn=2;
		alert('무승부');
	}
}

중복검사 부분은 그냥 공백이 아니면 리턴 하는 식으로 훨씬 짧게 짤 수 있었을 것이고...
배열을 사용한 이유가 연산을 적게하기 위함이었는데, 돌을 하나 둘 때마다 361번씩 게임판을 다시 그려서 HTML에 입력하는, 또다시 배보다 배꼽이 큰 상황이 나와버린 것이다. 가볍게 만들자는 마음으로 시작했는데 클릭마다 화면 전체 렌더링을(요즘 리액트 공부한다고 이런 말도 다 쓴다...) 다시하는 상황이니 참 미숙했다고 하겠다. 배열값을 바꾸면서 해당 셀에 innerHTML 한 번만 했으면 되지 않았을까... 저때는 2차원 배열에 심취해서 배열값을 그대로 출력하는 데에만 정신이 팔려있던 것 같다.

그리고 한가지 문제가 더 있다면 렌주룰 구현에 대한 것이었는데, 생각보다 3,3이나 4,4에 대한 룰 구현이 쉽지 않았다. 한쪽이 막혀있는 상황이나 5개의 빈 칸을 양쪽에서 미리 막고있는 상황 등등 그냥 돌만 세면 끝이라고 생각했던 게 여러가지 케이스를 적용하면서 자꾸만 반례 케이스가 튀어나왔다. 결국 저때 당시엔 세부 룰 구현을 포기했었는데, 지금 하고있는 팀 프로젝트가 끝나면 개인프로젝트로 소켓을 이용해 서로 다른 PC에서 사람끼리 두는 오목을 구현해볼까 한다.

여하튼... 오늘 적는 코딩 왕초보의 오목 만들기는 여기까지!

profile
뇌세포에 CPR중

0개의 댓글