반응형

 

 

글. 오상문 sualchi@daum.net

 

소스 코드입니다.

 

 

///////////////////////////////////////////////////////////////////////////
// bj.mc - Auto Created by GNEX IDE
%{
 #DEFINE PLAYERVER 4
 #DEFINE LCDCLASS 255
 #DEFINE IMAGETYPE 255
 #DEFINE AUDIOTYPE 255
 #DEFINE APPTYPE  1
 #DEFINE APPCPID  60000
 #DEFINE APPID  1
 #DEFINE APPNAME  "GNEX App"
 #DEFINE COMPTYPE 0
 #DEFINE AGENTTYPE 0
 #DEFINE VALIDCOUNT 255
 #DEFINE VALIDTERM 255
 #DEFINE DIRECTRUN 0
 #DEFINE STORETYPE 0
 #DEFINE APPVER  1
%}

#include "C:\PROGRAM FILES\SINJISOFT\GNEX SDK\include\SScript.h"

//***************************************************************
// 블랙잭 게임 - 베타 1.0
//
// 작성자 : 오상문 (sualchi@yahoo.co.kr / sualchi@daum.net)
//
// 갱신년월: 2004. 5. 22 
// 개발환경: GNEX, Mobile C 
//
// 참고사항1 : GNEX 프로젝트의 기본 환경 옵션을 적용했습니다. 
// 참고사항2 : 개선점이나 조언은 언제든지 환영합니다.
// 참고사항3 : Mobile C 개인 학습용으로 잘 활용하세요.
//***************************************************************   

//------------------------------------------------------
// GameProcess 상태 변수에서 사용 (전체적인 진행 과정)
// 도움말 / 초기화,출력 / 플레이 / 승자 출력 / 게임종료  
//------------------------------------------------------
#define INIT            0x01
#define HELP          0x02
#define START        0x04
#define PLAY          0x08
#define WINNER      0x10
#define GAMEOVER    0x20
#define WAIT           0x40
//------------------------------------------------------
// StageProcess 상태 변수에서 사용 (한판에서의 진행 과정)
// 비트0: 플레이어 종료 = 1
// 비트1: 딜러 종료 = 1
// 비트2: 플레이어 블랙잭 (비트2가 1이면 비트0 값도 1 처리)
// 비트3: 딜러 블랙잭 (비트3이 1이면 비트1 값도 1 처리)
//------------------------------------------------------
#define MAN_END         0x01
#define COM_END         0x02
#define MAN_BLACKJACK   0x04
#define COM_BLACKJACK   0x08

//------------------------------------------------------
// 게임에 사용되는  기타 매크로 값  
//------------------------------------------------------
#define TRUE    1
#define FALSE   0
#define YES     1
#define NO      0

#define UNKNOWN -1
#define DEALER  1
#define PLAYER  2
#define ALL     3

// 받을 수 있는 최대 카드 수
#define MAX_CARD 7

// 카드 이미지 제작시 카드 크기
#define CardSizeX 26
#define CardSizeY 40

// 보드 구성
#define TitleX      3
#define TitleY      0
#define BoardStartX 1
#define BoardStartY 1
#define BoardEndX   (swWidth - 2)
#define BoardEndY   115
#define ComStartX   4  
#define ComStartY   (BoardStartY+3)
#define ManStartX   ComStartX
#define ManStartY   (BoardStartY+60) 

// 카드 이미지 제작시 무늬 시작 위치
#define FSX     1
#define FSY     1
#define FEX     (CardSizeX - 10)
#define FEY     (CardSizeY - 10)

// 전체 카드 숫자 (무늬당 13장씩 4종)
#define SUM_CARD    52

//------------------------------------------------------
// 게임에 사용되는 변수   
//------------------------------------------------------
int GameProcess;        // 게임 전체 진행 상태  
int StageProcess;       // 판(내부) 진행 상태
int Winner;             // UNKNOWN(초기화값), DEALER, PLAYER, ALL, NO

// 카드 무늬
const string Shape[4] = {
    "♠", "◆", "♥", "♣"};
const string NumToStr[14] = {
    "X","A","2","3","4","5","6","7","8","9","10","J","Q","K"};

// 카드를 나열할 때 X 위치
const int Xpos[MAX_CARD+1] = {5,18,31,44,57,70,83,96};

int ShuffleCard[SUM_CARD];  // 섞어놓은 카드 데이터

int ComCard[MAX_CARD+1]={-1,-1,-1,-1,-1,-1,-1,-1}; // 딜러 받은 카드
int ManCard[MAX_CARD+1]={-1,-1,-1,-1,-1,-1,-1,-1}; // 플레이어 받은 카드

int ManCardNumber;          // 현재까지 받은 플레이어의 카드 숫자
int ComCardNumber;          // 현재까지 받은 딜러의 카드 숫자
int Money=19;               // 플레이어가 가진 돈 (배팅값 포함하면 20)
int Bet=1;                  // 배팅 값 게임 초기치
int ManPoint, ComPoint;     // 플레이어와 딜러가 얻은 카드 점수 합 

image Card[5];      // 스페이드, 다이아몬드, 하트, 크로버 카드와 뒷면(Card[4])

//----------------------------------------------------
// 게임에 사용되는 기타 임시 변수   
//------------------------------------------------------
int Time[4];        // 랜덤함수 초기화에 사용  
string str;         // 스트링

//----------------------------------------------------
// 화면에 출력할 문자열      
//------------------------------------------------------
const string help[] = {
    "*블랙잭파이터Beta1.0*",
    "---------------------",
    "21점에 가까우면 승리.",
    "21점을 넘으면 패배.",
    "2장 21점이면 블랙잭!", 
    "A는 1이나 11로 계산.",
    "J,Q,K는 10으로 계산.",  
    "블랙잭이면 더블!",
    "승자 5장 이상, 두배!" };

const string MenuText[] = {
    "▲:금액+, ◀:1장 더!",
    "▼:금액-, ▶:Go/Hit!" };           // 변경: 열어라! -> Go/Hit!

const string WinText[] = {
    "(+.+;) 비겼네요!",
    "(^O^) 자갸 이겼어!",
    "(-_-;) 딜러 승리!" };

//************************************************************
// 게임 초기화 (프로그램 구동시 한번만 실행)
//------------------------------------------------------
void Init()
{
    int i;

    GameProcess = INIT;

    // 무늬별 카드 이미지와 뒷면 이미지를 만들어서 변수에 저장한다.  
    for(i=0; i<5; i++) {
        ClearWhite();
        DrawRect(1, 1, CardSizeX, CardSizeY); // 카드 바탕

    if(i==4) {                          // 뒷면
        ShadeRect(4, 4, CardSizeX-3, CardSizeY-3, 4, 15); // 뒷면 무늬      
        GetDDB(Card[4], 1, 1, CardSizeX, CardSizeY, 0, 0); // 이미지 저장
    } else {                            // 앞면 4종  0,1,2,3
        if(i == 1 || i == 2)
            SetFontColor(109, 0);       // red, white
        else
            SetFontColor(3, 0);         // black, white

        DrawStr(FSX, FSY, Shape[i]);   
        DrawStr(FEX, FEY, Shape[i]);
        GetDDB(Card[i], 1, 1, CardSizeX, CardSizeY, 0, 0); // 이미지 저장
    }
 }

    SetFontColor(3, 0);
    ClearWhite();

    DrawBoard();        // 보드(바닥)를 그린 후에 버퍼에 저장한다.
    SaveLCD();
}   

//************************************************************
// 게임 시작시 나오는 도움말 출력하기
//------------------------------------------------------
void Help()
{
    int i;

    GameProcess = WAIT; 

    SetColor(23);                       // green
    FillRect(0, 0, swWidth-1, swHeight-1); 
    SetColor(3);                        // black

    for (i=0; i<9; i++)
        DrawStr(1, i*15+2, help[i]);

    Flush();
 
    SetTimer(5000, S_TM_ONCE);
    GameProcess = HELP;
}

//************************************************************

//------------------------------------------------------
// 보드(게임 화면 바탕)를 그린다.
//------------------------------------------------------
void DrawBoard()
{
    SetColor(125);                      // GOLD
    FillRect(0, 0, swWidth, swHeight); 

    SetColor(23);                       // green
    FillRectRound(BoardStartX, BoardStartY, BoardEndX, BoardEndY, 3); 
    SetColor(3);                        // black

    DrawMoney();                        // 배팅액과 가진돈 출력
    DrawStr(1, BoardEndY+3,  MenuText[0]);
    DrawStr(1, BoardEndY+18, MenuText[1]);
}

//------------------------------------------------------
// 카드를 섞는다.  (판이 시작될 때 실행)
//------------------------------------------------------
void Shuffle()
{
    int i, j, k, temp;

    // 랜덤 함수 초기화 ...
    GetTime(Time); 
    temp = (Time[1]<<8) | (Time[2]);
    RandSeed(temp);

    for (i=0; i < SUM_CARD; i++)    // 0~12, 13~15, 16~28, 29~51
        ShuffleCard[i] = i;    
    
    for (i=0; i < 100; i++) {           // 100번 임의 자리 교환
        j = Rand(0, SUM_CARD-1);        // 자리 바꿀 랜덤 위치 1
        k = Rand(0, SUM_CARD-1);        // 자리 바꿀 랜덤 위치 2

        if (j == k) { // 교환 위치가 같으면 다르게 처리   
            if ((j > 0) && (j != SUM_CARD-1))  j = SUM_CARD-1;
            else j = 1;
        }

        temp = ShuffleCard[j];          // 카드 위치 서로 바꿈
        ShuffleCard[j] = ShuffleCard[k];
        ShuffleCard[k] = temp;    
    }
}

//--------------------------------------------------
// 플레이어가 가진 돈과 배팅 금액을 출력한다.
//--------------------------------------------------
void DrawMoney()
{
    SetMediaSize(str, 0);               // 메모리 해제할까?
    MakeStr2(str, "BET:%2d칩 Money:%3d칩", Bet, Money);

    SetColor(23);                       // green
    FillRect(BoardStartX+2, BoardEndY-13, BoardEndX-1, BoardEndY-1);
    SetColor(3);                        // black

    DrawStr(4, BoardEndY-12, str);
    if(GameProcess != INIT)
        Flush();
}

//----------------------------------------------------
// 딜러의 n번째 카드를 한장 그린다.
// open = 공개여부, flush = Flush() 사용 출력 여부
//----------------------------------------------------
void DrawComCard(int n, int open, int flush)
{
    int x, shape, num;

    if (open == NO) { // 보여줄지 덮을지   
        PutDDB(Xpos[n], ComStartY, Card[4]);
    } else {         
        shape = ComCard[n] / 13;        // 카드 무늬 종류
        num = ComCard[n] % 13 + 1;      // 카드 번호 얻음 
        x = (num == 10) ? 12 : 18;      // 두자리 숫자 10 출력 위치 조정
        PutDDB(Xpos[n], ComStartY, Card[shape]); // 카드 기본 판

        if(shape == 1 || shape == 2)
            SetFontColor(109, 0);           // red, white
        else
            SetFontColor(3, 0);             // black, white

        DrawStr(Xpos[n]+3, ComStartY+10, NumToStr[num]); // 숫자 출력
        DrawStr(Xpos[n]+x, ComStartY+20, NumToStr[num]);
    }

    SetFontColor(3, 0); // red, white
    if(flush==YES)
        Flush();
}

//---------------------------------------------------
// 사람의 n번째 카드를 한장 그린다.
// open = 공개여부, flush = Flush() 사용 출력 여부
//----------------------------------------------------
void DrawManCard(int n, int open, int flush)  
{
    int x, shape, num;

    if (open == NO) {                   // 보여줄지 덮을지   
        PutDDB(Xpos[n], ManStartY, Card[4]);
    } else {
        shape = ManCard[n] / 13;        // 카드 무늬 종류
        num = ManCard[n] % 13 + 1;      // 카드 번호 얻음
        PutDDB(Xpos[n], ManStartY, Card[shape]); // 카드 기본판
        x = (num == 10) ? 12 : 18;      // 두자리 숫자 10은 출력 위치 조정

        if(shape == 1 || shape == 2)
            SetFontColor(109, 0);       // red, white
        else
            SetFontColor(3, 0);         // black, white

        DrawStr(Xpos[n]+3, ManStartY+10, NumToStr[num]); // 숫자 출력
        DrawStr(Xpos[n]+x, ManStartY+20, NumToStr[num]);

        SetFontColor(3, 0);  // black, white
    }

    if(flush==YES)
        Flush();
}

//------------------------------------------------
// 플레이어 카드를 한 장씩 더 받고 화면에 그린다.
//------------------------------------------------
void AddManCard(int open)
{
    if (ManCardNumber < MAX_CARD) {  // 허용 카드 개수까지 받음
        ManCard[ManCardNumber] = ShuffleCard[ManCardNumber + ComCardNumber];
        DrawManCard(ManCardNumber, NO, YES);
        if(open == YES)
            DrawManCard(ManCardNumber, YES, YES);
        ManCardNumber++;  
    } else {    // 최대 카드 수 넘으면 종료
        StageProcess = StageProcess | MAN_END;
    }
}

//----------------------------------------------
// 컴퓨터 카드를 한 장씩 더 받고 화면에 그린다.
//----------------------------------------------
void AddComCard(int open)
{
    if (ComCardNumber < MAX_CARD) {  // 허용 카드 개수까지 받음 
        ComCard[ComCardNumber] = ShuffleCard[ManCardNumber + ComCardNumber];  
        DrawComCard(ComCardNumber, NO, YES);
        if(open == YES)
            DrawComCard(ComCardNumber, YES, YES);
        ComCardNumber++;  
    } else {
        StageProcess = StageProcess | COM_END; // 최대 카드 수 넘으면 종료 
    }
}

//----------------------------------------------
// 딜러 또는 플레이어의 카드 점수 계산
//---------------------------------------------
int CheckPoint(int who) 
{
    int i, sum, ace, p;

    sum = 0;                    // 점수 합
    ace = 0;                    // A 카드 체크용 

    if (who == PLAYER) {
        for(i=0; i < ManCardNumber; i++) {
            p = ManCard[i] % 13 + 1; // 무늬별 14장씩 연속 번호에서 카드 숫자 얻음  
            if (p > 10)         // J, Q, K는 10이다.
                p = 10;     
            else if (p == 1)    // A 카드인지 검사
                ace++;   
            sum += p;           // A를 1로 처리한 결과 합
        }
    } else if (who == DEALER) {
        for(i=0; i < ComCardNumber; i++) {
            p = ComCard[i] % 13 + 1;
            if (p > 10)         // J, Q, K는 10이다. 
                p = 10;  
            else if (p == 1)    // A 카드인지 검사
                ace++;  
            sum += p;           // A를 1로 처리한 결과 합
        }
    } else
        sum = -1;

    if (ace > 0 && sum <= 11)   // A를 11로 활용할 조건이면...
        sum += 10;

    return sum;
}

//-----------------------------------------------------------
// 블랙잭 체크 
// [반환] DEALER: 딜러, PLAYER: 플레이어, TIE: 둘 다, NO: 없음)
//-------------------------------------------------------------
int CheckBlackjack()
{
    int temp;

    temp = NO;                  // 없음

    if (CheckPoint(PLAYER) == 21)
        temp = PLAYER;          // 플레이어가 블랙잭이다.
    if (CheckPoint(DEALER) == 21)
        temp += DEALER;         // 딜러가 블랙잭이다.

    return temp; 
}

//------------------------------------------------------
// 게임 한 판 진행할 때 마다 초기화하는 함수   
//------------------------------------------------------
void Start()
{
    GameProcess = WAIT;
    StageProcess = 0;
    ManCardNumber = 0;          // 플레이어가 받은 카드 수는 0
    ComCardNumber = 0;          // 딜러가 받은 카드 수는 0
    Bet = 1;                    // 초기 배팅 값
    ManPoint = 0;               // 플레이어가 얻은 카드 점수
    ComPoint = 0;               // 딜러가 얻은 카드 점수 
    Winner = UNKNOWN;           // 승자는 아직 모름

    Shuffle();                  // 카드 섞기
    RestoreLCD();               // 새 판 그리기
    DrawMoney();

    AddComCard(NO);             // 딜러 카드 (뒤집은 것)
    AddComCard(YES);            // 딜러 카드 (열린 것)  
    AddManCard(YES);            // 플레이어 카드 (열린 것)

    GameProcess = START;

//****************************************************
// 게임 한 판 시작~
//---------------------------------------------
void Play()
{
    GameProcess = PLAY;

    if (Winner == UNKNOWN) {    // 블랙잭은 첫 두장 때만 체크한다. 
        Winner = CheckBlackjack();  // 블랙잭 체크 
 
        if (Winner == PLAYER) {
            StageProcess = MAN_BLACKJACK;
        } else if (Winner == DEALER) {
            StageProcess = COM_BLACKJACK;
        } else if (Winner == PLAYER + DEALER) {
            StageProcess = StageProcess & MAN_BLACKJACK; 
            StageProcess = StageProcess & COM_BLACKJACK;  
        }

        if (Winner > 0)
            Winner();
    }

    ManPoint = CheckPoint(PLAYER); // 플레이어 점수 계산
    ComPoint = CheckPoint(DEALER); // 딜러 점수 계산 
 
    if(Winner == NO) {
        // 플레이어가 21점 이상이면 딜러 작업 없이 무조건 패배  
        if (ManPoint < 21) {
            if(ManPoint == 21) // 플레이어가 21점이면 딜러 카드 처리 GO!
                StageProcess = StageProcess | MAN_END; 
            if (StageProcess & MAN_END) {  // 플레이어가 끝났으면...    
                if(ComPoint >= 17 )     // 딜러가 17 이상이면 딜러 종료
                    StageProcess = StageProcess | COM_END;
                else {          // 딜러 플레이 마무리 진행 
                    while ( ComPoint < 17 ) {
                        AddComCard(YES);
                        ComPoint = CheckPoint(DEALER);
                    }
                    StageProcess = StageProcess | COM_END; // 딜러 종료
                }
            }
        } else {
            StageProcess = StageProcess | (MAN_END + COM_END);
        }
    }

    // 게임을 마친 상태이면... 승부 출력으로
    if((StageProcess & MAN_END) && (StageProcess & COM_END))
        Winner();
}

//******************************************************************
// 승패 결과 출력
//-------------------------
void Winner()
{
    int i, d;                   // d = check double
    string s1, s2;
 
    GameProcess = WINNER;
    d = 0; 

    for(i=0; i < ComCardNumber; i++)
        DrawComCard(i, YES, NO); 
    Flush();

    ManPoint = CheckPoint(PLAYER);  
    ComPoint = CheckPoint(DEALER);   

    // 블랙잭이 있으면
    if(StageProcess & MAN_BLACKJACK || StageProcess & COM_BLACKJACK) {
        switch(StageProcess & 0x0F) {
            case MAN_BLACKJACK: // 플레이어 블랙잭 승리
                Winner = PLAYER;
                d = 1;
                break;
            case COM_BLACKJACK: // 딜러 블랙잭 승리
                Winner = DEALER;
                d = 1;
                break;
            default:    // 양쪽 블랙잭은 무승부
                Winner = ALL;
        }
    } else { // 얻은 포인트 계산
        if(ManPoint > 21)
            ManPoint = 0;
        if(ComPoint > 21)
            ComPoint = 0;
        if(ManPoint > ComPoint) {  // 플레이어 승리
            Winner = PLAYER; 
            if(ManCardNumber > 4)
                d = 1;
        } else if(ComPoint > ManPoint) { // 딜러 승리
            Winner = DEALER; 
            if(ComCardNumber > 4)
                d = 1;
        } else        // 무승부
             Winner = ALL; 
    }

    // 점수 출력
    SetFontColor(125,23); 
    IntToAscii(s1, ComPoint);
    DrawStr(Xpos[ComCardNumber-1]+28, ComStartY+15, s1);
    IntToAscii(s2, ManPoint);
     DrawStr(Xpos[ManCardNumber-1]+28, ManStartY+15, s2);
    SetFontColor(3,0);   // black, white

    SetMediaSize(s1, 0);  // 메모리 해제? 메모리 누수가 어디에서???
    SetMediaSize(s2, 0);  // 메모리 해제? 메모리 누수가 어디에서???
 
    SetFontColor(0,23);  
    switch(Winner) {
        case ALL:
            DrawStr(15, ComStartY+42, WinText[0]);
            Money += Bet; // 배팅금 회수
            break;
        case PLAYER:
            DrawStr(15, ComStartY+42, WinText[1]);
            Money += (d ? (Bet*3) : (Bet*2));
            break;
        case DEALER:
            DrawStr(15, ComStartY+42, WinText[2]);
            Money -= d ? Bet : 0;
    }
    SetFontColor(3,0); 
    Flush();

    if(Money < 1) {             // 돈이 없으면 게임오버
        GameOver();
    } else { 
        --Money;                // 배팅액 1 지불하고 다시 시작  
        Bet = 1;
        SetTimer(2000, S_TM_ONCE);
    }
}

//***************************************************************
// 게임 종료...
//-----------------------
void GameOver()
{
    int i;

    GameProcess = GAMEOVER;

    ClearWhite();
    DrawStr(30,40,"게임 종료!!");    
    Flush();

    for(i=0; i < 8; i++) {   // 끝날 때 심심하니까...
        DrawManCard(i, NO, YES);
  DrawManCard(i, YES, YES); 
 }
}

//***************************************************************
// 키 이벤트 처리
//--------------------------
void EVENT_KEYPRESS()
{
    if (GameProcess==HELP) {
        Start();
    } else if (GameProcess == START) {
        switch (swData) {
            case SWAP_KEY_UP:       // 위 키  (배팅액 증가)
                if (Money > 0 && Bet < 10) {
                    Bet++;
                    Money++;
                    DrawMoney();
                }
                break;
            case SWAP_KEY_DOWN:     // 아래 키 (배팅액 감소)
                if (Bet > 1) {
                    Bet--;
                    Money++;
                    DrawMoney();
                }
                break;
            case SWAP_KEY_LEFT:     // 왼쪽 키 
            case SWAP_KEY_RIGHT:    // 오른쪽 키 
                AddManCard(YES);
                Play();
        }
    } else if (GameProcess == PLAY) {
        switch (swData) {
            case SWAP_KEY_RIGHT:    // 오른쪽 키 (계산)
                if (Bet != 0) {
                    StageProcess |= MAN_END;
                    Play();
                }    
                break;
            case SWAP_KEY_LEFT:     // 왼쪽 키 (카드 한 장 더)
                AddManCard(YES);
                Play();
        }
    }
    else if (GameProcess==GAMEOVER) {
        Exit(); 
    }
}

//***************************************************************
// 이벤트 타임아웃  처리 함수
//------------------------------
void EVENT_TIMEOUT()
{
    switch(GameProcess) {
        case HELP:
        case WINNER:
            Start();
            break;
        case GAMEOVER:
            Exit();
    }
}
 
//***************************************************************
// 메인 함수
//-------------------------------

void main()
{
    Init();                     // 게임 초기 설정
    Help();                     // 도움말 출력  
}


// 소스 끝

반응형

+ Recent posts