오목에서 금수체크하는 알고리즘 ( 불가능한가? )
글쓴이: nayana / 작성시간: 일, 2004/09/12 - 4:48오후
오목에서 삼삼(3*3), 3*4 및 체크를 할려고 합니다.
생각보다 알고리즘이 까다롭네요^^
int black_count = 0; int white_count = 0; for ( cell_x = 0; cell_x < 15; ++cell_x ) { for ( cell_y = 0; cell_y < 15; ++cell_y ) { if ( xCOmok::OmokPan[ cell_x ][ cell_y ] == xCOmok::BlackStone ) { //---------------------------------------------------------------------- // - 대각선을 검사한다.( 검은돌 ) if( xCOmok::OmokPan[ cell_x + 1 ][ cell_y + 1 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x + 2 ][ cell_y + 2 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x - 1 ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x + 3 ][ cell_y + 3 ] == 0 ) ++black_count; if( xCOmok::OmokPan[ cell_x - 1 ][ cell_y + 1 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x - 2 ][ cell_y + 2 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x + 1 ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x - 3 ][ cell_y + 3 ] == 0 ) ++black_count; //========================================================================= //------------------------------------------------------------------------- // - 가로를 검사한다.( 검은돌 ) if( xCOmok::OmokPan[ cell_x ][ cell_y + 1 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x ][ cell_y + 2 ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x ][ cell_y + 3 ] == 0 ) ++black_count; //=========================================================================== //--------------------------------------------------------------------------- // - 세로를 검사한다.( 검은돌 ) if( xCOmok::OmokPan[ cell_x + 1][ cell_y ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x + 2][ cell_y ] == xCOmok::BlackStone && xCOmok::OmokPan[ cell_x - 1][ cell_y ] == 0 && xCOmok::OmokPan[ cell_x + 3][ cell_y ] == 0 ) ++black_count; //=========================================================================== if ( black_count >= 2 ) { printf( "black_count : %d\n", black_count ); xCOmok::OmokPan[ stone_height ][ stone_width ] = 0; return xCOmok::BlackStone; } } else if ( xCOmok::OmokPan[ cell_x ][ cell_y ] == xCOmok::WhiteStone ) { //---------------------------------------------------------------------- // - 대각선을 검사한다.( 흰돌 ) if( xCOmok::OmokPan[ cell_x + 1 ][ cell_y + 1 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x + 2 ][ cell_y + 2 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x - 1 ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x + 3 ][ cell_y + 3 ] == 0 ) ++white_count; if( xCOmok::OmokPan[ cell_x - 1 ][ cell_y + 1 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x - 2 ][ cell_y + 2 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x + 1 ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x - 3 ][ cell_y + 3 ] == 0 ) ++white_count; //========================================================================= //------------------------------------------------------------------------- // - 가로를 검사한다.( 흰돌 ) if( xCOmok::OmokPan[ cell_x ][ cell_y + 1 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x ][ cell_y + 2 ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x ][ cell_y - 1 ] == 0 && xCOmok::OmokPan[ cell_x ][ cell_y + 3 ] == 0 ) ++white_count; //=========================================================================== //--------------------------------------------------------------------------- // - 세로를 검사한다.( 흰돌 ) if( xCOmok::OmokPan[ cell_x + 1][ cell_y ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x + 2][ cell_y ] == xCOmok::WhiteStone && xCOmok::OmokPan[ cell_x - 1][ cell_y ] == 0 && xCOmok::OmokPan[ cell_x + 3][ cell_y ] == 0 ) ++white_count; //=========================================================================== if ( white_count >= 2 ) { printf( "흰돌 삼삼 체크를 하였습니다.\n" ); xCOmok::OmokPan[ stone_height ][ stone_width ] = 0; return xCOmok::WhiteStone; } } }
나름대로 삼삼을 체크하는 알고리즘을 생각해보고 짜봤는데요 이렇게 했을 경우
문제점이 있습니다.
일단 첫번째는 3*4는 체크할수가 없다는거와
두번째는 배열 [0][1],[0][2],[0][3] 이렇게 돌을 놓고 [4][0],[4][1],[4][2]
이렇게 돌이 놓으면 삼삼으로 체크해버린다는것입니다.( 삼삼이 아닌데도...)
그리고 세번째는 [0][1],[0][2],[0][4] 이렇게 돌을 놓고 [2][4],[3][4] 돌을 놓아도 삼삼인데...이런것을 체크하는 알고리즘 만들기 쉽지 않나요...
고수님들 조언 부탁드립니다.
Forums:
저도 비슷한걸 짜긴 했는데..위의 코드를 자세히 보진 않았지만..
저도 비슷한걸 짜긴 했는데..
위의 코드를 자세히 보진 않았지만...
제가 한 방법 말씀드리면..
우선 막 돌이 놓인 자리를 기준으로..
8방향으로 1개씩 멀어지면서 같은 색이 나오는 동안..
hori, vert, lt_rb, rt_lb 각각에 헤아린 개수를 더해가면서..
6칸까지 검사하고..(6목을 판단해야 하므로..)
각 변수에 들어있는 값을 보고 2개 이상이 3이면 3x3..
한개가 3 한개가 4이면 3x4..
그리고 5가 있으면 승리..
이런식으로 했었습니다.
한개의 for문안에 꽤 길게 반복적 코드가 들어가지만..
가장 이해하기 쉽고 빠르게 잘 나왔던 걸로 기억합니다.
ㅡ_ㅡ;
학교다닐때 과제로 했었는데... 기억이 안나는 군요. :oops:
학교다닐때 과제로 했었는데...
기억이 안나는 군요.
:oops: 도움이 안되는 군요 정말..
장비병 이씨
[quote]우선 막 돌이 놓인 자리를 기준으로.. 8방향으로 1
이렇게 하는 경우 현재 돌이 [1][1], [1][2], [1][3], [2][2] 이렇게 돌이 놓여 있는 경우 [3][3]에다가 돌을 놓으면 삼삼 체크 안됩니다.
혹시 금수( 3 *3, 3 * 4, 4 * 4, 3 *3 *3, 3* 4 * 3, 3 * 4 * 4 , 4 * 4 * 4)참고로 떨어진 삼삼도 포함 하고 있습니다.
금수 알고리즘을 해결할 방법이 없나요? 여기저기 돌아다녀보아도
금수 알고리즘에 대해서 나온 부분이 없네요...책에 오목 알고리즘이라고 나온거 보면 금수 체크가 안되어 있고 데브피아나 여러싸이
트를 돌아다녀보아도 금수 알고리즘 체크하는 부분이 없습니다.
고수님들 참고할 싸이트 알고리즘 알고 계신분 알려주세요...
간단하게 생각했었는데.....생각보다 마니 까다롭네요...
3일정도 고민을 해봤는데 답이 안나옵니다. 위에 있던 소스는 이미
주석으로 처리해 놓고 여러가지로 삽실하면서 해보고 있습니다.
게임 싸이트의 오목만든 개발자로도 만나고 싶은 심정이 듭니다.
결국은 불가능한가요?금수 알고리즘 이렇게 어려울줄이야?
결국은 불가능한가요?
금수 알고리즘 이렇게 어려울줄이야?
"둘때마다 모든 돌에 대해 check 하는 수 밖에 없군요.( 이
"둘때마다 모든 돌에 대해 check 하는 수 밖에 없군요.
( 이런 ㅠ_ㅠ )"
->다시 생각해 보니 저럴 필요는 없군요
->새로 두어서 자신의 돌을 중심으로 3 이나 4 가 된 돌들에 대해서만 다시 check 하면 되겠군요.( 단 떨어진건 금수가 아니라는 가정하에.. )
떨어진것까지 금수다.. .싶으면 -_- 전 포기 하겠습니다.
모든 돌에 대해 check 하던가 ㅡ,.ㅡ ( 거의 NP 문제군요.. )
단 알고리즘에서 좌우가 막힌 3 x 3 은 금수가 아닌걸로
해주셔야 할것같습니다. (-- 더욱 꼬이겠군요. )
위에 제시해주신 알고리즘을 둘때마다 모든 돌에 대해 ( 물론
흑이 두면 흑돌에 대해서만 .. )
해주면 되겠군요
잘 생각하면 매우 빠르게도 가능합니다.
또 다른 생각으로는
일단 3 이 된 열을 모두 기억하는것도 방법일듯 합니다 ( 한쪽이 막히면 지우고 4 가 된열은 두쪽이 막히면 지우고.. 그런식으로 잠재적으로 3x3 이 될 열은 모조리 메모리에 ㅡ,.ㅡ )
그 열과 새로 둔 돌이 만약 새로운 3 혹은 4 의 열을 만들고
다른 열과 교차 한다면 문제가 생기는 거겠죠 ( 모든 3 이 된 열에 대해 check 해야 겠죠. )
만약 새로 둔 돌이 동시에 2개의 3을 만들더라도 어차피 하나의
열을 저장 한후 돌려보고 다시 다음 열을 저장 한후 돌려보면
검출이 될 것입니다.
( 돌이 떨어져서 된것은 금수가 아닌걸로 아는데... 규칙 아시는분?)
Neogeo - Future is Now.
neogeo 님 말씀처럼 돌을 둘때 마다 스캔하고 있습니다.예전에는
neogeo 님 말씀처럼 돌을 둘때 마다 스캔하고 있습니다.
예전에는 15 * 15를 두고 스캔 했지만 지금은 7 * 7 범위를 두고
스캔 하고 있습니다. 범위를 이렇게 하는 이유는 금수 알고리즘이
7 * 7 범위를 벗어 날수 없다는 이유 입니다. 하지만 여기에서도
버그가 있더군요 예를 들어서 [1][1],[2][2],[4][4] 떨어진 삼삼이
있고 [1][4],[2][3][2] 이런식으로 돌을 놓는 겨우 삼삼으로 처리하게 됩니다. 이런종류의 버그가 약 20가지 넘더군요...
제가 한것에 대한 대충 코딩을 해보자면 [code:1]vertic
제가 한것에 대한 대충 코딩을 해보자면
이런식으로 코딩을 하였습니다. 일단 소스를 보시면 아시겠지만
4 * 4 , 떨어진 삼삼 추가가 안되었습니다.. 현재 개발하고 있는
소스에는 4*4, 떨어진 삼삼이 들어가 있지만 간단한 예제를 들기위해서 추가하지 않았습니다.
답글을 기대하고 있었는데...^^;어떻게 해결해야할지..막막하군요..
답글을 기대하고 있었는데...^^;
어떻게 해결해야할지..막막하군요...
많은 분들의 답글 부탁드립니다.
[quote="nayana"][quote]우선 막 돌이 놓인 자리를 기준
삼삼체크 안되는게 맞습니다.
그 경우 삼삼이 아닙니다.
삼이 없던 상태에서 새로 돌을 놓음으로해서 삼이 두개 생기는 경우가 삼삼입니다. 이미 삼이 있던 상태([1][1], [1][2], [1][3])에 삼이 하나 더 생긴다고 삼삼이 아닙니다.
[1][2],[1][3],[2][2],[3][3]이 놓여있는 상태에서 [1][1]을 놓아야 삼삼이 됩니다.
tinywolf님께서 제안해주신 방법과 유사하게 구현하는 것이 가장 간단한 방법이 될 것 같습니다. (코드는 좀 늘어지겠지만... -_-; )
사는 지방이 달라서 그런 것인지...원래 학창 시절엔 모눈종이만
사는 지방이 달라서 그런 것인지...
원래 학창 시절엔 모눈종이만 있으면 오목을 뛰게 마련이기에...
나름대로 꽤나 오목을 많이 뛰어보았다고 생각하였는데 ^^;;
도대체 "금수"가 어떤 상황을 의미하는 것인가요? :shock:
용어를 모르는 것인지, 아니면 제가 살던 동네에선 없던 규칙인지.. 모르겠네요. :roll:
[quote="lunarainbow"]도대체 "금수"가 어떤 상황을 의미
동네마다 규칙이 다르더군요. 어떤 곳에서는 삼삼을 금하고, 어떤 곳에서는 아니고, 삼삼의 정의도 동네마다 다르더군요. 세개의 돌이 나란히 있는 것만 삼삼으로 치는 곳도 있고 두개 있고 하나 떨어져서 하나 있어도 삼삼으로 치는 곳도 있고.
세벌 https://sebuls.blogspot.kr/
pattern matching
가로,세로,정방향대각선,역방향대각선에 대해 3과 4에 대한 패턴 매칭을 수행하면 됩니다. 비트로 표현하면 비트 마스킹 기법으로 해결할 수 있을겁니다.
힌트를 좀 더 드리자면, 3에 대한 의미있는 패턴은 _011010_, _01110_, ...머 이런 식입니다.
위 힌트 만으로 먼가 떠오르는 바가 있다면 아마도 오목 추론 엔진도 만들수 있을거라 생각이 됩니다.
떠오르는 바가 없으면, 못믿겠다고 한다면, 제가 만든 인공지능 오목 추론 엔진에 관심을 가져 보는게 어떨런지... 물론 비공개 되어 있습니다.
[quote="sebul"][quote="lunarainbow"]도대체
아아. 그냥 보통 말하는 삼삼 이나 삼사 같은것을 통틀어 "금수" 라고 하는것이군요!
전 왜.. 동물을 생각했었는지 ^^;;
원래 오목이 다들 한번씩 만들어 보는 것인가 보네요. 예전에 저도 위에 손님X2님이랑 같은 방법으로 했었는데..
당시에 '아무래도 이건 비교 횟수가 너무 많지 않은가?! 뭔가 좀더 쌈박한 방법이 있을꺼야' 했지만.. 도무지 적당한 방법이 생각나지 않아 그냥 그렇게 했었던 기억이 나네요.
제가 조금 더 힌트(라고 해봐야 같은말 반복인듯 싶지만) 드리자면..
일단 삼삼을 체크하기 위해서, 의미있는 열의 순서는..
01110
010110
011010
(0 : 돌이 없는것, 1 : 자신의 돌)
이렇게 3가지 입니다.
반드시 위의 3가지 패턴과 일치하는것이 4방향중 2개는 존재해야 삼삼이 되는 것입니다.
자신이 마지막으로 놓은 돌을 위의 1에 맞추어가며 좌우로 확인하는 2중 루프를 돌면.. 쿨럭;;
그렇게 3가지 패턴. (삼사 도 체크하기 위해선 패턴이 좀더 많아지겠네요)을 체크하자면.. 3중 루프문이되나? ^^;
어쨌든 방향을 8방향이 아닌 4방향으로 잡고 하시는게 편할듯 싶습니다. ^^
어렵게 짜지마시고
recursive한 구조로 작성하세요.
여러가지 사항에 대해 그것을 일일이 if문과 루프로 처리하는 건 프로그래밍이 "노가다"라고 인정하는 것과 다름 없습니다.
문제를 쪼개서 일반 함수와 재귀 함수로 일일이 다 만드세요. 훨씬 더 보기 좋고 간단하게 만들 수 있을겁니다.
지금은 게임방이라... 언제고 회사에서 시간나면 올려볼까요?
이런 알고리즘을 혼자서 고민하고 실습해보는 건 나쁘지 않은 경험입니다만, 문제의 정답(해답이 아니라)은 언제나 교과서에 있습니다.
알고리즘 공부 열심히 하시길...
주어진 문제를 어떻게 쪼개느냐가 알고리듬의 성능을 직접적으로 좌우합니다.
주어진 문제를 어떻게 쪼개느냐가 알고리듬의 성능을 직접적으로 좌우합니다. 소스를 자세히 안봤지만, 아마도 brute force 하게 작성하신것 같습니다. brute force 테크닉은 정말 그렇게 사용해야 할 경우를 제외하면 가장 좋지 않은 결과를 줍니다.
저는 오목 프로그램을 짜본적도 없고, 오목의 정형화된 알고리듬을 본적도 없지만 제 생각에 체크하는 영역 자체을 좁힐 필요가 있는것 같습니다. 그리고 이런 좁은 영역 설정을 위해 "가장 위험한 지역(A1)"과 "가장 유리한 지역(A2)"이라는 별도의 메모리 구조를 두고 매번 돌을 둘때마다 이 메모리의 내용을 갱신하여 그 부분만을 체크하게 하면 문제가 보다 깔끔하게 해결될것 같습니다. 저는 아래처럼 정리되는군요.
1. 어떤 경우에도 상대와 나는 돌을 번갈아가면서 둔다.
2. 돌을 두는 전략으로는 공격, 방어 두가지 경우 밖에 없다.
3. A1, A2을 설정하여 상대가 되었든 내가 되었든 매번 돌을 둘때마다 갱신한다.(돌을 놓은 주변부에 대해서만 체크하면 됨)
4. 방어시에는 A1에 공격시에는 A2에 돌을 놓도록 한다.
5. 방어와 공격중 방어전략의 우선순위를 높이되 방어가 긴급히 요구되지 않을때는 디폴트로 공격을 한게한다.(혹은 공격과 방어에 대한 평가 함수를 만들어 평가값이 더 높은 전략을 선택하게 한다.)
일단 여기까지 하면, 현재에 근거한 오목 프로그램의 전체적인 윤곽은 다 나오지 않나 생각합니다. 이 이상의 고급기능(?)을 추가하기 위해서는 '수읽기' 예측능력을 부여해야 할듯 합니다. 이것은 상대가 돌을 놓아왔던 패턴을 통계적으로 분석해서 어디에 놓을것이라는 예측을 하고, 이를 바탕으로 자신의 전략대로 가상으로 N수 까지 계속 두어간 후 가장 유리한 지역이 예상되는것으로 A2을 설정해두는것이 될겁니다. 방어시 A1도 마찬가지게 될것이구요. 이렇게까지 하면 상당히 '좋은' 오목 프로그램이 나오지 않을까 생각되네요. :wink:
일단 1~5 의 규칙만 제대로 적용해도 예측능력은 꽝이더라도 최선의 전략으로 돌을 놓을 수는 있습니다. '최적' 상태로 돌을 놓으려면 통계적 예측능력을 부여해야만 가능 할겁니다. 적어도 제 생각엔 그렇다는거죠. 8)
그런데 정작 '금수'에 대한 얘기는 하나도 못꺼냈네요. :oops: 그
그런데 정작 '금수'에 대한 얘기는 하나도 못꺼냈네요. :oops: 그런데 그 문제는 A1, A2 를 갱신할때 자동으로 해결될 문제로 보여서 별로 할말도 없는것 같습니다. 아마 능력이 좋으시니 잘 해결하실걸로 생각하고, 생략하겠습니다. 8) 열심히 하세요~
흐흐
흐흐 심심해서 만들어봤는데 재밌군요.
[quote="sebul"][quote="lunarainbow"]도대체
여담입니다만 오목도 공식적인 규칙이 많이 있는 데 대부분 "백에게는 금수가 없다", "흑에게 3.3, 6목은 금수이다." 은 다 가지고 있습니다.
백과 흑에게 똑같이 금수를 주면 흑이 무조건 이기죠.
아시는 건 데 제가 쓸 때없이 한 건... ;;;;
금수알고리즘 간단합니다.
1. 열린3이 2개 이상이면 쌍삼이다.
1-1. 3을생각할때 돌세개가 전부 붙어있는3이있으면 그중에는 한칸의 빈공간을 끼고있는 3도있다.
2. 열리건닫건 4개만들어지는경우가 2개이상이면 사사다.
3. 현재놓은돌을 기준으로 생각한다.
3-1. 현재놓은돌기준으로 ← → , ↖ ↘ , ↑ ↓ , ↙ ↗ 이렇게 4가지로요소로 나누어볼수있다.
3-2. 기준대로 뻗어나가며 반복하다가 빈공간을 2번연속만나거나,
이미한번빈공간을끼고 3이나 4가 이루어지고 다시한번더 빈공간을 만나거나,
상대방의 돌을 만나거나,
벽을 만나는경우, 탐색을종료한다.
3-3. 각각 4가지는 서로반대인 두가지경우를 가지므로 각 두가지경우마다의 돌의갯수, 사용된빈공간(두경우 총합 최대1개까지 허용)을 이용하여 판단.
자세한것은 미디엄블로그에 포스팅해놨습니다.
https://medium.com/@cldhfleks2/java-%EC%98%A4%EB%AA%A9-%EA%B8%88%EC%88%98-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-b88d349a0553
댓글 달기