본문 바로가기
WinAPI

[Win API] 오목게임

by 코모's 2020. 4. 8.
반응형

NJ_OhMock.exe
0.10MB

 

// WinStudy_20200407_4.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//
 
#include "framework.h"
#include "WinStudy_20200407.h"
 
#define MAX_LOADSTRING 100
 
// 전역 변수:
HINSTANCE hInst;                                // 현재 인스턴스입니다.
WCHAR szTitle[MAX_LOADSTRING];                  // 제목 표시줄 텍스트입니다.
WCHAR szWindowClass[MAX_LOADSTRING];            // 기본 창 클래스 이름입니다.
 
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
 
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: 여기에 코드를 입력합니다.
 
    // 전역 문자열을 초기화합니다.
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINSTUDY20200407, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
 
    // 애플리케이션 초기화를 수행합니다:
    if (!InitInstance(hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINSTUDY20200407));
 
    MSG msg;
 
    // 기본 메시지 루프입니다:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int)msg.wParam;
}
 
 
 
//
//  함수: MyRegisterClass()
//
//  용도: 창 클래스를 등록합니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINSTUDY20200407));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(70, 140, 255));      //(HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINSTUDY20200407);
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassExW(&wcex);
}
 
class Stone
{
public:
    int Type = 0;//0이면 빈자리 1이면 흑돌 2이면 백돌
    int XX = 0;
    int YY = 0;
};
 
Stone S_List[18][18];
 
HBRUSH Pan = NULL;
HPEN Line = NULL;
 
HBRUSH White = NULL;
HBRUSH Black = NULL;
 
HFONT MyFont = NULL;
 
int sx = 0, sy = 0;
int count = 0;
int b = 0, w = 0;
 
bool BlackTurn = false;
bool GameOver = false;
 
int BlackWin = 0;
int WiteWin = 0;
 
 
void InitGame()
{
    Pan = (HBRUSH)CreateSolidBrush(RGB(220, 179, 92));
    Line = (HPEN)CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
 
    White = (HBRUSH)CreateSolidBrush(RGB(255, 255, 255));
    Black = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
 
    MyFont = CreateFont(30, 0, 0, 0, 0, 0, 0, 0, HANGEUL_CHARSET,
        0, 0, 0, VARIABLE_PITCH | FF_ROMAN, _T("굴림"));
    for (int i = 0; i < 19; i++)//초기화
    {
        for (int j = 0; j < 19; j++)
        {
            S_List[i][j].Type = 0;
            S_List[i][j].XX = 80 + i * 40;
            S_List[i][j].YY = 80 + j * 40;
        }
    }
}
 
void EndGame()
{
    if (Pan != NULL)
    {
        DeleteObject(Pan);
        Pan = NULL;
    }
    if (Line != NULL)
    {
        DeleteObject(Line);
        Line = NULL;
    }
    if (White != NULL)
    {
        DeleteObject(White);
        White = NULL;
    }
    if (Black != NULL)
    {
        DeleteObject(Black);
        Black = NULL;
    }
    if (MyFont != NULL)
    {
        DeleteObject(MyFont);
        MyFont = NULL;
    }
}
void Win()
{
    for (int i = 0; i < 19; i++)
    {
        for (int j = 0; j < 19; j++)
        {
            //흑돌 가로
            if (S_List[i][j].Type == 1 &&
                S_List[i + 1][j].Type == 1 &&
                S_List[i + 2][j].Type == 1 &&
                S_List[i + 3][j].Type == 1 &&
                S_List[i + 4][j].Type == 1)
            {
                GameOver = true;
            }
            //백돌 가로
            if (S_List[i][j].Type == 2 &&
                S_List[i + 1][j].Type == 2 &&
                S_List[i + 2][j].Type == 2 &&
                S_List[i + 3][j].Type == 2 &&
                S_List[i + 4][j].Type == 2)
            {
                GameOver = true;
            }
            //흑돌 세로
            if (S_List[i][j].Type == 1 &&
                S_List[i][j + 1].Type == 1 &&
                S_List[i][j + 2].Type == 1 &&
                S_List[i][j + 3].Type == 1 &&
                S_List[i][j + 4].Type == 1)
            {
                GameOver = true;
            }
            //백돌 세로
            if (S_List[i][j].Type == 2 &&
                S_List[i][j + 1].Type == 2 &&
                S_List[i][j + 2].Type == 2 &&
                S_List[i][j + 3].Type == 2 &&
                S_List[i][j + 4].Type == 2)
            {
                GameOver = true;
            }
            //흑돌 왼->오 대각선
            if (S_List[i][j].Type == 1 &&
                S_List[i + 1][j + 1].Type == 1 &&
                S_List[i + 2][j + 2].Type == 1 &&
                S_List[i + 3][j + 3].Type == 1 &&
                S_List[i + 4][j + 4].Type == 1)
            {
                GameOver = true;
            }
            //백돌 왼->오 대각선
            if (S_List[i][j].Type == 1 &&
                S_List[i + 1][j + 1].Type == 1 &&
                S_List[i + 2][j + 2].Type == 1 &&
                S_List[i + 3][j + 3].Type == 1 &&
                S_List[i + 4][j + 4].Type == 1)
            {
                GameOver = true;
            }
            //흑돌 오->왼 대각선
            if (S_List[i + 4][j].Type == 1 &&
                S_List[i + 3][j + 1].Type == 1 &&
                S_List[i + 2][j + 2].Type == 1 &&
                S_List[i + 1][j + 3].Type == 1 &&
                S_List[i][j + 4].Type == 1)
            {
                GameOver = true;
            }
            //백돌 오->왼 대각선
            if (S_List[i + 4][j].Type == 1 &&
                S_List[i + 3][j + 1].Type == 1 &&
                S_List[i + 2][j + 2].Type == 1 &&
                S_List[i + 1][j + 3].Type == 1 &&
                S_List[i][j + 4].Type == 1)
            {
                GameOver = true;
            }
 
        }
        
    }
    
}
 
void Clear()
{
    for (int i = 0; i < 19; i++)
    {
        for (int j = 0; j < 19; j++)
        {
            S_List[i][j].Type = 0;            
        }
    }
}
 
//
//   함수: InitInstance(HINSTANCE, int)
//
//   용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
//   주석:
//
//        이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
//        주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
 
    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        100, 100, 900, 900, nullptr, nullptr, hInstance, nullptr);
 (윈도우 크기)
    if (!hWnd)
    {
        return FALSE;
    }
 
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    return TRUE;
}
 
 
 
//
//  함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  용도: 주 창의 메시지를 처리합니다.
//
//  WM_COMMAND  - 애플리케이션 메뉴를 처리합니다.
//  WM_PAINT    - 주 창을 그립니다.
//  WM_DESTROY  - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        InitGame();
        break;
 
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // 메뉴 선택을 구문 분석합니다:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;
 
    case WM_LBUTTONDOWN:
    {
        sx = LOWORD(lParam);
        sy = HIWORD(lParam);  //마우스 왼쪽 버튼 클릭시 마우스 좌표를 얻어오는 방법       
 
        if (sx > 30 && sx < 30 + 19 * 40)//게임판 안을 클릭했을때만 발생
        {
            if (sy > 30 && sy < 30 + 19 * 40)
            {
                for (int i = 0; i < 19; i++)
                {
                    int X = (sx - 50) / 40; //첫번째 선의 위치 = 50, 선마다 간격 = 40
                    int Y = (sy - 50) / 40;
                    if (S_List[X][Y].Type == 0)
                    {
                        if (BlackTurn == true)
                            S_List[X][Y].Type = 1;
                        else
                            S_List[X][Y].Type = 2;
                    }
                }
            }
        }
        InvalidateRect(hWnd, NULL, TRUE);//강제로 WM_PAINT 메시지를 발생시켜주는 함수
        count++;
    }
    break;
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
 
        HPEN OldPen = (HPEN)SelectObject(hdc, Line);
        HBRUSH OldBrush = (HBRUSH)SelectObject(hdc, Pan);
        HFONT OldFont = (HFONT)SelectObject(hdc, MyFont);
 
        SelectObject(hdc, OldPen);
        Rectangle(hdc, 50, 50, 50 + 740, 50 + 740);//판그리기
 
        SelectObject(hdc, OldBrush);
 
        RECT Rect;
        GetClientRect(hWnd, &Rect);
 
        OldPen = (HPEN)SelectObject(hdc, Line);
        //가로줄
        for (int i = 40; i < 750; i = i + 40)
        {
            MoveToEx(hdc, 40 + 40, 40 + i, NULL);
            LineTo(hdc, 40 + 750 - 30, 40 + i);
        }
 
        //세로줄
        for (int i = 40; i < 750; i = i + 40)
        {
            MoveToEx(hdc, 40 + i, 40 + 40, NULL);
            LineTo(hdc, 40 + i, 40 + 750 - 30);
        }
 
        SetBkMode(hdc, TRANSPARENT); //<--글씨 배경을 빼는 방법
        TCHAR a_TempStr[128];
        if (BlackTurn == false)
        {
            SetTextColor(hdc, RGB(0, 0, 0)); //<--글씨색 바꾸기
            _stprintf_s(a_TempStr, _T("흑돌차례입니다."));
            TextOut(hdc, 50, 5, a_TempStr, _tcslen(a_TempStr));
        }
        else
        {
            SetTextColor(hdc, RGB(255, 255, 255)); //<--글씨색 바꾸기
            _stprintf_s(a_TempStr, _T("백돌차례입니다."));
            TextOut(hdc, 50, 5, a_TempStr, _tcslen(a_TempStr));
        }
 
        //점수판
        TCHAR Score[128];
        SetTextColor(hdc, RGB(255, 255, 0)); //<--글씨색 바꾸기
        _stprintf_s(Score, _T("흑돌(%d : %d)백돌"), BlackWin, WiteWin);
        TextOut(hdc, 400, 5, Score, _tcslen(Score));
 
 
        SelectObject(hdc, OldPen);
        SelectObject(hdc, OldFont);
 
        if (count % 2 == 1)
            BlackTurn = false;
        else
            BlackTurn = true;
 
 
        //돌그리기
        if (count >= 1)
        {
            for (int i = 0; i < 19; i++)
            {
                for (int j = 0; j < 19; j++)
                {
                    if (S_List[i][j].Type <= 0)
                        continue;
                    else if (S_List[i][j].Type == 1)//흑돌
                        SelectObject(hdc, Black);
                    else if (S_List[i][j].Type == 2)//백돌
                        SelectObject(hdc, White);
 
                    Ellipse(hdc, S_List[i][j].XX - 15, S_List[i][j].YY - 15, S_List[i][j].XX + 15, S_List[i][j].YY + 15);
 
                }
            }
        }
        Win();//승리체크
 
        if (GameOver == true)
        {
            if (BlackTurn == true)
            {
                TCHAR winner[15];
                _stprintf_s(winner, _T("백돌이 승리하였습니다."));
                MessageBoxW(hWnd, winner, _T("승리"), MB_OK);
                WiteWin++;
            }
            else
            {
                TCHAR winner[15];
                _stprintf_s(winner, _T("흑돌이 승리하였습니다."));
                MessageBoxW(hWnd, winner, _T("승리"), MB_OK);
                BlackWin++;
            }
 
            GameOver = false;
            Clear();
            InvalidateRect(hWnd, NULL, TRUE);//강제로 WM_PAINT 메시지를 발생시켜주는 함수
            count++;
        }
 
 
        EndPaint(hWnd, &ps);
    }
    break;
    case WM_DESTROY:
        EndGame();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
반응형

'WinAPI' 카테고리의 다른 글

[Win API] bmp파일로드 + 움직이기(드래그)  (0) 2020.04.09