오목에서 금수체크하는 알고리즘 ( 불가능한가? )

nayana의 이미지

오목에서 삼삼(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] 돌을 놓아도 삼삼인데...이런것을 체크하는 알고리즘 만들기 쉽지 않나요...
고수님들 조언 부탁드립니다.
tinywolf의 이미지

저도 비슷한걸 짜긴 했는데..

위의 코드를 자세히 보진 않았지만...

제가 한 방법 말씀드리면..

우선 막 돌이 놓인 자리를 기준으로..

8방향으로 1개씩 멀어지면서 같은 색이 나오는 동안..

hori, vert, lt_rb, rt_lb 각각에 헤아린 개수를 더해가면서..

6칸까지 검사하고..(6목을 판단해야 하므로..)

각 변수에 들어있는 값을 보고 2개 이상이 3이면 3x3..

한개가 3 한개가 4이면 3x4..

그리고 5가 있으면 승리..

이런식으로 했었습니다.

한개의 for문안에 꽤 길게 반복적 코드가 들어가지만..

가장 이해하기 쉽고 빠르게 잘 나왔던 걸로 기억합니다.

ㅡ_ㅡ;

스파이크의 이미지

학교다닐때 과제로 했었는데...
기억이 안나는 군요.
:oops: 도움이 안되는 군요 정말..

장비병 이씨

nayana의 이미지

Quote:
우선 막 돌이 놓인 자리를 기준으로..

8방향으로 1개씩 멀어지면서 같은 색이 나오는 동안..

hori, vert, lt_rb, rt_lb 각각에 헤아린 개수를 더해가면서

이렇게 하는 경우 현재 돌이 [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일정도 고민을 해봤는데 답이 안나옵니다. 위에 있던 소스는 이미
주석으로 처리해 놓고 여러가지로 삽실하면서 해보고 있습니다.
게임 싸이트의 오목만든 개발자로도 만나고 싶은 심정이 듭니다.

nayana의 이미지

결국은 불가능한가요?
금수 알고리즘 이렇게 어려울줄이야?

neogeo의 이미지

"둘때마다 모든 돌에 대해 check 하는 수 밖에 없군요.

( 이런 ㅠ_ㅠ )"

->다시 생각해 보니 저럴 필요는 없군요

->새로 두어서 자신의 돌을 중심으로 3 이나 4 가 된 돌들에 대해서만 다시 check 하면 되겠군요.( 단 떨어진건 금수가 아니라는 가정하에.. )

떨어진것까지 금수다.. .싶으면 -_- 전 포기 하겠습니다.

모든 돌에 대해 check 하던가 ㅡ,.ㅡ ( 거의 NP 문제군요.. )

단 알고리즘에서 좌우가 막힌 3 x 3 은 금수가 아닌걸로

해주셔야 할것같습니다. (-- 더욱 꼬이겠군요. )

위에 제시해주신 알고리즘을 둘때마다 모든 돌에 대해 ( 물론

흑이 두면 흑돌에 대해서만 .. )

해주면 되겠군요

잘 생각하면 매우 빠르게도 가능합니다.

또 다른 생각으로는

일단 3 이 된 열을 모두 기억하는것도 방법일듯 합니다 ( 한쪽이 막히면 지우고 4 가 된열은 두쪽이 막히면 지우고.. 그런식으로 잠재적으로 3x3 이 될 열은 모조리 메모리에 ㅡ,.ㅡ )

그 열과 새로 둔 돌이 만약 새로운 3 혹은 4 의 열을 만들고

다른 열과 교차 한다면 문제가 생기는 거겠죠 ( 모든 3 이 된 열에 대해 check 해야 겠죠. )

만약 새로 둔 돌이 동시에 2개의 3을 만들더라도 어차피 하나의

열을 저장 한후 돌려보고 다시 다음 열을 저장 한후 돌려보면

검출이 될 것입니다.

( 돌이 떨어져서 된것은 금수가 아닌걸로 아는데... 규칙 아시는분?)

Neogeo - Future is Now.

nayana의 이미지

neogeo 님 말씀처럼 돌을 둘때 마다 스캔하고 있습니다.
예전에는 15 * 15를 두고 스캔 했지만 지금은 7 * 7 범위를 두고
스캔 하고 있습니다. 범위를 이렇게 하는 이유는 금수 알고리즘이
7 * 7 범위를 벗어 날수 없다는 이유 입니다. 하지만 여기에서도
버그가 있더군요 예를 들어서 [1][1],[2][2],[4][4] 떨어진 삼삼이
있고 [1][4],[2][3][2] 이런식으로 돌을 놓는 겨우 삼삼으로 처리하게 됩니다. 이런종류의 버그가 약 20가지 넘더군요...

nayana의 이미지

제가 한것에 대한 대충 코딩을 해보자면

vertical_x  = ( stone_height - 4 < 0  ) ?  0 : stone_height - 4; 
	vertical_x1 = ( stone_height + 4 > 14 ) ? 14 : stone_height + 4; 
	horison_y   = ( stone_width  - 4 < 0  ) ?  0 : stone_width  - 4; 
	horison_y1  = ( stone_width  + 4 > 14 ) ? 14 : stone_width  + 4; 
 for(i=vertical_x;i<verical_x1;i++){
     for(j=verical_y;j<verical_y1;j++){
       if(m[i][j] == stone){
	 if(m[i+1][j+1]==stone && m[i+2][j+2]==stone &&
	    m[i-1][j-1]==0 && m[i+3][j+3]==0) sum++;
	 if(m[i-1][j+1]==stone && m[i-2][j+2]==stone &&
	    m[i+1][j-1]==0 && m[i-3][j+3]==0) sum++;
	 if(m[i  ][j+1]==stone && m[i  ][j+2]==stone &&
	    m[i  ][j-1]==0 && m[i  ][j+3]==0) sum++;
	 if(m[i+1][j  ]==stone && m[i+2][j  ]==stone &&
	    m[i-1][j  ]==0 && m[i+3][j  ]==0) sum++;
       }
     }
   }

이런식으로 코딩을 하였습니다. 일단 소스를 보시면 아시겠지만
4 * 4 , 떨어진 삼삼 추가가 안되었습니다.. 현재 개발하고 있는
소스에는 4*4, 떨어진 삼삼이 들어가 있지만 간단한 예제를 들기위해서 추가하지 않았습니다.

nayana의 이미지

답글을 기대하고 있었는데...^^;
어떻게 해결해야할지..막막하군요...
많은 분들의 답글 부탁드립니다.

익명 사용자의 이미지

nayana wrote:
Quote:
우선 막 돌이 놓인 자리를 기준으로..

8방향으로 1개씩 멀어지면서 같은 색이 나오는 동안..

hori, vert, lt_rb, rt_lb 각각에 헤아린 개수를 더해가면서

이렇게 하는 경우 현재 돌이 [1][1], [1][2], [1][3], [2][2] 이렇게 돌이 놓여 있는 경우 [3][3]에다가 돌을 놓으면 삼삼 체크 안됩니다.


삼삼체크 안되는게 맞습니다.
그 경우 삼삼이 아닙니다.
삼이 없던 상태에서 새로 돌을 놓음으로해서 삼이 두개 생기는 경우가 삼삼입니다. 이미 삼이 있던 상태([1][1], [1][2], [1][3])에 삼이 하나 더 생긴다고 삼삼이 아닙니다.
[1][2],[1][3],[2][2],[3][3]이 놓여있는 상태에서 [1][1]을 놓아야 삼삼이 됩니다.
tinywolf님께서 제안해주신 방법과 유사하게 구현하는 것이 가장 간단한 방법이 될 것 같습니다. (코드는 좀 늘어지겠지만... -_-; )
lunarainbow의 이미지

사는 지방이 달라서 그런 것인지...

원래 학창 시절엔 모눈종이만 있으면 오목을 뛰게 마련이기에...

나름대로 꽤나 오목을 많이 뛰어보았다고 생각하였는데 ^^;;

도대체 "금수"가 어떤 상황을 의미하는 것인가요? :shock:

용어를 모르는 것인지, 아니면 제가 살던 동네에선 없던 규칙인지.. 모르겠네요. :roll:

세벌의 이미지

lunarainbow wrote:
도대체 "금수"가 어떤 상황을 의미하는 것인가요? :shock:

용어를 모르는 것인지, 아니면 제가 살던 동네에선 없던 규칙인지.. 모르겠네요. :roll:


동네마다 규칙이 다르더군요. 어떤 곳에서는 삼삼을 금하고, 어떤 곳에서는 아니고, 삼삼의 정의도 동네마다 다르더군요. 세개의 돌이 나란히 있는 것만 삼삼으로 치는 곳도 있고 두개 있고 하나 떨어져서 하나 있어도 삼삼으로 치는 곳도 있고.
익명 사용자의 이미지

가로,세로,정방향대각선,역방향대각선에 대해 3과 4에 대한 패턴 매칭을 수행하면 됩니다. 비트로 표현하면 비트 마스킹 기법으로 해결할 수 있을겁니다.
힌트를 좀 더 드리자면, 3에 대한 의미있는 패턴은 _011010_, _01110_, ...머 이런 식입니다.
위 힌트 만으로 먼가 떠오르는 바가 있다면 아마도 오목 추론 엔진도 만들수 있을거라 생각이 됩니다.
떠오르는 바가 없으면, 못믿겠다고 한다면, 제가 만든 인공지능 오목 추론 엔진에 관심을 가져 보는게 어떨런지... 물론 비공개 되어 있습니다.

lunarainbow의 이미지

sebul wrote:
lunarainbow wrote:
도대체 "금수"가 어떤 상황을 의미하는 것인가요? :shock:

용어를 모르는 것인지, 아니면 제가 살던 동네에선 없던 규칙인지.. 모르겠네요. :roll:


동네마다 규칙이 다르더군요. 어떤 곳에서는 삼삼을 금하고, 어떤 곳에서는 아니고, 삼삼의 정의도 동네마다 다르더군요. 세개의 돌이 나란히 있는 것만 삼삼으로 치는 곳도 있고 두개 있고 하나 떨어져서 하나 있어도 삼삼으로 치는 곳도 있고.

아아. 그냥 보통 말하는 삼삼 이나 삼사 같은것을 통틀어 "금수" 라고 하는것이군요!

전 왜.. 동물을 생각했었는지 ^^;;

원래 오목이 다들 한번씩 만들어 보는 것인가 보네요. 예전에 저도 위에 손님X2님이랑 같은 방법으로 했었는데..

당시에 '아무래도 이건 비교 횟수가 너무 많지 않은가?! 뭔가 좀더 쌈박한 방법이 있을꺼야' 했지만.. 도무지 적당한 방법이 생각나지 않아 그냥 그렇게 했었던 기억이 나네요.

제가 조금 더 힌트(라고 해봐야 같은말 반복인듯 싶지만) 드리자면..

일단 삼삼을 체크하기 위해서, 의미있는 열의 순서는..

01110
010110
011010
(0 : 돌이 없는것, 1 : 자신의 돌)
이렇게 3가지 입니다.

반드시 위의 3가지 패턴과 일치하는것이 4방향중 2개는 존재해야 삼삼이 되는 것입니다.

자신이 마지막으로 놓은 돌을 위의 1에 맞추어가며 좌우로 확인하는 2중 루프를 돌면.. 쿨럭;;
그렇게 3가지 패턴. (삼사 도 체크하기 위해선 패턴이 좀더 많아지겠네요)을 체크하자면.. 3중 루프문이되나? ^^;

어쨌든 방향을 8방향이 아닌 4방향으로 잡고 하시는게 편할듯 싶습니다. ^^

blitzerg의 이미지

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: 그런데 그 문제는 A1, A2 를 갱신할때 자동으로 해결될 문제로 보여서 별로 할말도 없는것 같습니다. 아마 능력이 좋으시니 잘 해결하실걸로 생각하고, 생략하겠습니다. 8) 열심히 하세요~

blitzerg의 이미지

#include <cstdlib>
#include <iostream>

using namespace std;

typedef char Stone;
enum Direction { N, NE, E, SE, S, SW, W, NW };
enum Result { CONTINUE, NOPUT, WIN };
struct Pair { int x, y; };
const Pair move[8] = { {0,-1}, {1,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0}, {-1,-1} };
int table[20];
const Stone black = 'o';
const Stone white = 'x';
Stone board[19][20] = {
	//		 0000000000111111111
	//		 0123456789012345678
	/*00*/	"+++++++++++++++++++",
	/*01*/	"+++++++++++++++++++",
	/*02*/	"+++++++++++++++++++",
	/*03*/	"+++++++++++++++++++",
	/*04*/	"+++++++++++++++++++",
	/*05*/	"+++++++++++++++++++",
	/*06*/	"+++++++++++++++++++",
	/*07*/	"+++++++++++++++++++",
	/*08*/	"+++++++++++++++++++",
	/*09*/	"+++++++++++++++++++",
	/*10*/	"+++++++++++++++++++",
	/*11*/	"+++++++++++++++++++",
	/*12*/	"+++++++++++++++++++",
	/*13*/	"+++++++++++++++++++",
	/*14*/	"+++++++++++++++++++",
	/*15*/	"+++++++++++++++++++",
	/*16*/	"+++++++++++++++++++",
	/*17*/	"+++++++++++++++++++",
	/*18*/	"+++++++++++++++++++"
};

int count( const int x, const int y, const Stone stone, const Direction d )
{
	if( x == -1 || y == -1 )		return 0;
	else if( x == 19 || y == 19 )	return 0;
	
	if( board[y][x] == '+' )		return 0;
	else if( board[y][x] != stone ) return 100;
	else return 1 + count( x + move[d].x, y + move[d].y, stone, d );
}

void cleartable( void )
{
	for( int t = 0 ; t < 10 ; t++ )
	{
		table[t] = 0;
	}
}

bool isNoput( void )
{
	// 돌을 놓을 수 없는 조건 검사 : (3,3) (3,4)
	if( table[3] >= 2 ) return true;
	else if( table[3] >= 1 && table[4] >= 1 ) return true;
	else return false;
}

bool isWin( void )
{
	// 이기는데 필요한 돌 : 다섯 개 
	if( table[5] >= 1 ) return true;
	else return false;
}

Result verify( const int x, const int y, const Stone stone )
{
	cleartable();
	
	for( int d = N ; d < NW/2 ; d++ )
	{
		int v = count( x, y, stone, (Direction)d ) + count( x, y, stone, (Direction)((d+4)%8) ) - 1;
		if( v < 100 ) table[v]++;

		if( isWin() ) return WIN;
		else if( isNoput() ) return NOPUT;
	}

	return CONTINUE;
}

Result putStone( const int x, const int y, const Stone stone )
{
	if( board[y][x] == '+' )
	{
		Stone temp = board[y][x];
		
		board[y][x] = stone;
		
		switch( verify( x, y, stone ) )
		{
		case NOPUT :
			board[y][x] = temp;
			return NOPUT;
		case WIN :
			return WIN;
		default :
			return CONTINUE;
		}
	}
	else
	{
		return NOPUT;
	}
}

void showboard( void )
{
#ifdef  _MSC_VER
	system("cls");
#else
	system("clear");
#endif
	
	cout << "  0000000000111111111" << endl;
	cout << "  0123456789012345678" << endl;
	for( int b = 0 ; b < 19 ; b++ )
	{
		cout << b/10 << b%10 << board[b] << endl;
	}
}

void game( void )
{
	bool endstate = false;
	Stone user = black;
	string umsg = "black";
	string msg;
	
	while( !endstate )
	{
		int x, y;
		showboard();
		cout << msg;
		msg = "";

		do
		{
			cout << "\nwhere put a " << umsg << " stone?\n\tx (0~18) :";
			cin >> x;			
		} while( !(x >= 0 && x <= 18) );
		
		do
		{
			cout << "\ty (0~18) :";
			cin >> y;		
		} while( !(y >= 0 && y <= 18) );

		switch( putStone( x, y, user ) )
		{
		case NOPUT:
			msg = "\nError: wrong position!!\n";
			continue;
		case WIN:
			msg = umsg + " win!\n\n";
			endstate = true;
			break;
		default:
			user = (user==black) ? white : black;
			umsg = (user==black) ? "black" : "white";
			break;
		}
	}

	cout << msg;
}

int main(void)
{
	game();
	return 0;
}

흐흐 심심해서 만들어봤는데 재밌군요.

RedPain의 이미지

sebul wrote:
lunarainbow wrote:
도대체 "금수"가 어떤 상황을 의미하는 것인가요? :shock:

용어를 모르는 것인지, 아니면 제가 살던 동네에선 없던 규칙인지.. 모르겠네요. :roll:


동네마다 규칙이 다르더군요. 어떤 곳에서는 삼삼을 금하고, 어떤 곳에서는 아니고, 삼삼의 정의도 동네마다 다르더군요. 세개의 돌이 나란히 있는 것만 삼삼으로 치는 곳도 있고 두개 있고 하나 떨어져서 하나 있어도 삼삼으로 치는 곳도 있고.

여담입니다만 오목도 공식적인 규칙이 많이 있는 데 대부분 "백에게는 금수가 없다", "흑에게 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

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.