-
Notifications
You must be signed in to change notification settings - Fork 0
mingcc5240/Jangki
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Korean Chess(Janki) made by Visual C++ 6.0!! ======================================================================== MICROSOFT FOUNDATION CLASS LIBRARY : Jangki ======================================================================== AppWizard has created this Jangki application for you. This application not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your application. This file contains a summary of what you will find in each of the files that make up your Jangki application. Jangki.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. Jangki.h This is the main header file for the application. It includes other project specific headers (including Resource.h) and declares the CJangkiApp application class. Jangki.cpp This is the main application source file that contains the application class CJangkiApp. Jangki.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. Jangki.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. res\Jangki.ico This is an icon file, which is used as the application's icon. This icon is included by the main resource file Jangki.rc. res\Jangki.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file. ///////////////////////////////////////////////////////////////////////////// For the main frame window: MainFrm.h, MainFrm.cpp These files contain the frame class CMainFrame, which is derived from CFrameWnd and controls all SDI frame features. res\Toolbar.bmp This bitmap file is used to create tiled images for the toolbar. The initial toolbar and status bar are constructed in the CMainFrame class. Edit this toolbar bitmap using the resource editor, and update the IDR_MAINFRAME TOOLBAR array in Jangki.rc to add toolbar buttons. ///////////////////////////////////////////////////////////////////////////// AppWizard creates one document type and one view: JangkiDoc.h, JangkiDoc.cpp - the document These files contain your CJangkiDoc class. Edit these files to add your special document data and to implement file saving and loading (via CJangkiDoc::Serialize). JangkiView.h, JangkiView.cpp - the view of the document These files contain your CJangkiView class. CJangkiView objects are used to view CJangkiDoc objects. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named Jangki.pch and a precompiled types file named StdAfx.obj. Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize. If your application uses MFC in a shared DLL, and your application is in a language other than the operating system's current language, you will need to copy the corresponding localized resources MFC42XXX.DLL from the Microsoft Visual C++ CD-ROM onto the system or system32 directory, and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation. For example, MFC42DEU.DLL contains resources translated to German.) If you don't do this, some of the UI elements of your application will remain in the language of the operating system. ///////////////////////////////////////////////////////////////////////////// // JKStage.cpp: implementation of the CJKStage class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "JKStage.h" #include <stdlib.h> #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// int CJKStage::sm_nCount; // 휴리스틱 관련 플래그 bool CJKStage::m_bPoBeforeJang; bool CJKStage::m_bJolToCenter; bool CJKStage::m_bCHAPOBalance; bool CJKStage::m_bAggressivePO; bool CJKStage::m_bAggressiveCHA; bool CJKStage::m_bAggressiveJOL; bool CJKStage::m_bAggressiveSANG; bool CJKStage::m_bAggressiveMA; bool CJKStage::m_bOnlyJangCenter; CHistoryStack CJKStage::m_cHistoryStack; CJKStage::CJKStage() { ::srand( (unsigned)time( NULL ) ); Initialize(); } CJKStage::CJKStage(CJKStage * pParentStage) { m_pFirst = NULL; m_pSelectedChild = NULL; m_nDepth = pParentStage->m_nDepth + 1; m_enTeam = pParentStage->m_enTeam == TM_HAN ? TM_CHO : TM_HAN; m_bAmIMax = !pParentStage->IsMaxTurn(); ::memcpy(m_enPanel,pParentStage->m_enPanel,sizeof(m_enPanel)); // GetCHAPOCount(); } void CJKStage::GetCHAPOCount() { // if ( !m_bCHAPOBalance ) return; m_nHANChaCount = 0; m_nHANPoCount = 0; m_nCHOChaCount = 0; m_nCHOPoCount = 0; for ( int x,y = 0; y < DF_PANEL_HEIGHT; ++ y ) for ( x = 0; x < DF_PANEL_WIDTH; ++ x ) { switch ( m_enPanel[y][x] ) { case PS_HAN_CHA : ++ m_nHANChaCount; case PS_HAN_PO : ++ m_nHANPoCount; case PS_CHO_CHA : ++ m_nCHOChaCount; case PS_CHO_PO : ++ m_nCHOPoCount; } } } CJKStage::~CJKStage() { ClearList(); if ( m_pSelectedChild ) delete m_pSelectedChild; } void CJKStage::Initialize() { m_pFirst = NULL; m_pSelectedChild = NULL; m_cHistoryStack.ClearStack(); ::memset(m_enPanel,PS_NOTHING,sizeof(m_enPanel)); m_enPanel[0][0] = PS_HAN_CHA; m_enPanel[0][1] = PS_HAN_SANG; m_enPanel[0][2] = PS_HAN_MA; m_enPanel[0][3] = PS_HAN_SA; m_enPanel[0][5] = PS_HAN_SA; m_enPanel[0][6] = PS_HAN_MA; m_enPanel[0][7] = PS_HAN_SANG; m_enPanel[0][8] = PS_HAN_CHA; m_enPanel[1][4] = PS_HAN_JANG; m_enPanel[2][1] = PS_HAN_PO; m_enPanel[2][7] = PS_HAN_PO; m_enPanel[3][0] = PS_HAN_JOL; m_enPanel[3][2] = PS_HAN_JOL; m_enPanel[3][4] = PS_HAN_JOL; m_enPanel[3][6] = PS_HAN_JOL; m_enPanel[3][8] = PS_HAN_JOL; m_enPanel[9][0] = PS_CHO_CHA; m_enPanel[9][1] = PS_CHO_MA; m_enPanel[9][2] = PS_CHO_SANG; m_enPanel[9][3] = PS_CHO_SA; m_enPanel[9][5] = PS_CHO_SA; m_enPanel[9][6] = PS_CHO_MA; m_enPanel[9][7] = PS_CHO_SANG; m_enPanel[9][8] = PS_CHO_CHA; m_enPanel[8][4] = PS_CHO_JANG; m_enPanel[7][1] = PS_CHO_PO; m_enPanel[7][7] = PS_CHO_PO; m_enPanel[6][0] = PS_CHO_JOL; m_enPanel[6][2] = PS_CHO_JOL; m_enPanel[6][4] = PS_CHO_JOL; m_enPanel[6][6] = PS_CHO_JOL; m_enPanel[6][8] = PS_CHO_JOL; m_bPoBeforeJang = true; m_bJolToCenter = true; m_bCHAPOBalance = true; m_bAggressivePO = false; m_bAggressiveCHA = true; m_bAggressiveJOL = true; m_bAggressiveSANG = false; m_bAggressiveMA = false; m_bOnlyJangCenter = true; GetCHAPOCount(); } ////////////////////////////////////////////// // 지정된 위치로 말들이 통과할 수 있는지 체크 bool CJKStage::IsPassable(int nX,int nY) { if ( nX < 0 ) return false; if ( nY < 0 ) return false; if ( nX >= DF_PANEL_WIDTH ) return false; if ( nY >= DF_PANEL_HEIGHT ) return false; if ( m_enPanel[nY][nX] == PS_NOTHING ) return true; else return false; } void CJKStage::ClearList() { if ( m_pFirst ) { CJKStage *pNode = m_pFirst; CJKStage *pTmp; do { pTmp = pNode->m_pNext; delete pNode; pNode = pTmp; } while (pNode != NULL); m_pFirst = NULL; } } void CJKStage::ClearList(CJKStage *pException) { if ( m_pFirst ) { CJKStage *pNode = m_pFirst; CJKStage *pTmp; do { pTmp = pNode->m_pNext; if ( pNode != pException ) delete pNode; pNode = pTmp; } while (pNode != NULL); m_pFirst = NULL; } } ////////////////////////////////////////////// // 지정된 위치로 말들이 이동할 수 있는지 체크 bool CJKStage::TryToAddMovableXY(int nFromX,int nFromY,int nToX,int nToY) { if ( nToX < 0 ) return false; if ( nToY < 0 ) return false; if ( nToX >= DF_PANEL_WIDTH ) return false; if ( nToY >= DF_PANEL_HEIGHT ) return false; // 이동하고자 하는 곳에 같은 팀 말이 있으면 못 움직인다. if ( GetTeamAt(nToX,nToY) == GetTeamAt(nFromX,nFromY) ) return false; CJKStage *pNewStage = new CJKStage(this); pNewStage->MovePiece(nFromX,nFromY,nToX,nToY); pNewStage->m_nFromX = nFromX; pNewStage->m_nFromY = nFromY; pNewStage->m_nToX = nToX; pNewStage->m_nToY = nToY; pNewStage->m_enEatenPiece = m_enPanel[nToY][nToX]; pNewStage->m_nHANChaCount = m_nHANChaCount; pNewStage->m_nHANPoCount = m_nHANPoCount; pNewStage->m_nCHOChaCount = m_nCHOChaCount; pNewStage->m_nCHOPoCount = m_nCHOPoCount; switch ( pNewStage->m_enEatenPiece ) { case PS_HAN_CHA : -- pNewStage->m_nHANChaCount;break; case PS_HAN_PO : -- pNewStage->m_nHANPoCount;break; case PS_CHO_CHA : -- pNewStage->m_nCHOChaCount;break; case PS_CHO_PO : -- pNewStage->m_nCHOPoCount;break; } int nNewScore = pNewStage->PayOff(); if ( sm_nCount % 1000 == 0 ) { TRACE("Count - %d\n",sm_nCount); } ++ sm_nCount; /////////////////////////////////////////////////////// // Max입장에선 최대 값을 가지는 국면을 선택하므로 // "가치가 큰 국면순"으로 정렬해 두면 알파베타 가지치기 // 효율이 증대된다. if ( m_bAmIMax ) { if ( m_pFirst ) { CJKStage *pNode = m_pFirst; do { if ( nNewScore >= pNode->GetScore() ) break; pNode = pNode->m_pNext; } while( pNode != NULL ); if ( pNode == NULL ) { m_pLast->m_pNext = pNewStage; pNewStage->m_pPrev = m_pLast; pNewStage->m_pNext = NULL; m_pLast = pNewStage; } else { CJKStage * pTmp = pNode->m_pPrev; pNode->m_pPrev = pNewStage; pNewStage->m_pNext = pNode; pNewStage->m_pPrev = pTmp; if ( pTmp ) { pTmp->m_pNext = pNewStage; } else { m_pFirst = pNewStage; } } } else { m_pFirst = pNewStage; m_pLast = pNewStage; pNewStage->m_pPrev = NULL; pNewStage->m_pNext = NULL; } } else { if ( m_pFirst ) { CJKStage *pNode = m_pFirst; do { if ( nNewScore <= pNode->GetScore() ) break; pNode = pNode->m_pNext; } while(pNode != NULL); if ( pNode == NULL ) { m_pLast->m_pNext = pNewStage; pNewStage->m_pPrev = m_pLast; pNewStage->m_pNext = NULL; m_pLast = pNewStage; } else { CJKStage * pTmp = pNode->m_pPrev; pNode->m_pPrev = pNewStage; pNewStage->m_pNext = pNode; pNewStage->m_pPrev = pTmp; if ( pTmp ) { pTmp->m_pNext = pNewStage; } else { m_pFirst = pNewStage; } } } else { m_pFirst = pNewStage; m_pLast = pNewStage; pNewStage->m_pPrev = NULL; pNewStage->m_pNext = NULL; } } return true; } ////////////////////////////////////////////// // 지정된 위치에 있는 말의 소속 팀을 반환 TEAM CJKStage::GetTeamAt(int nX,int nY) { if ( m_enPanel[nY][nX] == PS_NOTHING ) return TM_NOTHING; if ( m_enPanel[nY][nX] < PS_BOUNDARY ) return TM_CHO; return TM_HAN; } void CJKStage::GetMovableSaAndJang(int nFromX,int nFromY) { switch ( nFromY ) { case 0 : case 7 : switch ( nFromX ) { case 3 : TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + 1); break; case 4 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); break; case 5 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + 1); break; } break; case 1 : case 8 : switch ( nFromX ) { case 3 : TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); break; case 4 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + 1); break; case 5 : TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); break; } break; case 2 : case 9 : switch ( nFromX ) { case 3 : TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); break; case 4 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); break; case 5 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY - 1); break; } break; } } void CJKStage::GetMovableJol(int nFromX,int nFromY) { int nDirection = GetTeamAt(nFromX,nFromY) == TM_CHO ? -1 : 1; ////////////////////////////////////////////////// // 사,장이 움직이는 영역 안에선 사,장과 똑같이 // 대각선으로도 움직일 수있다.뒤로는 금지 switch ( nFromY ) { case 1 : case 8 : switch ( nFromX ) { case 4 : TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + nDirection); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + nDirection); break; } break; case 2 : case 7 : switch ( nFromX ) { case 3 : TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + nDirection); break; case 5 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + nDirection); break; } break; } // 좌로 움직여 본다. TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY); // 우로 움직여 본다. TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY); // 직진 해 본다. TryToAddMovableXY(nFromX,nFromY,nFromX,nFromY + nDirection); } void CJKStage::GetMovablePo(int nFromX,int nFromY) { bool bMovable = false; // 우측 라인으로 이동시켜본다. for ( int k = nFromX + 1; k < DF_PANEL_WIDTH; ++ k ) { if ( bMovable ) { if ( m_enPanel[nFromY][k] != PS_CHO_PO && m_enPanel[nFromY][k] != PS_HAN_PO) { TryToAddMovableXY(nFromX,nFromY,k,nFromY); if ( m_enPanel[nFromY][k] != PS_NOTHING ) break; } else { break; } } else { ///////////////////////////////////////////////////// // 포 이외의 다른 말이 나올 경우 그 다음칸부터 // 포가 이동할 수 있는 영역이다. if ( m_enPanel[nFromY][k] == PS_HAN_PO ) break; if ( m_enPanel[nFromY][k] == PS_CHO_PO ) break; if ( m_enPanel[nFromY][k] != PS_NOTHING ) bMovable = true; } } bMovable = false; // 좌측 라인으로 이동시켜본다. for ( k = nFromX - 1; k >= 0; -- k ) { if ( bMovable ) { if ( m_enPanel[nFromY][k] != PS_CHO_PO && m_enPanel[nFromY][k] != PS_HAN_PO ) { TryToAddMovableXY(nFromX,nFromY,k,nFromY); if ( m_enPanel[nFromY][k] != PS_NOTHING ) break; } else { break; } } else { ///////////////////////////////////////////////////// // 포 이외의 다른 말이 나올 경우 그 다음칸부터 // 포가 이동할 수 있는 영역이다. if ( m_enPanel[nFromY][k] == PS_HAN_PO ) break; if ( m_enPanel[nFromY][k] == PS_CHO_PO ) break; if ( m_enPanel[nFromY][k] != PS_NOTHING ) bMovable = true; } } bMovable = false; // 위로 이동시켜 본다. for ( k = nFromY - 1; k >= 0; -- k ) { if ( bMovable ) { if ( m_enPanel[k][nFromX] != PS_CHO_PO && m_enPanel[k][nFromX] != PS_HAN_PO ) { TryToAddMovableXY(nFromX,nFromY,nFromX,k); if ( m_enPanel[k][nFromX] != PS_NOTHING ) break; } else { break; } } else { ///////////////////////////////////////////////////// // 포 이외의 다른 말이 나올 경우 그 다음칸부터 // 포가 이동할 수 있는 영역이다. if ( m_enPanel[k][nFromX] == PS_HAN_PO ) break; if ( m_enPanel[k][nFromX] == PS_CHO_PO ) break; if ( m_enPanel[k][nFromX] != PS_NOTHING ) bMovable = true; } } bMovable = false; // 아래로 이동시켜본다. for ( k = nFromY + 1; k < DF_PANEL_HEIGHT; ++ k ) { if ( bMovable ) { if ( m_enPanel[k][nFromX] != PS_CHO_PO && m_enPanel[k][nFromX] != PS_HAN_PO ) { TryToAddMovableXY(nFromX,nFromY,nFromX,k); if ( m_enPanel[k][nFromX] != PS_NOTHING ) break; } else { break; } } else { ///////////////////////////////////////////////////// // 포 이외의 다른 말이 나올 경우 그 다음칸부터 // 포가 이동할 수 있는 영역이다. if ( m_enPanel[k][nFromX] == PS_HAN_PO ) break; if ( m_enPanel[k][nFromX] == PS_CHO_PO ) break; if ( m_enPanel[k][nFromX] != PS_NOTHING ) bMovable = true; } } } void CJKStage::GetMovableCha(int nFromX,int nFromY) { ////////////////////////////////////////////////// // 사,장이 움직이는 영역 안에선 사,장과 똑같이 // 대각선으로도 움직일 수있다. switch ( nFromY ) { case 0 : case 7 : switch ( nFromX ) { case 3 : if ( GetTeamAt(4,nFromY) != GetTeamAt(nFromX,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + 1); if ( GetTeamAt(4,nFromY + 1) == PS_NOTHING ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY + 2); break; case 5 : if ( GetTeamAt(4,nFromY) != GetTeamAt(nFromX,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + 1); if ( GetTeamAt(4,nFromY + 1) == PS_NOTHING ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY + 2); break; } break; case 1 : case 8 : switch ( nFromX ) { case 4 : TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY - 1); TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + 1); TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + 1); break; } break; case 2 : case 9 : switch ( nFromX ) { case 3 : if ( GetTeamAt(4,nFromY) != GetTeamAt(nFromX,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY - 1); if ( GetTeamAt(4,nFromY - 1) == PS_NOTHING ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY - 2); break; case 5 : if ( GetTeamAt(4,nFromY) != GetTeamAt(nFromX,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY - 1); if ( GetTeamAt(4,nFromY - 1) == PS_NOTHING ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY - 2); break; } break; } // 우측 라인으로 이동시켜본다. for ( int k = nFromX + 1; k < DF_PANEL_WIDTH; ++ k ) { // 같은팀 말이 진행로에 있으면 더 이상 못 간다. if ( GetTeamAt(k,nFromY) == GetTeamAt(nFromX,nFromY) ) break; TryToAddMovableXY(nFromX,nFromY,k,nFromY); if ( GetTeamAt(k,nFromY) != PS_NOTHING ) break; } // 좌측 라인으로 이동시켜본다. for ( k = nFromX - 1; k >= 0; -- k ) { // 같은팀 말이 진행로에 있으면 더 이상 못 간다. if ( GetTeamAt(k,nFromY) == GetTeamAt(nFromX,nFromY) ) break; TryToAddMovableXY(nFromX,nFromY,k,nFromY); if ( GetTeamAt(k,nFromY) != PS_NOTHING ) break; } // 위로 이동시켜 본다. for ( k = nFromY - 1; k >= 0; -- k ) { // 같은팀 말이 진행로에 있으면 더 이상 못 간다. if ( GetTeamAt(nFromX,k) == GetTeamAt(nFromX,nFromY) ) break; TryToAddMovableXY(nFromX,nFromY,nFromX,k); if ( GetTeamAt(nFromX,k) != PS_NOTHING ) break; } // 아래로 이동시켜본다. for ( k = nFromY + 1; k < DF_PANEL_HEIGHT; ++ k ) { // 같은팀 말이 진행로에 있으면 더 이상 못 간다. if ( GetTeamAt(nFromX,k) == GetTeamAt(nFromX,nFromY) ) break; TryToAddMovableXY(nFromX,nFromY,nFromX,k); if ( GetTeamAt(nFromX,k) != PS_NOTHING ) break; } } void CJKStage::GetMovableMa(int nFromX,int nFromY) { // 전방 & 좌측으로 이동해 본다. if ( IsPassable(nFromX,nFromY - 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY - 2); // 전방 & 우측으로 이동해 본다. if ( IsPassable(nFromX,nFromY - 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY - 2); // 후방 & 좌측으로 이동해 본다. if ( IsPassable(nFromX,nFromY + 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 1,nFromY + 2); // 후방 & 우측으로 이동해 본다. if ( IsPassable(nFromX,nFromY + 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 1,nFromY + 2); // 좌측 & 전방으로 이동해 본다. if ( IsPassable(nFromX - 1,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY - 1); // 좌측 & 후방으로 이동해 본다. if ( IsPassable(nFromX - 1,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY + 1); // 우측 & 전방으로 이동해 본다. if ( IsPassable(nFromX + 1,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY - 1); // 우측 & 후방으로 이동해 본다. if ( IsPassable(nFromX + 1,nFromY) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY + 1); } void CJKStage::GetMovableSang(int nFromX,int nFromY) { // 전방 & 좌측으로 이동해 본다. if ( IsPassable(nFromX,nFromY - 1) && IsPassable(nFromX - 1,nFromY - 2) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY - 3); // 전방 & 우측으로 이동해 본다. if ( IsPassable(nFromX,nFromY - 1) && IsPassable(nFromX + 1,nFromY - 2) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY - 3); // 후방 & 좌측으로 이동해 본다. if ( IsPassable(nFromX,nFromY + 1) && IsPassable(nFromX - 1,nFromY + 2) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 2,nFromY + 3); // 후방 & 우측으로 이동해 본다. if ( IsPassable(nFromX,nFromY + 1) && IsPassable(nFromX + 1,nFromY + 2) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 2,nFromY + 3); // 좌측 & 전방으로 이동해 본다. if ( IsPassable(nFromX - 1,nFromY) && IsPassable(nFromX - 2,nFromY - 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 3,nFromY - 2); // 좌측 & 후방으로 이동해 본다. if ( IsPassable(nFromX - 1,nFromY) && IsPassable(nFromX - 2,nFromY + 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX - 3,nFromY + 2); // 우측 & 전방으로 이동해 본다. if ( IsPassable(nFromX + 1,nFromY) && IsPassable(nFromX + 2,nFromY - 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 3,nFromY - 2); // 우측 & 후방으로 이동해 본다. if ( IsPassable(nFromX + 1,nFromY) && IsPassable(nFromX + 2,nFromY + 1) ) TryToAddMovableXY(nFromX,nFromY,nFromX + 3,nFromY + 2); } ///////////////////////////////////////////////// // HAN : Plus score // CHO : Minus score int CJKStage::PayOff() { m_nScore = 0; for ( int i,j = 0; j < DF_PANEL_HEIGHT; ++ j ) for ( i = 0; i < DF_PANEL_WIDTH; ++ i ) { switch ( m_enPanel[j][i] ) { case PS_CHO_JANG : { m_nScore -= DF_SCORE_JANG; // 포를 장 앞에 두려는 성향 if ( m_bPoBeforeJang ) { if ( m_enPanel[j - 1][i] == PS_CHO_PO ) m_nScore -= 50; } break; } case PS_CHO_SA : m_nScore -= DF_SCORE_SA;break; case PS_CHO_JOL : { m_nScore -= DF_SCORE_JOL; // 졸을 서로 모으되 가운데쪽으로 모은다. if ( m_bJolToCenter ) { if ( m_enPanel[j][i - 1] == PS_CHO_JOL && i > 5 ) m_nScore -= 1; if ( m_enPanel[j][i + 1] == PS_CHO_JOL && i <= 5 ) m_nScore -= 1; } // 졸의 공격 성향 업 if ( m_bAggressiveJOL ) { if ( j < 7 ) m_nScore -= 1; } break; } case PS_CHO_PO : { // 포 2,차 1이면 차 점수가 높다. // 포 1,차 2이면 포 점수가 높다. // 그렇지 않음 포와 차는 동급이다. m_nScore -= DF_SCORE_PO; if ( m_bCHAPOBalance && m_nCHOPoCount < m_nCHOChaCount ) m_nScore -= 2000; // 포의 공격 성향 업 if ( m_bAggressivePO ) { if ( j < 7 ) m_nScore -= 1; } break; } case PS_CHO_CHA : { // 포 2,차 1이면 차 점수가 높다. // 포 1,차 2이면 포 점수가 높다. // 그렇지 않음 포와 차는 동급이다. m_nScore -= DF_SCORE_CHA; if ( m_bCHAPOBalance && m_nCHOChaCount < m_nCHOPoCount ) m_nScore -= 2000; // 차의 공격 성향 업 if ( m_bAggressiveCHA ) { if ( j < 7 ) m_nScore -= 2; } break; } case PS_CHO_MA : { m_nScore -= DF_SCORE_MA; // 마의 공격 성향 업 if ( m_bAggressiveMA ) { if ( j < 7 ) m_nScore -= 1; } break; } case PS_CHO_SANG : { m_nScore -= DF_SCORE_SANG; // 상의 공격 성향 업 if ( m_bAggressiveSANG ) { if ( j < 7 ) m_nScore -= 1; } break; } case PS_HAN_JANG : { m_nScore += DF_SCORE_JANG; // 포를 장 앞에 두려는 성향 if ( m_bPoBeforeJang ) { if ( m_enPanel[j + 1][i] == PS_HAN_PO ) m_nScore += 50; } break; } case PS_HAN_SA : m_nScore += DF_SCORE_SA;break; case PS_HAN_JOL : { m_nScore += DF_SCORE_JOL; // 졸을 서로 모으되 가운데쪽으로 모은다. if ( m_bJolToCenter ) { if ( m_enPanel[j][i - 1] == PS_HAN_JOL && i > 5 ) m_nScore += 1; if ( m_enPanel[j][i + 1] == PS_HAN_JOL && i <= 5 ) m_nScore += 1; } // 졸의 공격 성향 업 if ( m_bAggressiveJOL ) { if ( j > 3 ) m_nScore += 1; } break; } case PS_HAN_PO : { // 포 2,차 1이면 차 점수가 높다. // 포 1,차 2이면 포 점수가 높다. // 그렇지 않음 포와 차는 동급이다. m_nScore += DF_SCORE_PO; if ( m_bCHAPOBalance && m_nHANPoCount < m_nHANChaCount ) m_nScore += 2000; // 포의 공격 성향 업 if ( m_bAggressivePO ) { if ( j > 3 ) m_nScore += 1; } break; } case PS_HAN_CHA : { // 포 2,차 1이면 차 점수가 높다. // 포 1,차 2이면 포 점수가 높다. // 그렇지 않음 포와 차는 동급이다. m_nScore += DF_SCORE_CHA; if ( m_bCHAPOBalance && m_nHANChaCount < m_nHANPoCount ) m_nScore += 2000; // 차의 공격 성향 업 if ( m_bAggressiveCHA ) { if ( j > 3 ) m_nScore += 2; } break; } case PS_HAN_MA : { m_nScore += DF_SCORE_MA; // 마의 공격 성향 업 if ( m_bAggressiveMA ) { if ( j > 3 ) m_nScore += 1; } break; } case PS_HAN_SANG : { m_nScore += DF_SCORE_SANG; // 상의 공격 성향 업 if ( m_bAggressiveSANG ) { if ( j > 3 ) m_nScore += 1; } break; } } } // 장 이외에는 장 영역 중간에 오는 걸 막는다. if ( m_bOnlyJangCenter ) { if ( m_enPanel[1][4] != PS_NOTHING && m_enPanel[1][4] != PS_HAN_JANG && m_enPanel[1][5] != PS_HAN_SA ) m_nScore -= 10; if ( m_enPanel[8][4] != PS_NOTHING && m_enPanel[8][4] != PS_CHO_JANG && m_enPanel[8][4] != PS_CHO_SA ) m_nScore += 10; } return m_nScore; } bool CJKStage::SaveStage(const char * filename) { FILE *fp = fopen(filename,"w+b"); if ( fp == NULL ) return false; fwrite(m_enPanel,1,sizeof(m_enPanel),fp); m_cHistoryStack.SaveHistory(fp); fclose(fp); return true; } bool CJKStage::LoadStage(const char * filename) { FILE *fp = fopen(filename,"r+b"); if ( fp == NULL ) return false; fread(m_enPanel,1,sizeof(m_enPanel),fp); m_cHistoryStack.LoadHistory(fp); fclose(fp); return true; } bool CJKStage::MovePiece(int nFromX,int nFromY,int nToX,int nToY) { if ( nFromX < 0 || nFromX >= DF_PANEL_WIDTH ) return false; if ( nFromY < 0 || nFromY >= DF_PANEL_HEIGHT ) return false; if ( nToX < 0 || nToX >= DF_PANEL_WIDTH ) return false; if ( nToY < 0 || nToY >= DF_PANEL_HEIGHT ) return false; m_enPanel[nToY][nToX] = m_enPanel[nFromY][nFromX]; m_enPanel[nFromY][nFromX] = PS_NOTHING; return true; } MOVERESULT CJKStage::HumanMove(int nFromX,int nFromY,int nToX,int nToY) { PIECES enEatenPiece = m_enPanel[nToY][nToX]; bool bResult = MovePiece(nFromX,nFromY,nToX,nToY); if ( bResult ) { // History 저장 m_cHistoryStack.Push(nFromX,nFromY,nToX,nToY,enEatenPiece); } if ( !bResult ) return MR_UNMOVED; if ( enEatenPiece == PS_HAN_JANG ) return MR_HANDEAD; if ( enEatenPiece == PS_CHO_JANG ) return MR_CHODEAD; return MR_MOVED; } bool CJKStage::GetNextPieceLoc(int nFromX,int nFromY,CMoveData & cMD) { if ( nFromX < 0 || nFromX >= DF_PANEL_WIDTH ) return false; if ( nFromY < 0 || nFromY >= DF_PANEL_HEIGHT ) return false; ClearList(); cMD.Reset(); ///////////////////////////////////////////////////// // 각 말 별로 움직일 수 있는 범위를 구한다. switch ( m_enPanel[nFromY][nFromX] ) { case PS_CHO_JANG : case PS_CHO_SA : GetMovableSaAndJang(nFromX,nFromY);break; case PS_CHO_JOL : GetMovableJol(nFromX,nFromY);break; case PS_CHO_PO : GetMovablePo(nFromX,nFromY);break; case PS_CHO_CHA : GetMovableCha(nFromX,nFromY);break; case PS_CHO_MA : GetMovableMa(nFromX,nFromY);break; case PS_CHO_SANG : GetMovableSang(nFromX,nFromY);break; case PS_HAN_JANG : case PS_HAN_SA : GetMovableSaAndJang(nFromX,nFromY);break; case PS_HAN_JOL : GetMovableJol(nFromX,nFromY);break; case PS_HAN_PO : GetMovablePo(nFromX,nFromY);break; case PS_HAN_CHA : GetMovableCha(nFromX,nFromY);break; case PS_HAN_MA : GetMovableMa(nFromX,nFromY);break; case PS_HAN_SANG : GetMovableSang(nFromX,nFromY);break; } cMD.SetFromXY(nFromX,nFromY); if ( m_pFirst ) { CJKStage * pNode = m_pFirst; do { cMD.AddToXY(pNode->m_nToX,pNode->m_nToY); pNode = pNode->m_pNext; } while ( pNode != NULL ); return true; } return true; } void CJKStage::GetNextStage() { if ( m_enTeam == TM_HAN ) { for ( int j,i = 0; i < DF_PANEL_HEIGHT; ++ i ) { for ( j = 0; j < DF_PANEL_WIDTH; ++ j ) { switch ( m_enPanel[i][j] ) { case PS_HAN_JANG : case PS_HAN_SA : GetMovableSaAndJang(j,i);break; case PS_HAN_JOL : GetMovableJol(j,i);break; case PS_HAN_PO : GetMovablePo(j,i);break; case PS_HAN_CHA : GetMovableCha(j,i);break; case PS_HAN_MA : GetMovableMa(j,i);break; case PS_HAN_SANG : GetMovableSang(j,i);break; } } } } else { for ( int j,i = 0; i < DF_PANEL_HEIGHT; ++ i ) { for ( j = 0; j < DF_PANEL_WIDTH; ++ j ) { switch ( m_enPanel[i][j] ) { case PS_CHO_JANG : case PS_CHO_SA : GetMovableSaAndJang(j,i);break; case PS_CHO_JOL : GetMovableJol(j,i);break; case PS_CHO_PO : GetMovablePo(j,i);break; case PS_CHO_CHA : GetMovableCha(j,i);break; case PS_CHO_MA : GetMovableMa(j,i);break; case PS_CHO_SANG : GetMovableSang(j,i);break; } } } } } bool CJKStage::CutOffTest() { if ( m_enEatenPiece == PS_CHO_JANG ) return true; if ( m_enEatenPiece == PS_HAN_JANG ) return true; //////////////////////////////////////////////////////////// // FeedOver를 할 때 인간이 둘 수가 정적일때 그만둬야 한다. // 컴퓨터 수가 정적이라서 그만 둘 경우 그 다음 인간 수에서 // 치명타를 입을 수가 있다. if ( m_enEatenPiece != PS_NOTHING ) if ( m_nDepth <= DF_FEEDOVER_DEPTH ) return false; if ( m_nDepth >= DF_CUTOFF_DEPTH ) return true; /* if ( m_enEatenPiece == PS_CHO_JANG ) return true; if ( m_enEatenPiece == PS_HAN_JANG ) return true; ///////////////////////////////////////////////////// // 기본적으로 몇 수 앞까지는 무조건 내다본다. if ( m_nDepth <= DF_CUTOFF_DEPTH ) return false; ///////////////////////////////////////////////////// // FEED OVER Depth까지 오면 추론을 완전히 그만둔다. if ( m_nDepth >= DF_FEEDOVER_DEPTH ) return true; ///////////////////////////////////////////////////// // FEED OVER를 한다.즉 "인간이 둘 국면"이 정적일 때 // 추론을 그만둔다.Depth 가 홀수이면 인간이 둘 수. // if ( m_nDepth % 2 == 1 && m_enEatenPiece == PS_NOTHING ) if ( m_enEatenPiece == PS_NOTHING ) return true; */ return true; return false; } int CJKStage::MaxValue(int nAlpha,int nBeta) { // CUTOFF test if ( CutOffTest() ) return m_nScore; //////////////////////////////////////////////////// // GetNextStage()에서 가능한 다음 국면들을 효율적으로 // 소트(알파베타 가지치기에)한 후 리스트로 만들어둔다. GetNextStage(); if ( m_pFirst ) { CJKStage * pNode = m_pFirst; int nMinValue; // 다음 국면을 모두 테스트해본다. do { nMinValue = pNode->MinValue(nAlpha,nBeta); if ( nMinValue > nAlpha ) { nAlpha = nMinValue; m_pSelectedChild = pNode; } //////////////////////////////////////////////////////// // 부모인 Min은 작은 점수를 선택하려 할 것인데 내(Max)가 // 만든 국면의 점수가 Beta보다 커버리면 부모인 Min의 // 선택권에서 벗아나므로 더 이상 진행에도 의미가 없다. // 나(Max)는 가장 큰 점수를 가지는 국면을 택하기 때문이다. if ( nAlpha >= nBeta ) break; pNode = pNode->m_pNext; } while ( pNode != NULL ); } // 선택된 다음 국면은 메모리상에서 삭제하지 않는다. ClearList(m_pSelectedChild); return nAlpha; } int CJKStage::MinValue(int nAlpha,int nBeta) { // CUTOFF test if ( CutOffTest() ) return m_nScore; //////////////////////////////////////////////////// // GetNextStage()에서 가능한 다음 국면들을 효율적으로 // 소트(알파베타 가지치기에)한 후 리스트로 만들어둔다. GetNextStage(); if ( m_pFirst ) { CJKStage * pNode = m_pFirst; int nMaxValue; do { nMaxValue = pNode->MaxValue(nAlpha,nBeta); if ( nMaxValue < nBeta ) { nBeta = nMaxValue; m_pSelectedChild = pNode; } //////////////////////////////////////////////////////// // 부모인 Max는 큰 점수를 선택하려 할 것인데 내(Min)가 // 만든 국면의 점수가 Alpha보다 작으면 부모인 Max의 // 선택권에서 벗아나므로 더 이상 진행에도 의미가 없다. // 나(Min)는 가장 작은 점수를 가지는 국면을 택하기 때문이다. if ( nBeta <= nAlpha ) break; pNode = pNode->m_pNext; } while ( pNode != NULL ); } // 선택된 다음 국면은 메모리상에서 삭제하지 않는다. ClearList(m_pSelectedChild); return nBeta; } MOVERESULT CJKStage::Infer(TEAM enTeam) { ///////////////////////////////////////////////////// // ALPHA - Max가 선택할 다음 국면 후보의 값(최대치) // BETA - Min이 선택할 다음 국면 후보의 값(최소치) ///////////////////////////////////////////////////// // 한나라가 Plus 점수이므로 Max가 되어야 한다. m_bAmIMax = (enTeam == TM_HAN); m_enTeam = enTeam; m_nDepth = 0; sm_nCount = 0; CJKStage *pSelected = NULL; ///////////////////////////////////////////////////// // 알파는 최대한 작게,베타는 최대한 크게 초기화함으로서 // 최초에는 가장 깊숙히까지 가지를 뻗을 수 있게 한다. // (알파베타 가지치기를 당하지 않게 한다.) int nAlpha = -9999999; int nBeta = +9999999; int nScore; ClearList(); GetNextStage(); int nSelectedNo; //////////////////////////////////////// // 한나라 입장에서 추론한다면... if ( m_bAmIMax ) { if ( m_pFirst ) { CJKStage * pNode = m_pFirst; static int snCount = 0; do { nScore = pNode->MinValue(nAlpha,nBeta); CJKStage *pTmp = pNode; do { TRACE("Way No.%d,Depth - %d : %d,%d to %d,%d\n",snCount , pTmp->m_nDepth, pTmp->m_nFromX, pTmp->m_nFromY, pTmp->m_nToX, pTmp->m_nToY); pTmp = pTmp->m_pSelectedChild; } while ( pTmp != NULL ); TRACE("Way No.%d Score : %d\n\n",snCount ++,nScore); if ( nScore > nAlpha ) { nAlpha = nScore; pSelected = pNode; nSelectedNo = snCount; } pNode = pNode->m_pNext; } while ( pNode != NULL ); } } else { //////////////////////////////////////// // 조나라 입장에서 추론한다면... if ( m_pFirst ) { CJKStage * pNode = m_pFirst; static int snCount = 0; do { nScore = pNode->MaxValue(nAlpha,nBeta); CJKStage *pTmp = pNode; do { TRACE("Way No.%d,Depth - %d : %d,%d to %d,%d\n",snCount , pTmp->m_nDepth, pTmp->m_nFromX, pTmp->m_nFromY, pTmp->m_nToX, pTmp->m_nToY); pTmp = pTmp->m_pSelectedChild; } while ( pTmp != NULL ); snCount ++; TRACE("Way No.%d Score : %d\n\n",snCount,nScore); if ( nScore < nBeta ) { nBeta = nScore; pSelected = pNode; nSelectedNo = snCount; } pNode = pNode->m_pNext; } while ( pNode != NULL ); } } if ( pSelected ) { TRACE("Selected No. %d with Score %d\n",-- nSelectedNo,nScore); m_nFromX = pSelected->m_nFromX; m_nFromY = pSelected->m_nFromY; m_nToX = pSelected->m_nToX; m_nToY = pSelected->m_nToY; m_enEatenPiece = m_enPanel[m_nToY][m_nToX]; MovePiece(m_nFromX,m_nFromY,m_nToX,m_nToY); // History 저장 m_cHistoryStack.Push(m_nFromX,m_nFromY,m_nToX,m_nToY,m_enEatenPiece); m_enEatenPiece = pSelected->m_enEatenPiece; if ( m_enEatenPiece == PS_HAN_JANG ) return MR_HANDEAD; if ( m_enEatenPiece == PS_CHO_JANG ) return MR_CHODEAD; return MR_MOVED; } return MR_UNMOVED; } bool CJKStage::GetLastMove(SHistory & LMStore) { return m_cHistoryStack.GetLastMove(LMStore); } bool CJKStage::MoveBack() { SHistory sH; if ( m_cHistoryStack.Pop(sH) ) { m_enPanel[sH.nFromY][sH.nFromX] = m_enPanel[sH.nToY][sH.nToX]; m_enPanel[sH.nToY][sH.nToX] = sH.enEatenPiece; return true; } return false; }
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published