순천향대학교컴퓨터학부이상정 1 학습내용 단순오목게임 인터넷오목게임 승부판정오목게임 순천향대학교컴퓨터학부이상정 2
단순오목게임 순천향대학교컴퓨터학부이상정 3 예제 49: 단순오목게임 스크린에바둑판을그리고, 스크린을터치하면해당위치에흰돌또는검은돌만표시 승부는판정하지않음 메뉴 ID_START, ID_EXIT 순천향대학교컴퓨터학부이상정 4
예제 49: 코드 (1) #define MAXLINE 19 // 바둑판줄수 #define DELTALINE 12 // 바둑판줄간격 #define STARTX 10 // 바둑판시작 X 좌표 #define STARTY 60 // 바둑판시작 Y 좌표 HBRUSH WhiteBrush, BlackBrush; enum SITE NONE, BLACK, WHITE ; SITE Board[MAXLINE-2][MAXLINE-2]; BOOL WhTurn = FALSE; // 흰돌, 검은돌브러시 // 바둑돌없음, 검은돌, 휜돌 // 바둑판상태배열 // 다음둘차례, TRUE: 흰돌, FALSE: 검은돌 void InitOmok(); void LbuttonDownEvent(HWND hwnd, int x, int y); void DrawOmok(HWND hwnd); void DrawSite(HWND hwnd, int x, int y, SITE dol); // 오목게임초기화 // 스크린터치이벤트함수 // 바둑판과돌화면에표시 // 바둑돌표시 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) switch (message) case WM_LBUTTONDOWN: LbuttonDownEvent(hWnd, LOWORD(lParam), HIWORD(lParam)); 순천향대학교컴퓨터학부이상정 5 예제 49: 코드 (2) case WM_LBUTTONDOWN: LbuttonDownEvent(hWnd, LOWORD(lParam), HIWORD(lParam)); case WM_COMMAND: wmid = LOWORD(wParam); wmevent = HIWORD(wParam); switch (wmid) case ID_START: /// 오목게임초기화 InitOmok(); InvalidateRect(hWnd, NULL, TRUE); case ID_EXIT: /// 게임종료 MessageBox(hWnd,L"Game is over!!", L"", NULL); SendMessage(hWnd, WM_CLOSE, 0, 0); case IDM_HELP_ABOUT: 순천향대학교컴퓨터학부이상정 6
예제 49: 코드 (3) case WM_CREATE: /// 오목초기화 InitOmok(); g_hwndcommandbar = CommandBar_Create(g_hInst, hwnd, 1); CommandBar_InsertMenubar(g_hWndCommandBar, g_hinst, IDR_MENU1, 0); CommandBar_AddAdornments(g_hWndCommandBar, 0, 0); case WM_PAINT: hdc = BeginPaint(hWnd, &ps); /// 바둑판화면에표시 DrawOmok(hWnd); EndPaint(hWnd, &ps); 순천향대학교컴퓨터학부이상정 7 예제 49: 코드 (4) /// 오목초기화 void InitOmok() // 브러시생성 WhiteBrush = CreateSolidBrush(RGB(255,255,255)); BlackBrush = CreateSolidBrush(RGB(0,0,0)); 0 0)); // 바둑판상태배열초기화 for (int x = 0; x < MAXLINE-2; x++) for (int y = 0; y < MAXLINE-2; y++) Board[x][y] = NONE; /// 스크린터치이벤트함수 void LbuttonDownEvent(HWND hwnd, int x, int y) int ix, iy; // 바둑판상태배열인덱스 ix = (x-startx) / DELTALINE; iy = (y-starty) / DELTALINE; // 경계범위위반조사 if (ix < 0 ix >= MAXLINE-2 iy < 0 iy >= MAXLINE-2 ) return; 순천향대학교컴퓨터학부이상정 8
예제 49: 코드 (5) if (Board[ix][iy] == NONE) // 해당위치에돌이없으면 // 다음돌선택하고화면에표시 Board[ix][iy] = WhTurn? WHITE : BLACK; DrawSite(hWnd, ix, iy, Board[ix][iy]); // 돌차례바꿈 WhTurn =!WhTurn; /// 바둑판과돌화면에표시 void DrawOmok(HWND hwnd) HDC hdc = GetDC(hWnd); int px, py, endx, endy; int deltax, deltay; // 선간격, 끝좌표지정 deltax = deltay = DELTALINE; endx = STARTX +(MAXLINE-1)*deltaX; endy = STARTY + (MAXLINE-1)*deltaY; 순천향대학교컴퓨터학부이상정 9 예제 49: 코드 (6) // 가로줄표시 for (int y = 0; y < MAXLINE; y++) py = STARTY + y*deltay; // 그려질 y 좌표 MoveToEx(hdc, STARTX, py, NULL); LineTo(hdc, endx, py); // 세로줄표시 for (int x= 0; x < MAXLINE; x++) px = STARTX + x*deltax; // 그려질 x 좌표 MoveToEx(hdc, px, STARTY, NULL); LineTo(hdc, px, endy); // 바둑돌표시 for (int x = 0; x < MAXLINE-2; x++) for (int y=0; y < 19; y++) DrawSite(hWnd, x, y, Board[x][y]); 순천향대학교컴퓨터학부이상정 10
예제 49: 코드 (7) /// 바둑돌표시 void DrawSite(HWND hwnd, int x, int y, SITE dol) HDC hdc = GetDC(hWnd); int px, py; // 타원시작점 px = STARTX+x*DELTALINE+DELTALINE/2+1; py = STARTY+y*DELTALINE+DELTALINE/2+1; if (dol!= NONE) // 돌이없으면 if (dol == BLACK) // 검은돌 SelectObject(hdc, BlackBrush); Ellipse(hdc, px, py, px+deltaline-2, py+deltaline-2); DeleteObject(BlackBrush); else // 흰돌 SelectObject(hdc, WhiteBrush); Ellipse(hdc, px, py, px+deltaline-2, py+deltaline-2); DeleteObject(WhiteBrush); 순천향대학교컴퓨터학부이상정 11 인터넷오목게임 순천향대학교컴퓨터학부이상정 12
예제 50: 인터넷오목게임 예제 49 의단순오목게임을수정하여인터넷에연결하여상대방과오목게임 기존의오프라인게임에네트워크게임기능추가 네트워크게임메뉴 ID_SERVER: 서버, 흰돌 ID_CONNECT: 클라이언트, 검은돌, 연결요청시작 ID_STOP: 네트워크게임중지 에디트, 버튼컨트롤 ID_IP, ID_PORT: IP 주소, 포트번호 ID_BUTTON: 연결버튼 클라이언트로동작시화면에표시 PC 용으로실행시에는일부수정 MyRegisterClass() 함수에서 IDR_MENU1 메뉴로드 바둑판크기, DELTALINE 20 create_gui() 함수에서 CreateWindow() 함수매개변수 hinst #pragma comment(lib,"ws2_32.lib") 순천향대학교컴퓨터학부이상정 13 예제 50: 실행결과 (1) PC 는서버, 실습보드는클라이언트로동작하는예 순천향대학교컴퓨터학부이상정 14
예제 50: 실행결과 (2) 순천향대학교컴퓨터학부이상정 15 예제 50: 서버동작 WM_CREATE 메시지에서 initwinsock() 호출하여윈속초기화 서버동작 메뉴 ID_SERVER 에서서버쓰레드함수 ServerStart() 생성하고실행 ServerStart() 쓰레드함수 서버소켓생성, socket() 주소 / 포트연결지정, bind() 클라이언트접속대기, listen() 클라이언트접속, accept() 바둑판그림, InvalidateRect() 데이터수신쓰레드함수 ReceiveData() 실행 ReceiveData() 쓰레드함수 recv() 함수사용하여상대방의바둑돌 x,,y 좌표수신 Drawsite() 호출하여바둑판에표시 순천향대학교컴퓨터학부이상정 16
예제 50: 클라이언트동작 클라이언트동작 ID_CONNECT 메뉴에서 create_gui() 함수호출 create_gui() 함수 IP, 포트에디트컨트롤, 연결버튼생성하고화면에표시 ID_BUTTON 메뉴에서 ConnectClick() 함수호출 Connect() 함수호출하여서버에연결요청 Connect() 함수 소켓생성, socket() 접속할서버주소 / 포트지정및연결, connect() 데이터수신쓰레드함수 ReceiveData() 실행 메인윈도우에서버튼, 에디트컨트롤제거 바둑판그림, InvalidateRect() 순천향대학교컴퓨터학부이상정 17 예제 50: 데이터송신 WM_LBUTTONDOWN 메시지에서 LbuttonDownEvent() 함수호출 LbuttonDownEvent() 함수 바둑돌위치계산하고 Drawsite() 호출하여바둑판에표시 네트워크연결이면 SendData() 함수호출하여위치 x, y 송신 SendData() 함수 send() 함수사용하여바둑돌 x, y 좌표를상대방에게송신 순천향대학교컴퓨터학부이상정 18
예제 50: 코드 ATOM MyRegisterClass(HINSTANCE hinstance, LPTSTR szwindowclass) /// ATOM MyRegisterClass(HINSTANCE hinstance) wc.lpszmenuname = 0; /// wcex.lpszmenuname = MAKEINTRESOURCE(IDR_MENU1); MENU1); // PC 용 //// 오목관련선언 #define MAXLINE 19 // 바둑판줄수 #define DELTALINE 12 // 바둑판줄간격 /// #define DELTALINE 20 // PC 용 #define STARTX 10 // 바둑판시작 X 좌표 #define STARTY 60 // 바둑판시작 Y 좌표 HBRUSH WhiteBrush, BlackBrush; enum SITE NONE, BLACK, WHITE ; SITE Board[MAXLINE-2][MAXLINE-2]; bool WhTurn = false; // 흰돌, 검은돌브러시 // 바둑돌없음, 검은돌, 휜돌 // 바둑판상태배열 // 다음둘차례, true: 흰돌, false: 검은돌 void InitOmok(); void LbuttonDownEvent(HWND hwnd, int x, int y); void DrawOmok(HWND hwnd); void DrawSite(HWND hwnd, int x, int y, SITE dol); 순천향대학교컴퓨터학부이상정 19 // 오목게임초기화 // 스크린터치이벤트함수 // 바둑판과돌화면에표시 // 바둑돌표시 예제 50: 코드 //// 네트워크관련선언 #include <Winsock2.h> #pragma comment(lib,"ws2.lib") // #pragma comment(lib,"ws2_32.lib") #define ID_IP IP 500 #define ID_PORT 501 #define ID_BUTTON 502 HWND hip, hport, hconnect; // 컨트롤핸들 HANDLE hserverthread, hrecvthread; // 쓰레드핸들 bool IsGameStart = false; // true: 게임시작하여진행중 WCHAR szip[20], szport[20]; // 에디트컨트롤버퍼 bool IsConnected = false, // 연결상태표시플래그 IsClient = false; // 클라이언트로실행중임을표시 SOCKET server, client; // 소켓 bool initwinsock(); void create_gui(hwnd hwnd); void ConnectClick(HWND hwnd); bool Connect(HWND hwnd); DWORD WINAPI ServerStart(LPVOID pdata); DWORD WINAPI ReceiveData(LPVOID pdata); void SendData(int x, int y); void NetworkStop(); 순천향대학교컴퓨터학부이상정 20 // 윈속초기화 // 에디트컨트롤, 버튼생성 // Connect 버튼클릭함수 // 서버에연결요청함수 // 채팅서버시작쓰레드함수 // 메시지수신쓰레드함수 // 데이터송신함수 // 네트워크중지함수
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) int wmid, wmevent; PAINTSTRUCT ps; HDC hdc; switch (message) case WM_LBUTTONDOWN: if (IsGameStart == true) // 게임진행중이면 LbuttonDownEvent(hWnd, LOWORD(lParam), HIWORD(lParam)); case WM_COMMAND: wmid = LOWORD(wParam); wmevent = HIWORD(wParam); switch (wmid) case ID_START: /// 오목초기화 InitOmok(); IsGameStart = true; InvalidateRect(hWnd, NULL, true); 순천향대학교컴퓨터학부이상정 21 // 게임시작 case ID_EXIT: /// 게임종료 MessageBox(hWnd,L"Game is over!!", L"", NULL); SendMessage(hWnd, WM_CLOSE, 0, 0); case ID_SERVER: // 서버시작 /// 서버쓰레드생성하고실행 hserverthread = CreateThread(NULL, 0, ServerStart,(PVOID)hWnd, 0, NULL); case ID_CONNECT: /// GUI 표시후연결요청 /// GUI 컨트롤생성 create_gui(hwnd); case ID_BUTTON: // Connect 버튼 // 버튼클릭함수호출 ConnectClick(hWnd); case ID_IP: // IP 주소 if (wmevent == EN_CHANGE) GetWindowText(hIP, szip, 20); case ID_PORT: // 포트번호 if (wmevent == EN_CHANGE) GetWindowText(hPort, szport, 20); case ID_STOP: NetworkStop(); // 네트워크중지함수 MessageBox(hWnd,L"Game is over!!", L"", NULL); SendMessage(hWnd, WM_CLOSE, 0, 0); case IDM_HELP_ABOUT: 순천향대학교컴퓨터학부이상정 22
임베디드 case 소프트웨어 WM_CREATE: /// 오목초기화 InitOmok(); /// 윈속초기화 if (initwinsock() == false) return 0; g_hwndcommandbar = CommandBar_Create(g_hInst, hwnd, 1); CommandBar_InsertMenubar(g_hWndCommandBar, g_hinst, IDR_MENU1, 0); CommandBar_AddAdornments(g_hWndCommandBar, 0, 0); case WM_PAINT: hdc = BeginPaint(hWnd, &ps); /// 오목판그림 if (IsGameStart == true) DrawOmok(hWnd); EndPaint(hWnd, &ps); //////// 오목관련루틴 /// 오목초기화 void InitOmok() WhiteBrush = CreateSolidBrush(RGB(255,255,255)); BlackBrush = CreateSolidBrush(RGB(0,0,0)); for (int x = 0; x < MAXLINE-2; x++) for (int y = 0; y < MAXLINE-2; y++) Board[x][y] = NONE; 순천향대학교컴퓨터학부이상정 23 /// 스크린터치이벤트함수 void LbuttonDownEvent(HWND hwnd, int x, int y) int ix, iy; ix = (x-startx) / DELTALINE; iy = (y-starty) / DELTALINE; // 경계범위조사 if (ix < 0 ix >= MAXLINE-2 iy < 0 iy >= MAXLINE-2) return; if (Board[ix][iy] == NONE) // 다음돌표시하고화면표시 Board[ix][iy] = WhTurn? WHITE : BLACK; DrawSite(hWnd, ix, iy, Board[ix][iy]); if (IsConnected!= true) // 차례바꿈 WhTurn =!WhTurn; else // 네트워크연결이면 SendData(ix,iy); // 네트워크연결이아니면 /// 바둑판과돌화면에표시 void DrawOmok(HWND hwnd) HDC hdc = GetDC(hWnd); int px, py, endx, endy; int deltax, deltay; 순천향대학교컴퓨터학부이상정 24
임베디드 // 선소프트웨어간격, 끝좌표지정 deltax = deltay = DELTALINE; endx = STARTX + (MAXLINE-1)*deltaX; endy = STARTY + (MAXLINE-1)*deltaY; // 가로줄표시 for (int y = 0; y < MAXLINE; y++) py = STARTY + y*deltay; // 그려질 y 좌표 MoveToEx(hdc, STARTX, py, NULL); LineTo(hdc, endx, py); // 세로줄표시 for (int x= 0; x < MAXLINE; x++) px = STARTX + x*deltax; MoveToEx(hdc, px, STARTY, NULL); LineTo(hdc, px, endy); // 바둑돌표시 for (int x = 0; x < MAXLINE-2; x++) for (int y=0; y < MAXLINE-2; y++) DrawSite(hWnd, x, y, Board[x][y]); /// 바둑돌그림 void DrawSite(HWND hwnd, int x, int y, SITE dol) HDC hdc = GetDC(hWnd); int px, py; // 그려질 x 좌표 // 타원시작점 px = STARTX+x*DELTALINE+DELTALINE/2+1; py = STARTY+y*DELTALINE+DELTALINE/2+1; 순천향대학교컴퓨터학부이상정 25 if (dol!= NONE) // 돌이없으면 if (dol == BLACK) // 검은돌 SelectObject(hdc, BlackBrush); Ellipse(hdc, px, py, px+deltaline-2, py+deltaline-2); DeleteObject(BlackBrush); else // 흰돌 SelectObject(hdc, WhiteBrush); Ellipse(hdc, px, py, px+deltaline-2, py+deltaline-2); DeleteObject(WhiteBrush); //////////////////////////////////// //////// 네트워크관련루틴 /// 윈속초기화 bool initwinsock() WSADATA wsadata; int retval; retval = WSAStartup(MAKEWORD(2,2), ( &wsadata); if (retval!= 0) MessageBox(NULL,L"WSAStartup Fail",L"", MB_ICONERROR); return false; return true; 순천향대학교컴퓨터학부이상정 26
임베디드 void create_gui(hwnd 소프트웨어 hwnd) // 에디트컨트롤생성 hip = CreateWindow(L"edit", edit, NULL, WS_CHILD WS_BORDER WS_VISIBLE, 10, 40, 120, 20, hwnd, (HMENU)ID_IP, g_hinst, NULL); hport = CreateWindow(L"edit", NULL, WS_CHILD WS_BORDER WS_VISIBLE, 150, 40, 50, 20, hwnd, (HMENU)ID_PORT, g_hinst, NULL); // 버튼생성 hconnect = CreateWindow(L"button", L"Connect", WS_CHILD WS_VISIBLE BS_PUSHBUTTON, 10, 65, 120, 20, hwnd, (HMENU)ID_BUTTON, g_hinst, NULL); /// 채팅서버시작, 클라이언트의접속을받고, 메시지를수신 DWORD WINAPI ServerStart(LPVOID pdata) sockaddr_in addr; int retval; HWND hwnd = (HWND)pData; /// 서버소켓생성 server = socket(af_inet, SOCK_STREAM, 0); if (server == INVALID_SOCKET) MessageBox(hWnd,L"SocketCreate Fail",L"", MB_ICONERROR); return 0; /// 주소 / 포트지정및연결 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(inaddr_any); // 서버의 IP 주소 addr.sin_port = htons(7000); // 서버포트를 7000으로지정 retval = bind(server, (struct sockaddr *)&addr, sizeof(addr)); 순천향대학교컴퓨터학부이상정 27 임베디드 if (retval 소프트웨어 == SOCKET_ERROR) MessageBox(hWnd,L"Bind Fail",L"", MB_ICONERROR); return 0; /// 클라이언트접속대기 retval = listen(server, SOMAXCONN); // 클라이언트개수를최대로설정 if (retval == SOCKET_ERROR) ERROR) MessageBox(hWnd,L"Listen Fail",L"", MB_ICONERROR); return 0; /// 메시지출력 MessageBox(hWnd,L"Server Start... r n",l"", MB_OK); /// 클라이언트접속 sockaddr_in client_addr; int addrlen; addrlen = sizeof(client_addr); client = accept(server, (struct sockaddr *)&client_addr, &addrlen); if (client == INVALID _ SOCKET) ) MessageBox(hWnd,L"Accept Fail",L"", MB_ICONERROR); return 0; IsConnected = true; /// 접속한클라이언트 IP 주소출력 CHAR bip[50]; WCHAR ip[50], szmsg[80]; strcpy(bip, inet_ntoa(client_addr.sin_addr)); // 숫자 IP주소를문자열로변환 mbstowcs(ip, bip, strlen(bip)+1); // ASCII 문자를유니코드로변환 wsprintf(szmsg, L"Start game with IP %s r n", ip); 순천향대학교컴퓨터학부이상정 28
MessageBox(hWnd,szMsg, L"", MB_OK); // 바둑판그림 IsGameStart = true; WhTurn = true; // 서버는흰돌 InvalidateRect(hWnd, NULL, true); /// Receive 쓰레드생성및실행 hrecvthread = CreateThread(NULL, 0, ReceiveData,(PVOID)hWnd, 0, NULL); return 0; /// Connect 버튼클릭함수 void ConnectClick(HWND hwnd) if (IsClient == false) // 서버에접속할경우 if (Connect(hWnd)( == false) // 서버에연결요청 MessageBox(hWnd,L"Connect Fail",L"", MB_ICONERROR); else IsClient = true; else // 이미접속된경우 MessageBox(hWnd,L"Already connected",l"", MB_ICONERROR); 순천향대학교컴퓨터학부이상정 29 // 서버에연결요청함수 bool Connect(HWND hwnd) sockaddr_in serveraddr; CHAR bip[20]; int retval, port; /// 소켓생성 client = socket(af_inet, SOCK_STREAM, 0); if (client == INVALID_SOCKET) return false; /// 접속할서버주소 / 포트지정및연결 wcstombs(bip, szip, wcslen(szip)+1); // 유니코드를 ASCII 문자로변환 port = _wtoi(szport); // 포트번호문자열을정수로변환 memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_ addr.s_ addr = inet_ addr(bip); // 서버의 IP 주소 serveraddr.sin_port = htons(port); // 포트번호 retval = connect(client, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); if (retval == SOCKET_ERROR) return false; IsConnected = true; /// Receive 쓰레드생성및실행 hrecvthread = CreateThread(NULL, 0, ReceiveData,(PVOID)hWnd, 0, NULL); 순천향대학교컴퓨터학부이상정 30
/// 버튼, 에디트제거 DestroyWindow(hIP); DestroyWindow(hPort); DestroyWindow(hConnect); /// 메시지출력 MessageBox(hWnd,L"Start game r n",l"", MB_OK); /// 바둑판그림 IsGameStart = true; WhTurn = false; // 클라이언트는검은돌 InvalidateRect(hWnd, NULL, true); return true; /// 데이터송신함수 void SendData(int x, int y) CHAR ix[4], iy[4]; *(UINT *)ix = htonl(x); () // host-to-network 바이트변환 send(client, ix, 4, 0); // x 데이터송신 *(UINT *)iy = htonl(y); // host-to-network 바이트변환 send(client, iy, 4, 0); // x 데이터송신 순천향대학교컴퓨터학부이상정 31 /// 메시지수신쓰레드함수 DWORD WINAPI ReceiveData(LPVOID pdata) CHAR ix[4], iy[4]; int x, y, size; HWND hwnd = (HWND)pData; // 핸들인수 while (IsConnected == true) // x 데이터수신 size = recv(client, ix, 4, 0); // x 데이터수신 if (size!= SOCKET_ERROR) x = ntohl(*(uint *)ix); // nework-to-host 바이트변환 // y 데이터수신 recv(client, iy, 4, 0); // x 데이터수신 if (size!= SOCKET_ERROR) y = ntohl(*(uint *)iy); // nework-to-host 바이트변환 if (Board[x][y] == NONE) // 다음돌표시하고화면표시 Board[x][y] =!WhTurn? WHITE : BLACK; // 상대편돌표시 DrawSite(hWnd, x, y, Board[x][y]); [][]) return 0; 순천향대학교컴퓨터학부이상정 32
예제 50: 코드 /// 네트워크중지함수 void NetworkStop() if (IsConnected == true) // 클라이언트연결상태이면 IsConnected = false; // Receive 쓰레드종료 closesocket(client); // 소켓해제 closesocket(server); MessageBox(NULL,L"Connection is closed. r n",l"stop", MB_OK); 순천향대학교컴퓨터학부이상정 33 과제 17 예제 50 의인터넷오목게임에승부를판정하는기능을추가하여라 최근에놓인돌을기준으로같은색의돌이수직, 수평, 대각선으로 5 개연속해서놓여있는지조사 수평조사 현재위치의 x 좌표기준으로좌 (--x) x), 우 (++x) 로다른색의돌을만날때까지개수카운트하여 5개이면승리 수직조사 현재위치의 y 좌표기준으로상 (--y), 하 (++y) 로다른색의돌을만날때까지개수카운트하여 5개이면승리 대각선조사 현재위치의 x,y 좌표기준으로좌상 (--x, --y), 우하 (++x, ++y) 로다른색의돌을만날때까지개수카운트하여 5개이면승리 현재위치의 x,y 좌표기준으로좌하 (--x, ++y), 우상 (++x, --y) 로다른색의돌을만날때까지개수카운트하여 5개이면승리 순천향대학교컴퓨터학부이상정 34