지난 시간까지 작성한 코드에서는 게임 시작 대기 화면에서 확인 버튼을 누르면,

바로 State.GAME_RUNNING으로 GameView.curViewState가 변경 되었지만,


이번에는 State.GAME_DISTRIBUTECARDS 로 변경되도록 바꾸어 주고 나서,

카드를 나누어 주는 것을 구현해 주어야 하겠지요?

/**
 * 키 입력.
 */
public void keyPressed(int keyCode)
{
    switch(keyCode)
    {

/**
*
* ... 생략 ...
*
*/


case KEY_COMR: case KEY_FIRE: case KEY_POUND: /* '#' */ if(curViewState == State.GAME_WAIT) { byte i; curViewState = State.GAME_DISTRIBUTECARDS;
distributeStep = 0; // 나눠주기 단계 0으로 초기화. curTurn = User.PLAYER; repaints(); Sleep.wait(this, 500); distributeStep = 1; // 나눠주기 단계 1로 초기화. room.init(); repaints(); Sleep.wait(this, 500); for(i=2; i<10; i++) { distributeStep = i; // 나눠주기 단계 설정. // 컴퓨터에게 카드를 줄때는, if(distributeStep == 4 || distributeStep == 6) curTurn = User.COMPUTER; else curTurn = User.PLAYER; room.distributeCards(distributeStep); repaints(); Sleep.wait(this, 500); } // 카드를 다 나누어주었다면, 게임 시작. curViewState = State.GAME_RUNNING; curTurn = User.PLAYER; repaints(); } }
}

다른 키 입력은 모두 생략하고, 게임 대기 화면에서 확인키를 눌렀을 때만을 살펴봅니다.
(다른 키 입력은 지난 시간에 작성한 내용과 동일 합니다.)

가장 먼저, 확인키를 누르면, curViewState를 State.GAME_DISTRIBUTECARDS로 초기화를 해서,

카드를 나눠주는 화면을 그려줄 수 있도록 합니다.

distributeStep은 카드를 나눠주는 단계를 저장하는 변수인데, 잠시후에 나옵니다.


그 다음에는, distributeStep을 하나씩 증가 해줄때마다,

repaints() 함수를 호출해서 전체화면을 다시 그려주어, 나눠주는 것을 플레이어가 확인하게 하는 것이죠.


카드를 나누어 주는 동작은 0번, 1번은 keyPressed에서 직접 처리해주고,

2번 ~ 9번까지의 동작은, gostop.GameRoom 클래스에서 distributeCards() 함수로 처리합니다.

/**
 * 카드를 나눠준다.
 * @param distributeStep 나눠주기 단계.
 */
public void distributeCards(int distributeStep)
{
    switch(distributeStep)
    {
    case 2: // 중앙에 카드를 뒤집어 바닥에 4장의 카드를 깜.
       for(i=0; i<4; i++)
            setMonth(i, suffleCards.removeLast(), false);
        break;
    case 3: // 플레이어에게 먼저 5장의 카드를 줌.
       for(i=0; i<5; i++)
            setUserHand(User.PLAYER, i, suffleCards.removeLast());
        break;
    case 4: // 컴퓨터에게 5장.
        for(i=0; i<5; i++)
            setUserHand(User.COMPUTER, i, suffleCards.removeLast());
        break;
    case 5: // 다시 바닥에 4장을 깜.
        for(i=4; i<8; i++)
            setMonth(i, suffleCards.removeLast(), false);
        break;
    case 6: // 컴퓨터에게 5장.
        for(i=5; i<10; i++)
            setUserHand(User.COMPUTER, i, suffleCards.removeLast());
        break;
    case 7: // 플레이어에게 5장.
        for(i=5; i<10; i++)
            setUserHand(User.PLAYER, i, suffleCards.removeLast());
        break;
        }
    }

Step별로 중앙에 카드를 뿌려주고, 컴퓨터와 플레이어에게도 각각 나눠줍니다.

이때 나눠주는 카드는 모두 중앙의 카드에서 위에서부터 하나씩 차례로 뒤집어 나누어주는 것이며,

앞서 살펴보았던 BCollector 클래스의 removeLast() 함수를 호출해서 뒤집어 줍니다.


이제 카드를 나누어 주는 동작은 모두 구현했습니다.

동작을 구현했더라도 그 동작을 화면상에 그려주는 작업도 필요하겠지요.

카드를 나누어 주는 장면은 drawDistributeCards() 함수가 처리합니다.

/**
 * 카드를 나눠주는 중의 화면을 그려준다.
 * @param g
 */
private void drawDistributeCards(Graphics g)
{
    int i, j;

    // Step 0: 아무것도 그리지않는다.
    if(distributeStep == 0)
        return;


    // Step 1: 화투를 섞어 중앙에 쌓아놓음.
    drawCard(floorCenterPos.left-TRANS_WIDTH, 
floorCenterPos.top+TRANS_HEIGHT*curTurn, CARD_BACK); if(distributeStep == 1) return; // Step 2: 중앙의 카드중 위에서 4장을 바닥에 깜. for(i=0; i<4; i++) { if(room.getMonth(i)[0] != room.CARD_NULL) drawCard(floorCardPos[i].left-TRANS_WIDTH,
floorCardPos[i].top+TRANS_HEIGHT*curTurn,
CARD_BACK); } if(distributeStep == 2) return; // Step 3: 중앙의 카드중 위에서 5장을 플레이어에게... for(i=0; i<5; i++) drawCard(i*12, height-CARD_HEIGHT+TRANS_HEIGHT*curTurn,
CARD_BACK); if(distributeStep == 3) return; // Step 4: 중앙의 카드중 위에서 5장을 컴퓨터에게... if(curTurn == User.COMPUTER) for(i=0; i<5; i++) drawSmallCard((i+1)*5, -TRANS_HEIGHT, CARD_BACK); if(distributeStep == 4) return; // Step 5: 중앙의 카드중 위에서 4장을 바닥에 깜. for(i=4; i<8; i++) { if(room.getMonth(i)[0] != room.CARD_NULL) drawCard(floorCardPos[i].left-TRANS_WIDTH,
floorCardPos[i].top+TRANS_HEIGHT*curTurn,
CARD_BACK); } if(distributeStep == 5) return; // Step 6: 중앙의 카드중 위에서 5장을 컴퓨터에게... if(curTurn == User.COMPUTER) for(i=5; i<10; i++) drawSmallCard((i+1)*5, -TRANS_HEIGHT, CARD_BACK); if(distributeStep == 6) return; // Step 7: 중앙의 카드중 위에서 5장을 플레이어에게... for(i=5; i<10; i++) drawCard(i*12, height-CARD_HEIGHT+TRANS_HEIGHT*curTurn,
CARD_BACK); if(distributeStep == 7) return; // Step 8: 바닥에 깔린 패를 모두 뒤집어 준다. drawMonths(g); /* * 중앙의 패 중에, 서비스 패가 있다면, 실행. */ for(i=0; i<8; i++) {
/* 서비스 패가 있다면, */ if( room.isAdditionalCard(room.getMonth(i)[0]) ) { if(i < 4) room.addPee(User.COMPUTER, room.getMonth(i)[0]); else room.addPee(User.PLAYER, room.getMonth(i)[0]); room.setMonth(i, true); } } if(distributeStep == 8) return; // Step 9: 각 월 정렬. room.sortMonth(); // 월 정렬. drawPee(); // 플레이어가 먹은 서비스피를 그려준다. }

distributeStep은, 한번 나눠줄때마다 keyPressed() 함수에서 distributeStep을 증가 시켜주고

다시 drawDistributeCards()를 호출하므로, 카드를 나눠주는 동작을 한단계 한단계 확인할수 있습니다.


drawDistributeStep()은 보시는 것과 같이 한단계 한단계, 단계별로 나눠주는 동작이 구현되어 있습니다.

1번 단계에서는 섞은 카드를 중앙에 그려줍니다.

말이 섞은 카드를 중앙에 그려주는 것이지, 결국엔 화투의 뒷면을 게임 화면 중앙에 그려주는 것 뿐입니다.

아래는 1번 단계의 수행 결과입니다. 그림과 비교하시면서 보시는 것이 더 이해가 빠를것 같네요.


< Step #1 >

2단계 에서는, 섞은 카드에서 위에서 4장을 바닥에 깔아주는 동작을 합니다.

// Step 2: 중앙의 카드중 위에서 4장을 바닥에 깜.
for(i=0; i<4; i++)
{
    if(room.getMonth(i)[0] != room.CARD_NULL)
        drawCard(floorCardPos[i].left-TRANS_WIDTH, 
floorCardPos[i].top+TRANS_HEIGHT*curTurn,
CARD_BACK); }

0번 부터 3번까지의 자리에 해당 자리에 카드가 있다면,(널 카드가 아니라면,) 카드를 그려줍니다.

아래는 2번 단계의 수행 결과입니다.


< Step #2 >

마찬가지로 3번 과정 역시 그려주는 위치만 floorCardPos가 아닐뿐... 나머지 과정은 모두 동일합니다.


같은 방식으로 7단계를 실행하고 나면, 다음과 같은 결과를 볼 수 있습니다.

 
< Step #7 >

이제 카드를 뒤집어야 하는데, 바닥의 패 중에 서비스 패가 있어서는 안되겠지요.

그래서 바닥의 패를 뒤집고 난 후, 바닥에 서비스 패가 있는지 체크합니다.

/*
 * 중앙의 패 중에, 서비스 패가 있다면, 실행.
 */
for(i=0; i<8; i++)
{
/* 서비스 패가 있다면, */ if( room.isAdditionalCard(room.getMonth(i)[0]) ) { if(i < 4) room.addPee(User.COMPUTER, room.getMonth(i)[0]); else room.addPee(User.PLAYER, room.getMonth(i)[0]); room.setMonth(i, true); } }

만약 바닥에서 서비스 패를 발견했다면,

앞서 나눠준 바닥 인덱스 3번 이하에 있는 서비스 패는 컴퓨터가 먹고,

나중에 나눠준 7번 이하의 서비스 패는 플레이어가 먹습니다.

그리고 서비스패가 빠져나간 바닥 슬롯의 마지막에 중앙의 카드에서 한장을 뒤집어 배치 해 주면 되겠죠.


그리고 나서, sortMonth() 함수를 호출 해주면, 같은 종류의 카드들은 한 슬롯에 몰아 줍니다.

Step 9의 결과는 다음과 같습니다.


< Step #9>

Step 8을 거치고 나면, sortMonth() 함수에 의해서 각 월이 위와 같이 정렬이 됩니다.

그럼 각 월을 정렬해 주는 sortMonth() 함수는 어떤식으로 이루어 져 있는지 한번 살펴보도록 하죠.

/**
 * 각 월을 정렬한다.
 */
public void sortMonth()
{
    int k;

    for(i=0; i<12; i++)
        for(j=0; j<12; j++)
        {
// 카드가 존재하지 않는 곳과는 비교하지 않는다.
if(cardsMonth[i][0] == CARD_NULL
|| cardsMonth[j][0] == CARD_NULL) continue;
// 같은 종류의 패라면, if((i != j) && cardsMonth[i][0]/4 == cardsMonth[j][0]/4 && cardsMonth[i][0] != CARD_NULL
&& cardsMonth[j][0] != CARD_NULL) { for(k=0; k<4; k++) { if(cardsMonth[i][k] == CARD_NULL) { cardsMonth[i][k] = cardsMonth[j][0]; cardsMonth[j][0] = CARD_NULL; } } } } }


sortMonth() 함수는 같은 종류의 카드는 같은 슬롯에 몰아 주는 역할을 합니다.

이미지 배열이 쭈르륵 있는데, 그중에 같은 종류의 카드인지를 도대체 어떻게 판든을 해야 할까요?

그 정답은 바로 화투 그림의 배열 속에 있습니다.

다시 한번 화투 이미지를 살펴보면,

 

위와 같이 되어 있습니다.

위를 보면 각 월 별로, 1월, 2월, 3월, 4월, 5월, 쭈르륵... 12월, 그리고 서비스패, 뒷면.

이런식으로 되어 있죠.


각 월마다가 같은 종류의 카드이고, 각 월은 모두 4장씩입니다.

그러므로, 해당 카드의 인덱스를 4로 나눠서 몫이 같다면, 바로 같은 종류의 패가 되겠지요.

그러나 CARD_NULL 상수가 -1인데, -1을 4로 나눠도 몫은 0이므로, 1월 카드로 오인할 소지가 있습니다.

그러므로, CARD_NULL 이라면, 계산하지 않아야 하겠지요.

 

Posted by maysent
: