diff --git a/.gitignore b/.gitignore index e8cbad86..b579dcb1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -## Ignore Visual Studio temporary files, build results, and +## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files @@ -260,14 +260,7 @@ paket-files/ __pycache__/ *.pyc - -# exe and dll -*.exe -*.dll - -# backup -*.bak - +############################################# # QT # C++ objects and libs @@ -313,3 +306,15 @@ target_wrapper.* # QtCreator CMake CMakeLists.txt.user* + +########################################### + +# exe and dll +*.exe +*.dll + +# backup +*.bak + +# visual studio code +.vscode/ diff --git a/NineChess/ninechess.pro b/NineChess/ninechess.pro index 0e767650..3e1525c7 100644 --- a/NineChess/ninechess.pro +++ b/NineChess/ninechess.pro @@ -3,7 +3,6 @@ # Project created by QtCreator 2015-11-03T22:30:34 # #------------------------------------------------- -#QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01 QT += core gui \ multimedia @@ -23,6 +22,7 @@ SOURCES += \ src/gamescene.cpp \ src/gameview.cpp \ src/ninechess.cpp \ + src/ninechessai_ab.cpp \ src/ninechesswindow.cpp \ src/pieceitem.cpp \ src/aithread.cpp @@ -34,9 +34,10 @@ HEADERS += \ src/gameview.h \ src/graphicsconst.h \ src/ninechess.h \ + src/ninechessai_ab.h \ src/ninechesswindow.h \ src/pieceitem.h \ - src/sizehintlistview.h \ + src/manuallistview.h \ src/aithread.h FORMS += \ @@ -46,10 +47,10 @@ RESOURCES += \ ninechesswindow.qrc DISTFILES += \ + NineChess.rc \ ../Readme.md \ ../范例棋谱.txt \ ../History.txt \ - ../Licence.txt \ - NineChess.rc + ../Licence.txt RC_FILE += NineChess.rc diff --git a/NineChess/ninechess.pro.user b/NineChess/ninechess.pro.user index 28544d38..df4126e6 100644 --- a/NineChess/ninechess.pro.user +++ b/NineChess/ninechess.pro.user @@ -1,10 +1,10 @@ - + EnvironmentId - {9a8c5f9d-1814-40d9-ab01-983c45f229c5} + {fba36f69-c7a3-4c3f-91d4-7c71ad79549c} ProjectExplorer.Project.ActiveTarget @@ -54,22 +54,19 @@ ProjectExplorer.Project.PluginSettings - - - true - + ProjectExplorer.Project.Target.0 - Desktop Qt 5.9.7 GCC 64bit - Desktop Qt 5.9.7 GCC 64bit - qt.qt5.597.gcc_64_kit + Desktop Qt 5.11.0 MSVC2017 64bit + Desktop Qt 5.11.0 MSVC2017 64bit + qt.qt5.5110.win64_msvc2017_64_kit 0 0 0 - /media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Debug + E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug true @@ -87,10 +84,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + false @@ -106,10 +100,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + true clean @@ -129,7 +120,7 @@ true - /media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Release + E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Release true @@ -147,10 +138,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + false @@ -166,10 +154,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + true clean @@ -189,7 +174,7 @@ true - /media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Profile + E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Profile true @@ -207,10 +192,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + false @@ -226,10 +208,7 @@ Make Qt4ProjectManager.MakeStep - - -w - -r - + true clean @@ -257,7 +236,7 @@ ProjectExplorer.BuildSteps.Deploy 1 - Deploy Configuration + 部署设置 ProjectExplorer.DefaultDeployConfiguration @@ -307,10 +286,11 @@ ninechess - Qt4ProjectManager.Qt4RunConfiguration:/media/sniper/Work/My program/QT/NineChess/NineChess/ninechess.pro + Qt4ProjectManager.Qt4RunConfiguration:E:/My program/QT/NineChess/NineChess/ninechess.pro true ninechess.pro + false 3768 diff --git a/NineChess/ninechess.vcxproj b/NineChess/ninechess.vcxproj index 72db3220..dcd226d3 100644 --- a/NineChess/ninechess.vcxproj +++ b/NineChess/ninechess.vcxproj @@ -371,17 +371,29 @@ + + + + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\release;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\release;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork @@ -419,11 +431,15 @@ .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;release;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories) - - .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;debug;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories) - .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;debug;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories) - .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;release;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories) - .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;release;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories) + + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\debug;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\release;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + .\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(QTDIR)\include;.\release;\include;$(QTDIR)\mkspecs\win32-msvc;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtNetwork + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB + _WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_WIDGETS_LIB;QT_CORE_LIB;QT_GUI_LIB;QT_MULTIMEDIA_LIB;QT_NETWORK_LIB @@ -481,6 +497,7 @@ + @@ -490,6 +507,7 @@ + diff --git a/NineChess/ninechess.vcxproj.filters b/NineChess/ninechess.vcxproj.filters index 0e2d5f3a..7945718a 100644 --- a/NineChess/ninechess.vcxproj.filters +++ b/NineChess/ninechess.vcxproj.filters @@ -50,10 +50,11 @@ * false - - {B83CAF91-C7BF-462F-B76C-EA11631F866C} - * - false + + {d3810898-e5d4-49ce-92da-beddffba0697} + + + {16c52ca8-0391-4ad2-919c-4a865ad87e98} @@ -81,6 +82,12 @@ Source Files + + Source Files + + + Source Files + @@ -107,6 +114,12 @@ Header Files + + Header Files + + + Header Files + @@ -236,27 +249,40 @@ Resource Files - + + Text Files + + + Project Files + - - - - - Header Files - - - - - - - - - + + Text Files + + + Text Files + + + Text Files + Header Files + + Header Files + + + + + Project Files + + + + + Project Files + \ No newline at end of file diff --git a/NineChess/ninechesswindow.qrc b/NineChess/ninechesswindow.qrc index 0c4a0c2c..341a9aa6 100644 --- a/NineChess/ninechesswindow.qrc +++ b/NineChess/ninechesswindow.qrc @@ -1,54 +1,54 @@ - Resources/image/black_piece.png - Resources/image/board.png - Resources/image/white_piece.png - Resources/image/background.png + resources/image/black_piece.png + resources/image/board.png + resources/image/white_piece.png + resources/image/background.png - Resources/icon/Black.png - Resources/icon/White.png - Resources/icon/ActualSizeHS.png - Resources/icon/BreakpointHS.png - Resources/icon/DocumentHS.png - Resources/icon/EditInformationHS.png - Resources/icon/EditTableHS.png - Resources/icon/Error.png - Resources/icon/First.png - Resources/icon/FlipHorizontalHS.png - Resources/icon/FlipVerticalHS.png - Resources/icon/FullScreenHS.png - Resources/icon/Help.png - Resources/icon/HomeHS.png - Resources/icon/Last.png - Resources/icon/LeftHS.png - Resources/icon/LegendHS.png - Resources/icon/NewDocumentHS.png - Resources/icon/Next.png - Resources/icon/OpenHS.png - Resources/icon/Pause.png - Resources/icon/Play.png - Resources/icon/Previous.png - Resources/icon/PrimaryKeyHS.png - Resources/icon/Refresh.png - Resources/icon/Request.png - Resources/icon/OptionsHS.png - Resources/icon/Web.png - Resources/icon/RestartHS.png - Resources/icon/Invert.png - Resources/icon/RightHS.png - Resources/icon/SaveHS.png + resources/icon/Black.png + resources/icon/White.png + resources/icon/ActualSizeHS.png + resources/icon/BreakpointHS.png + resources/icon/DocumentHS.png + resources/icon/EditInformationHS.png + resources/icon/EditTableHS.png + resources/icon/Error.png + resources/icon/First.png + resources/icon/FlipHorizontalHS.png + resources/icon/FlipVerticalHS.png + resources/icon/FullScreenHS.png + resources/icon/Help.png + resources/icon/HomeHS.png + resources/icon/Last.png + resources/icon/LeftHS.png + resources/icon/LegendHS.png + resources/icon/NewDocumentHS.png + resources/icon/Next.png + resources/icon/OpenHS.png + resources/icon/Pause.png + resources/icon/Play.png + resources/icon/Previous.png + resources/icon/PrimaryKeyHS.png + resources/icon/Refresh.png + resources/icon/Request.png + resources/icon/OptionsHS.png + resources/icon/Web.png + resources/icon/RestartHS.png + resources/icon/Invert.png + resources/icon/RightHS.png + resources/icon/SaveHS.png - Resources/sound/choose.wav - Resources/sound/drog.wav - Resources/sound/forbidden.wav - Resources/sound/loss.wav - Resources/sound/move.wav - Resources/sound/newgame.wav - Resources/sound/remove.wav - Resources/sound/win.wav - Resources/sound/warning.wav - Resources/sound/capture.wav + resources/sound/choose.wav + resources/sound/drog.wav + resources/sound/forbidden.wav + resources/sound/loss.wav + resources/sound/move.wav + resources/sound/newgame.wav + resources/sound/remove.wav + resources/sound/win.wav + resources/sound/warning.wav + resources/sound/capture.wav diff --git a/NineChess/ninechesswindow.ui b/NineChess/ninechesswindow.ui index 2879b5e3..ee1c208f 100644 --- a/NineChess/ninechesswindow.ui +++ b/NineChess/ninechesswindow.ui @@ -39,7 +39,7 @@ - background-image: url(:/image/Resources/image/background.png); + background-image: url(:/image/resources/image/background.png); Qt::ScrollBarAlwaysOff @@ -57,7 +57,7 @@ 0 0 491 - 23 + 26 @@ -247,7 +247,7 @@ - :/icon/Resources/icon/Black.png + :/icon/resources/icon/Black.png Qt::AlignCenter @@ -328,7 +328,7 @@ - :/icon/Resources/icon/White.png + :/icon/resources/icon/White.png Qt::AlignCenter @@ -398,7 +398,7 @@ - :/icon/Resources/icon/Help.png + :/icon/resources/icon/Help.png @@ -424,7 +424,7 @@ - + 7 @@ -443,7 +443,7 @@ - :/icon/Resources/icon/DocumentHS.png:/icon/Resources/icon/DocumentHS.png + :/icon/resources/icon/DocumentHS.png:/icon/resources/icon/DocumentHS.png 新建(&N) @@ -458,7 +458,7 @@ - :/icon/Resources/icon/OpenHS.png:/icon/Resources/icon/OpenHS.png + :/icon/resources/icon/OpenHS.png:/icon/resources/icon/OpenHS.png 打开(&O)... @@ -470,7 +470,7 @@ - :/icon/Resources/icon/SaveHS.png:/icon/Resources/icon/SaveHS.png + :/icon/resources/icon/SaveHS.png:/icon/resources/icon/SaveHS.png 保存(&S) @@ -482,7 +482,7 @@ - :/icon/Resources/icon/SaveHS.png:/icon/Resources/icon/SaveHS.png + :/icon/resources/icon/SaveHS.png:/icon/resources/icon/SaveHS.png 另存为(&A)... @@ -499,7 +499,7 @@ - :/icon/Resources/icon/EditTableHS.png:/icon/Resources/icon/EditTableHS.png + :/icon/resources/icon/EditTableHS.png:/icon/resources/icon/EditTableHS.png 编辑棋局(&E) @@ -508,7 +508,7 @@ - :/icon/Resources/icon/FlipVerticalHS.png:/icon/Resources/icon/FlipVerticalHS.png + :/icon/resources/icon/FlipVerticalHS.png:/icon/resources/icon/FlipVerticalHS.png 上下翻转(&F) @@ -517,7 +517,7 @@ - :/icon/Resources/icon/FlipHorizontalHS.png:/icon/Resources/icon/FlipHorizontalHS.png + :/icon/resources/icon/FlipHorizontalHS.png:/icon/resources/icon/FlipHorizontalHS.png 左右翻转(&M) @@ -526,7 +526,7 @@ - :/icon/Resources/icon/RightHS.png:/icon/Resources/icon/RightHS.png + :/icon/resources/icon/RightHS.png:/icon/resources/icon/RightHS.png 顺时针旋转90°(&R) @@ -538,7 +538,7 @@ - :/icon/Resources/icon/LeftHS.png:/icon/Resources/icon/LeftHS.png + :/icon/resources/icon/LeftHS.png:/icon/resources/icon/LeftHS.png 逆时针旋转90°(&L) @@ -556,7 +556,7 @@ - :/icon/Resources/icon/Invert.png:/icon/Resources/icon/Invert.png + :/icon/resources/icon/Invert.png:/icon/resources/icon/Invert.png 黑白反转(&B) @@ -565,7 +565,7 @@ - :/icon/Resources/icon/First.png:/icon/Resources/icon/First.png + :/icon/resources/icon/First.png:/icon/resources/icon/First.png 初始局面(&S) @@ -580,7 +580,7 @@ - :/icon/Resources/icon/Previous.png:/icon/Resources/icon/Previous.png + :/icon/resources/icon/Previous.png:/icon/resources/icon/Previous.png 前一招(&B) @@ -592,7 +592,7 @@ - :/icon/Resources/icon/Next.png:/icon/Resources/icon/Next.png + :/icon/resources/icon/Next.png:/icon/resources/icon/Next.png 后一招(&F) @@ -607,7 +607,7 @@ - :/icon/Resources/icon/Last.png:/icon/Resources/icon/Last.png + :/icon/resources/icon/Last.png:/icon/resources/icon/Last.png 最后局面(&E) @@ -622,7 +622,7 @@ - :/icon/Resources/icon/Play.png:/icon/Resources/icon/Play.png + :/icon/resources/icon/Play.png:/icon/resources/icon/Play.png 自动演示(&A) @@ -634,7 +634,7 @@ - :/icon/Resources/icon/BreakpointHS.png:/icon/Resources/icon/BreakpointHS.png + :/icon/resources/icon/BreakpointHS.png:/icon/resources/icon/BreakpointHS.png 认输(&G) @@ -660,7 +660,7 @@ - :/icon/Resources/icon/FullScreenHS.png:/icon/Resources/icon/FullScreenHS.png + :/icon/resources/icon/FullScreenHS.png:/icon/resources/icon/FullScreenHS.png 本机对战(&L) @@ -678,7 +678,7 @@ - :/icon/Resources/icon/Web.png:/icon/Resources/icon/Web.png + :/icon/resources/icon/Web.png:/icon/resources/icon/Web.png 网络对战(&I) @@ -690,7 +690,7 @@ - :/icon/Resources/icon/OptionsHS.png:/icon/Resources/icon/OptionsHS.png + :/icon/resources/icon/OptionsHS.png:/icon/resources/icon/OptionsHS.png 引擎设置(&E)... @@ -708,7 +708,7 @@ - :/icon/Resources/icon/Black.png:/icon/Resources/icon/Black.png + :/icon/resources/icon/Black.png:/icon/resources/icon/Black.png 电脑执先手(&T) @@ -723,7 +723,7 @@ - :/icon/Resources/icon/White.png:/icon/Resources/icon/White.png + :/icon/resources/icon/White.png:/icon/resources/icon/White.png 电脑执后手(&R) @@ -738,7 +738,7 @@ - :/icon/Resources/icon/PrimaryKeyHS.png:/icon/Resources/icon/PrimaryKeyHS.png + :/icon/resources/icon/PrimaryKeyHS.png:/icon/resources/icon/PrimaryKeyHS.png 设置(&O)... @@ -808,7 +808,7 @@ - :/icon/Resources/icon/Help.png:/icon/Resources/icon/Help.png + :/icon/resources/icon/Help.png:/icon/resources/icon/Help.png 查看帮助(&V) @@ -820,7 +820,7 @@ - :/icon/Resources/icon/HomeHS.png:/icon/Resources/icon/HomeHS.png + :/icon/resources/icon/HomeHS.png:/icon/resources/icon/HomeHS.png 作者主页(&W) @@ -846,9 +846,9 @@
gameview.h
- SizeHintListView + ManualListView QListView -
sizehintlistview.h
+
manuallistview.h
diff --git a/NineChess/Resources/icon/1.png b/NineChess/resources/icon/1.png similarity index 100% rename from NineChess/Resources/icon/1.png rename to NineChess/resources/icon/1.png diff --git a/NineChess/Resources/icon/2.png b/NineChess/resources/icon/2.png similarity index 100% rename from NineChess/Resources/icon/2.png rename to NineChess/resources/icon/2.png diff --git a/NineChess/Resources/icon/ActualSizeHS.png b/NineChess/resources/icon/ActualSizeHS.png similarity index 100% rename from NineChess/Resources/icon/ActualSizeHS.png rename to NineChess/resources/icon/ActualSizeHS.png diff --git a/NineChess/Resources/icon/Black.png b/NineChess/resources/icon/Black.png similarity index 100% rename from NineChess/Resources/icon/Black.png rename to NineChess/resources/icon/Black.png diff --git a/NineChess/Resources/icon/BreakpointHS.png b/NineChess/resources/icon/BreakpointHS.png similarity index 100% rename from NineChess/Resources/icon/BreakpointHS.png rename to NineChess/resources/icon/BreakpointHS.png diff --git a/NineChess/Resources/icon/DocumentHS.png b/NineChess/resources/icon/DocumentHS.png similarity index 100% rename from NineChess/Resources/icon/DocumentHS.png rename to NineChess/resources/icon/DocumentHS.png diff --git a/NineChess/Resources/icon/EditInformationHS.png b/NineChess/resources/icon/EditInformationHS.png similarity index 100% rename from NineChess/Resources/icon/EditInformationHS.png rename to NineChess/resources/icon/EditInformationHS.png diff --git a/NineChess/Resources/icon/EditTableHS.png b/NineChess/resources/icon/EditTableHS.png similarity index 100% rename from NineChess/Resources/icon/EditTableHS.png rename to NineChess/resources/icon/EditTableHS.png diff --git a/NineChess/Resources/icon/Error.png b/NineChess/resources/icon/Error.png similarity index 100% rename from NineChess/Resources/icon/Error.png rename to NineChess/resources/icon/Error.png diff --git a/NineChess/Resources/icon/First.png b/NineChess/resources/icon/First.png similarity index 100% rename from NineChess/Resources/icon/First.png rename to NineChess/resources/icon/First.png diff --git a/NineChess/Resources/icon/FlipHorizontalHS.png b/NineChess/resources/icon/FlipHorizontalHS.png similarity index 100% rename from NineChess/Resources/icon/FlipHorizontalHS.png rename to NineChess/resources/icon/FlipHorizontalHS.png diff --git a/NineChess/Resources/icon/FlipVerticalHS.png b/NineChess/resources/icon/FlipVerticalHS.png similarity index 100% rename from NineChess/Resources/icon/FlipVerticalHS.png rename to NineChess/resources/icon/FlipVerticalHS.png diff --git a/NineChess/Resources/icon/FullScreenHS.png b/NineChess/resources/icon/FullScreenHS.png similarity index 100% rename from NineChess/Resources/icon/FullScreenHS.png rename to NineChess/resources/icon/FullScreenHS.png diff --git a/NineChess/Resources/icon/Help.png b/NineChess/resources/icon/Help.png similarity index 100% rename from NineChess/Resources/icon/Help.png rename to NineChess/resources/icon/Help.png diff --git a/NineChess/Resources/icon/HomeHS.png b/NineChess/resources/icon/HomeHS.png similarity index 100% rename from NineChess/Resources/icon/HomeHS.png rename to NineChess/resources/icon/HomeHS.png diff --git a/NineChess/Resources/icon/Invert.png b/NineChess/resources/icon/Invert.png similarity index 100% rename from NineChess/Resources/icon/Invert.png rename to NineChess/resources/icon/Invert.png diff --git a/NineChess/Resources/icon/Last.png b/NineChess/resources/icon/Last.png similarity index 100% rename from NineChess/Resources/icon/Last.png rename to NineChess/resources/icon/Last.png diff --git a/NineChess/Resources/icon/LeftHS.png b/NineChess/resources/icon/LeftHS.png similarity index 100% rename from NineChess/Resources/icon/LeftHS.png rename to NineChess/resources/icon/LeftHS.png diff --git a/NineChess/Resources/icon/LegendHS.png b/NineChess/resources/icon/LegendHS.png similarity index 100% rename from NineChess/Resources/icon/LegendHS.png rename to NineChess/resources/icon/LegendHS.png diff --git a/NineChess/Resources/icon/NewDocumentHS.png b/NineChess/resources/icon/NewDocumentHS.png similarity index 100% rename from NineChess/Resources/icon/NewDocumentHS.png rename to NineChess/resources/icon/NewDocumentHS.png diff --git a/NineChess/Resources/icon/Next.png b/NineChess/resources/icon/Next.png similarity index 100% rename from NineChess/Resources/icon/Next.png rename to NineChess/resources/icon/Next.png diff --git a/NineChess/Resources/icon/OpenHS.png b/NineChess/resources/icon/OpenHS.png similarity index 100% rename from NineChess/Resources/icon/OpenHS.png rename to NineChess/resources/icon/OpenHS.png diff --git a/NineChess/Resources/icon/OptionsHS.png b/NineChess/resources/icon/OptionsHS.png similarity index 100% rename from NineChess/Resources/icon/OptionsHS.png rename to NineChess/resources/icon/OptionsHS.png diff --git a/NineChess/Resources/icon/Pause.png b/NineChess/resources/icon/Pause.png similarity index 100% rename from NineChess/Resources/icon/Pause.png rename to NineChess/resources/icon/Pause.png diff --git a/NineChess/Resources/icon/Play.png b/NineChess/resources/icon/Play.png similarity index 100% rename from NineChess/Resources/icon/Play.png rename to NineChess/resources/icon/Play.png diff --git a/NineChess/Resources/icon/Previous.png b/NineChess/resources/icon/Previous.png similarity index 100% rename from NineChess/Resources/icon/Previous.png rename to NineChess/resources/icon/Previous.png diff --git a/NineChess/Resources/icon/PrimaryKeyHS.png b/NineChess/resources/icon/PrimaryKeyHS.png similarity index 100% rename from NineChess/Resources/icon/PrimaryKeyHS.png rename to NineChess/resources/icon/PrimaryKeyHS.png diff --git a/NineChess/Resources/icon/Refresh.png b/NineChess/resources/icon/Refresh.png similarity index 100% rename from NineChess/Resources/icon/Refresh.png rename to NineChess/resources/icon/Refresh.png diff --git a/NineChess/Resources/icon/Request.png b/NineChess/resources/icon/Request.png similarity index 100% rename from NineChess/Resources/icon/Request.png rename to NineChess/resources/icon/Request.png diff --git a/NineChess/Resources/icon/RestartHS.png b/NineChess/resources/icon/RestartHS.png similarity index 100% rename from NineChess/Resources/icon/RestartHS.png rename to NineChess/resources/icon/RestartHS.png diff --git a/NineChess/Resources/icon/RightHS.png b/NineChess/resources/icon/RightHS.png similarity index 100% rename from NineChess/Resources/icon/RightHS.png rename to NineChess/resources/icon/RightHS.png diff --git a/NineChess/Resources/icon/SaveHS.png b/NineChess/resources/icon/SaveHS.png similarity index 100% rename from NineChess/Resources/icon/SaveHS.png rename to NineChess/resources/icon/SaveHS.png diff --git a/NineChess/Resources/icon/Web.png b/NineChess/resources/icon/Web.png similarity index 100% rename from NineChess/Resources/icon/Web.png rename to NineChess/resources/icon/Web.png diff --git a/NineChess/Resources/icon/White.png b/NineChess/resources/icon/White.png similarity index 100% rename from NineChess/Resources/icon/White.png rename to NineChess/resources/icon/White.png diff --git a/NineChess/Resources/image/background.png b/NineChess/resources/image/background.png similarity index 100% rename from NineChess/Resources/image/background.png rename to NineChess/resources/image/background.png diff --git a/NineChess/Resources/image/black_piece.png b/NineChess/resources/image/black_piece.png similarity index 100% rename from NineChess/Resources/image/black_piece.png rename to NineChess/resources/image/black_piece.png diff --git a/NineChess/Resources/image/board.png b/NineChess/resources/image/board.png similarity index 100% rename from NineChess/Resources/image/board.png rename to NineChess/resources/image/board.png diff --git a/NineChess/Resources/image/current.png b/NineChess/resources/image/current.png similarity index 100% rename from NineChess/Resources/image/current.png rename to NineChess/resources/image/current.png diff --git a/NineChess/Resources/image/remove.png b/NineChess/resources/image/remove.png similarity index 100% rename from NineChess/Resources/image/remove.png rename to NineChess/resources/image/remove.png diff --git a/NineChess/Resources/image/white_piece.png b/NineChess/resources/image/white_piece.png similarity index 100% rename from NineChess/Resources/image/white_piece.png rename to NineChess/resources/image/white_piece.png diff --git a/NineChess/Resources/image/xy.png b/NineChess/resources/image/xy.png similarity index 100% rename from NineChess/Resources/image/xy.png rename to NineChess/resources/image/xy.png diff --git a/NineChess/Resources/sound/capture.wav b/NineChess/resources/sound/capture.wav similarity index 100% rename from NineChess/Resources/sound/capture.wav rename to NineChess/resources/sound/capture.wav diff --git a/NineChess/Resources/sound/choose.wav b/NineChess/resources/sound/choose.wav similarity index 100% rename from NineChess/Resources/sound/choose.wav rename to NineChess/resources/sound/choose.wav diff --git a/NineChess/Resources/sound/drog.wav b/NineChess/resources/sound/drog.wav similarity index 100% rename from NineChess/Resources/sound/drog.wav rename to NineChess/resources/sound/drog.wav diff --git a/NineChess/Resources/sound/forbidden.wav b/NineChess/resources/sound/forbidden.wav similarity index 100% rename from NineChess/Resources/sound/forbidden.wav rename to NineChess/resources/sound/forbidden.wav diff --git a/NineChess/Resources/sound/loss.wav b/NineChess/resources/sound/loss.wav similarity index 100% rename from NineChess/Resources/sound/loss.wav rename to NineChess/resources/sound/loss.wav diff --git a/NineChess/Resources/sound/move.wav b/NineChess/resources/sound/move.wav similarity index 100% rename from NineChess/Resources/sound/move.wav rename to NineChess/resources/sound/move.wav diff --git a/NineChess/Resources/sound/newgame.wav b/NineChess/resources/sound/newgame.wav similarity index 100% rename from NineChess/Resources/sound/newgame.wav rename to NineChess/resources/sound/newgame.wav diff --git a/NineChess/Resources/sound/remove.wav b/NineChess/resources/sound/remove.wav similarity index 100% rename from NineChess/Resources/sound/remove.wav rename to NineChess/resources/sound/remove.wav diff --git a/NineChess/Resources/sound/warning.wav b/NineChess/resources/sound/warning.wav similarity index 100% rename from NineChess/Resources/sound/warning.wav rename to NineChess/resources/sound/warning.wav diff --git a/NineChess/Resources/sound/win.wav b/NineChess/resources/sound/win.wav similarity index 100% rename from NineChess/Resources/sound/win.wav rename to NineChess/resources/sound/win.wav diff --git a/NineChess/src/aithread.cpp b/NineChess/src/aithread.cpp index 4528a0d6..2078b34c 100644 --- a/NineChess/src/aithread.cpp +++ b/NineChess/src/aithread.cpp @@ -1,4 +1,4 @@ -#include +#include #include "aithread.h" AiThread::AiThread(QObject *parent) : QThread(parent), @@ -13,13 +13,21 @@ AiThread::~AiThread() wait(); } +void AiThread::setAi(const NineChess &chess) +{ + mutex.lock(); + this->chess = chess; + ai_ab.setChess(chess); + mutex.unlock(); +} + void AiThread::run() { // 测试用数据 int iTemp = 0; while (true) { - if(isInterruptionRequested()) + if (isInterruptionRequested()) return; mutex.lock(); if (waiting_) @@ -29,17 +37,10 @@ void AiThread::run() // 测试用 qDebug() << "thread running " << iTemp << "ms"; msleep(250); - iTemp+=250; + iTemp += 250; } } -void AiThread::setChess(NineChess &chess) -{ - mutex.lock(); - this->chess = chess; - mutex.unlock(); -} - void AiThread::pause() { mutex.lock(); diff --git a/NineChess/src/aithread.h b/NineChess/src/aithread.h index 047ff915..48f581b6 100644 --- a/NineChess/src/aithread.h +++ b/NineChess/src/aithread.h @@ -1,27 +1,29 @@ -#ifndef AITHREAD_H +#ifndef AITHREAD_H #define AITHREAD_H #include #include #include #include "ninechess.h" +#include "ninechessai_ab.h" class AiThread : public QThread { Q_OBJECT + public: explicit AiThread(QObject *parent = nullptr); ~AiThread(); signals: // 招法信号 - void command(QString cmdline); + void command(const QString &cmdline, bool update = true); protected: void run() override; public slots: - void setChess(NineChess &); + void setAi(const NineChess &); void pause(); void resume(); void stop(); @@ -36,6 +38,8 @@ private: // 棋类 NineChess chess; + // Alpha-Beta剪枝算法类 + NineChessAi_ab ai_ab; }; #endif // AITHREAD_H diff --git a/NineChess/src/boarditem.cpp b/NineChess/src/boarditem.cpp index b37d4205..d37f5c22 100644 --- a/NineChess/src/boarditem.cpp +++ b/NineChess/src/boarditem.cpp @@ -63,10 +63,13 @@ void BoardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + Q_UNUSED(option) + Q_UNUSED(widget) + // 填充阴影 painter->fillRect(boundingRect(), QBrush(QColor(64, 64, 64))); // 填充图片 - painter->drawPixmap(-size/2, -size/2, size, size, QPixmap(":/image/Resources/image/board.png")); + painter->drawPixmap(-size/2, -size/2, size, size, QPixmap(":/image/resources/image/board.png")); // 黑色实线画笔 QPen pen(QBrush(Qt::black), LINE_WEIGHT, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin); painter->setPen(pen); diff --git a/NineChess/src/gamecontroller.cpp b/NineChess/src/gamecontroller.cpp index a382ea0a..d6c57f8e 100644 --- a/NineChess/src/gamecontroller.cpp +++ b/NineChess/src/gamecontroller.cpp @@ -17,37 +17,42 @@ #include "boarditem.h" GameController::GameController(GameScene &scene, QObject *parent) : QObject(parent), -// 是否浏览过历史纪录 -scene(scene), -currentPiece(nullptr), -currentRow(-1), -isEditing(false), -isInverted(false), -isEngine1(false), -isEngine2(false), -hasAnimation(true), -durationTime(250), -hasSound(true), -timeID(0), -ruleNo(-1), -timeLimit(0), -stepsLimit(0) + scene(scene), + currentPiece(nullptr), + currentRow(-1), + isEditing(false), + isInverted(false), + isEngine1(false), + isEngine2(false), + hasAnimation(true), + durationTime(250), + hasSound(true), + timeID(0), + ruleNo(-1), + timeLimit(0), + stepsLimit(0) { // 已在view的样式表中添加背景,scene中不用添加背景 // 区别在于,view中的背景不随视图变换而变换,scene中的背景随视图变换而变换 - //scene.setBackgroundBrush(QPixmap(":/image/Resources/image/background.png")); + //scene.setBackgroundBrush(QPixmap(":/image/resources/image/background.png")); gameReset(); + + // 关联AI和控制器的招法命令行 + connect(&ai1, SIGNAL(command(const QString &, bool)), + this, SLOT(command(const QString &, bool))); + connect(&ai2, SIGNAL(command(const QString &, bool)), + this, SLOT(command(const QString &, bool))); + // 安装事件过滤器监视scene的各个事件,由于我重载了QGraphicsScene,相关事件在重载函数中已设定,不必安装监视器。 //scene.installEventFilter(this); } GameController::~GameController() { - // 清除棋子 - qDeleteAll(pieceList); - pieceList.clear(); - currentPiece = nullptr; + // 停止计时器 + if (timeID != 0) + killTimer(timeID); } const QMap GameController::getActions() @@ -86,7 +91,7 @@ void GameController::gameReset() timeID = 0; // 重置游戏 chess.reset(); - chessTemp.reset(); + chessTemp = chess; // 清除棋子 qDeleteAll(pieceList); @@ -123,7 +128,6 @@ void GameController::gameReset() scene.addItem(newP); } - // 读取规则限时要求 timeLimit = chess.getRule()->maxTime; // 如果规则不要求计时,则time1和time2表示已用时间 @@ -150,7 +154,7 @@ void GameController::gameReset() message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放音效 - playSound(":/sound/Resources/sound/newgame.wav"); + playSound(":/sound/resources/sound/newgame.wav"); } void GameController::setEditing(bool arg) @@ -202,7 +206,7 @@ void GameController::setEngine1(bool arg) isEngine1 = arg; if (arg) { qDebug() << "Player1 is computer."; - ai1.setChess(chess); + ai1.setAi(chess); ai1.start(); } else { @@ -214,14 +218,7 @@ void GameController::setEngine1(bool arg) void GameController::setEngine2(bool arg) { isEngine2 = arg; - if (arg) { - qDebug() << "Player2 is computer."; -// ai2.start(); - } - else { - qDebug() << "Player2 is not computer."; - ai2.stop(); - } + } void GameController::setAnimation(bool arg) @@ -279,9 +276,11 @@ void GameController::timerEvent(QTimerEvent *event) message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放音效 - playSound(":/sound/Resources/sound/win.wav"); + playSound(":/sound/resources/sound/win.wav"); } - /* + + // 测试用代码 + /* int ti = time.elapsed(); static QTime t; if (ti < 0) @@ -305,7 +304,7 @@ void GameController::timerEvent(QTimerEvent *event) */ } -bool GameController::command(QString &cmd, bool update /*= true*/) +bool GameController::command(const QString &cmd, bool update /*= true*/) { if (chess.command(cmd.toStdString().c_str())) { if (chess.getPhase() == NineChess::GAME_NOTSTARTED) { @@ -379,6 +378,14 @@ bool GameController::actionPiece(QPointF pos) { chess = chessTemp; manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1); + // 如果再决出胜负后悔棋,则重新启动计时 + if (chess.whoWin() == NineChess::NOBODY) { + // 重新启动计时 + timeID = startTimer(100); + // 发信号更新状态栏 + message = QString::fromStdString(chess.getTip()); + emit statusBarChanged(message); + } } else { @@ -414,8 +421,6 @@ bool GameController::actionPiece(QPointF pos) else if (chess.getAction() == NineChess::ACTION_PLACE) { // 如果移子不成功,尝试重新选子 result = movePiece(pos); - if (!result) - result = choosePiece(pos); }// 去子 else if (chess.getAction() == NineChess::ACTION_REMOVE) { result = removePiece(pos); @@ -442,7 +447,7 @@ bool GameController::actionPiece(QPointF pos) } if (chess.whoWin() != NineChess::NOBODY && (manualListModel.data(manualListModel.index(currentRow-1))).toString().contains("Time over.")) - playSound(":/sound/Resources/sound/win.wav"); + playSound(":/sound/resources/sound/win.wav"); } updateScence(); @@ -467,12 +472,12 @@ bool GameController::choosePiece(QPointF pos) message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放选子音效 - playSound(":/sound/Resources/sound/choose.wav"); + playSound(":/sound/resources/sound/choose.wav"); return true; } else { // 播放禁止音效 - playSound(":/sound/Resources/sound/forbidden.wav"); + playSound(":/sound/resources/sound/forbidden.wav"); return false; } } @@ -486,14 +491,14 @@ bool GameController::placePiece(QPointF pos) } if (!chess.place(c, p)) { // 播放禁止音效 - playSound(":/sound/Resources/sound/forbidden.wav"); + playSound(":/sound/resources/sound/forbidden.wav"); return false; } // 发信号更新状态栏 message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放音效 - playSound(":/sound/Resources/sound/drog.wav"); + playSound(":/sound/resources/sound/drog.wav"); return true; } @@ -514,12 +519,14 @@ bool GameController::movePiece(QPointF pos) message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放音效 - playSound(":/sound/Resources/sound/move.wav"); + playSound(":/sound/resources/sound/move.wav"); return true; } - // 播放禁止音效 - playSound(":/sound/Resources/sound/forbidden.wav"); - return false; + // 如果移子不成功,尝试重新选子 + else + { + return choosePiece(pos); + } } // 去子 @@ -531,7 +538,7 @@ bool GameController::removePiece(QPointF pos) } if (!chess.remove(c, p)) { // 播放禁止音效 - playSound(":/sound/Resources/sound/forbidden.wav"); + playSound(":/sound/resources/sound/forbidden.wav"); return false; } @@ -539,7 +546,7 @@ bool GameController::removePiece(QPointF pos) message = QString::fromStdString(chess.getTip()); emit statusBarChanged(message); // 播放音效 - playSound(":/sound/Resources/sound/remove.wav"); + playSound(":/sound/resources/sound/remove.wav"); return true; } @@ -564,7 +571,7 @@ bool GameController::giveUp() manualListModel.setData(manualListModel.index(currentRow), (*i).c_str()); } if (chess.whoWin() != NineChess::NOBODY) - playSound(":/sound/Resources/sound/loss.wav"); + playSound(":/sound/resources/sound/loss.wav"); } return result; } diff --git a/NineChess/src/gamecontroller.h b/NineChess/src/gamecontroller.h index de5ac46b..13deae2c 100644 --- a/NineChess/src/gamecontroller.h +++ b/NineChess/src/gamecontroller.h @@ -72,7 +72,7 @@ public slots: // 认输 bool giveUp(); // 棋谱的命令行执行 - bool command(QString &cmd, bool update = true); + bool command(const QString &cmd, bool update = true); // 历史局面及局面改变 bool phaseChange(int row); // 更新棋局显示,每步后必须执行 diff --git a/NineChess/src/gamescene.cpp b/NineChess/src/gamescene.cpp index 9a062743..3ac7ddcc 100644 --- a/NineChess/src/gamescene.cpp +++ b/NineChess/src/gamescene.cpp @@ -27,24 +27,27 @@ GameScene::~GameScene() delete board; } +// 屏蔽掉Shift和Control按键,事实证明没用,按键事件未必由视图类处理 +/* void GameScene::keyPressEvent(QKeyEvent *keyEvent) { - // 屏蔽掉Shift和Control按键,事实证明没用,按键事件未必由视图类处理 if(keyEvent->key() == Qt::Key_Shift || keyEvent->key() == Qt::Key_Control) return; QGraphicsScene::keyPressEvent(keyEvent); } +*/ void GameScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent) { - //什么也不做,屏蔽双击事件 - Q_UNUSED(mouseEvent) + //屏蔽双击事件 + mouseEvent->accept(); } + void GameScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) { - //什么也不做,屏蔽鼠标按下事件 - Q_UNUSED(mouseEvent) + //屏蔽鼠标按下事件 + mouseEvent->accept(); /* // 只处理左键事件 if(mouseEvent->button() != Qt::LeftButton) @@ -64,8 +67,10 @@ void GameScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) void GameScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) { // 只处理左键事件 - if(mouseEvent->button() != Qt::LeftButton) + if (mouseEvent->button() != Qt::LeftButton) { + mouseEvent->accept(); return; + } // 如果是棋盘 QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform()); @@ -83,6 +88,8 @@ void GameScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) emit mouseReleased(item->scenePos()); } + mouseEvent->accept(); + // 调用默认事件处理函数 //QGraphicsScene::mouseReleaseEvent(mouseEvent); } diff --git a/NineChess/src/gamescene.h b/NineChess/src/gamescene.h index fb6884e9..8b27b991 100644 --- a/NineChess/src/gamescene.h +++ b/NineChess/src/gamescene.h @@ -23,7 +23,7 @@ public: const QPointF pos_p2, pos_p2_g; protected: - void keyPressEvent(QKeyEvent *keyEvent); + //void keyPressEvent(QKeyEvent *keyEvent); void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent); void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); diff --git a/NineChess/src/sizehintlistview.h b/NineChess/src/manuallistview.h similarity index 79% rename from NineChess/src/sizehintlistview.h rename to NineChess/src/manuallistview.h index 8c611649..55871aa9 100644 --- a/NineChess/src/sizehintlistview.h +++ b/NineChess/src/manuallistview.h @@ -7,18 +7,20 @@ * 但调节停靠栏宽度后就不好看了 */ -#ifndef SIZEHINTLISTVIEW -#define SIZEHINTLISTVIEW +#ifndef MANUALLISTVIEW +#define MANUALLISTVIEW #include #include -class SizeHintListView : public QListView +class ManualListView : public QListView { Q_OBJECT public: - SizeHintListView(QWidget * parent = nullptr) { Q_UNUSED(parent) } + ManualListView(QWidget * parent = nullptr) : QListView (parent) { + Q_UNUSED(parent) + } QSize sizeHint() const { QSize size = QListView::sizeHint(); // 缺省宽度设为128,这样就不太宽了 @@ -50,11 +52,16 @@ protected slots: // 采用判断最后一个元素是否改变来选中之 void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()) { - QAbstractItemView::dataChanged(topLeft, bottomRight, roles); - QModelIndex index = model()->index(model()->rowCount() - 1, 0); - if (index == bottomRight) { - setCurrentIndex(index); - scrollToBottom(); + // 调用父类默认函数 + QListView::dataChanged(topLeft, bottomRight, roles); + // 如果包含model + if (model()) { + // 判断 + QModelIndex index = model()->index(model()->rowCount() - 1, 0); + if (index == bottomRight) { + setCurrentIndex(index); + scrollToBottom(); + } } } @@ -66,5 +73,4 @@ protected slots: } }; -#endif // SIZEHINTLISTVIEW - +#endif // MANUALLISTVIEW diff --git a/NineChess/src/ninechess.cpp b/NineChess/src/ninechess.cpp index 6eac615d..f3aaaf9b 100644 --- a/NineChess/src/ninechess.cpp +++ b/NineChess/src/ninechess.cpp @@ -130,44 +130,44 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla this->rule.maxSteps = s; this->rule.maxTime = t; // 设置步数 - this->step = step; + data_.step = step; // 设置状态 // 局面阶段标识 if (flags & GAME_NOTSTARTED) - phase = GAME_NOTSTARTED; + data_.phase = GAME_NOTSTARTED; else if (flags & GAME_OPENING) - phase = GAME_OPENING; + data_.phase = GAME_OPENING; else if (flags & GAME_MID) - phase = GAME_MID; + data_.phase = GAME_MID; else if (flags & GAME_OVER) - phase = GAME_OVER; + data_.phase = GAME_OVER; else return false; // 轮流状态标识 if (flags & PLAYER1) - turn = PLAYER1; + data_.turn = PLAYER1; else if (flags & PLAYER2) - turn = PLAYER2; + data_.turn = PLAYER2; else return false; // 动作状态标识 if (flags & ACTION_CHOOSE) - action = ACTION_CHOOSE; + data_.action = ACTION_CHOOSE; else if (flags & ACTION_PLACE) - action = ACTION_PLACE; + data_.action = ACTION_PLACE; else if (flags & ACTION_REMOVE) - action = ACTION_REMOVE; + data_.action = ACTION_REMOVE; else return false; // 胜负标识 - winner = NOBODY; + data_.winner = NOBODY; // 当前棋局(3×8) if (boardsource == nullptr) - memset(this->board, 0, sizeof(this->board)); + memset(data_.board, 0, sizeof(data_.board)); else - memcpy(this->board, boardsource, sizeof(this->board)); + memcpy(data_.board, boardsource, sizeof(data_.board)); // 生成招法表 for (int i = 1; i <= RING; i++) { @@ -257,38 +257,38 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla } // 计算盘面子数 - player1_Remain = player2_Remain = 0; + data_.player1_Remain = data_.player2_Remain = 0; for (int i = 1; i < RING + 2; i++) { for (int j = 0; j < SEAT; j++) { - if (board[i*SEAT + j] & '\x10') - player1_Remain++; - else if (board[i*SEAT + j] & '\x20') { - player2_Remain++; + if (data_.board[i*SEAT + j] & '\x10') + data_.player1_Remain++; + else if (data_.board[i*SEAT + j] & '\x20') { + data_.player2_Remain++; } } } // 设置玩家盘面剩余子数和未放置子数 - if (player1_Remain > rule->numOfChess || player2_Remain > rule->numOfChess) + if (data_.player1_Remain > rule->numOfChess || data_.player2_Remain > rule->numOfChess) return false; if (p1_InHand < 0 || p2_InHand < 0) return false; - player1_InHand = rule->numOfChess - player1_Remain; - player2_InHand = rule->numOfChess - player2_Remain; - player1_InHand = p1_InHand < player1_InHand ? p1_InHand : player1_InHand; - player2_InHand = p2_InHand < player2_InHand ? p2_InHand : player2_InHand; + data_.player1_InHand = rule->numOfChess - data_.player1_Remain; + data_.player2_InHand = rule->numOfChess - data_.player2_Remain; + data_.player1_InHand = p1_InHand < data_.player1_InHand ? p1_InHand : data_.player1_InHand; + data_.player2_InHand = p2_InHand < data_.player2_InHand ? p2_InHand : data_.player2_InHand; // 设置去子状态时的剩余尚待去除子数 if (flags & ACTION_REMOVE) { if (num_NeedRemove >= 0 && num_NeedRemove < 3) - this->num_NeedRemove = num_NeedRemove; + data_.num_NeedRemove = num_NeedRemove; } else - this->num_NeedRemove = 0; + data_.num_NeedRemove = 0; // 清空成三记录 - millList.clear(); + data_.millList.clear(); // 不选中棋子 currentPos = 0; @@ -322,53 +322,53 @@ void NineChess::getData(struct Rule &rule, int &step, int &chess, const char *&b int &p1_InHand, int &p2_InHand, int &num_NeedRemove) { rule = this->rule; - step = this->step; - chess = phase | turn | action | winner; - board = this->board; - p1_InHand = player1_InHand; - p2_InHand = player2_InHand; - num_NeedRemove = this->num_NeedRemove; + step = data_.step; + chess = data_.phase | data_.turn | data_.action | data_.winner; + board = data_.board; + p1_InHand = data_.player1_InHand; + p2_InHand = data_.player2_InHand; + num_NeedRemove = data_.num_NeedRemove; } const char * NineChess::getBoard() { - return board; + return data_.board; } bool NineChess::reset() { - if (phase == GAME_NOTSTARTED && player1_MS == player2_MS == 0) + if (data_.phase == GAME_NOTSTARTED && player1_MS == player2_MS == 0) return true; // 步数归零 - step = 0; + data_.step = 0; // 局面阶段标识 - phase = GAME_NOTSTARTED; + data_.phase = GAME_NOTSTARTED; // 轮流状态标识 - turn = PLAYER1; + data_.turn = PLAYER1; // 动作状态标识 - action = ACTION_PLACE; + data_.action = ACTION_PLACE; // 胜负标识 - winner = NOBODY; + data_.winner = NOBODY; // 当前棋局(3×8) - memset(board, 0, sizeof(board)); + memset(data_.board, 0, sizeof(data_.board)); // 盘面子数归零 - player1_Remain = player2_Remain = 0; + data_.player1_Remain = data_.player2_Remain = 0; // 设置玩家盘面剩余子数和未放置子数 - player1_InHand = player2_InHand = rule.numOfChess; + data_.player1_InHand = data_.player2_InHand = rule.numOfChess; // 设置去子状态时的剩余尚待去除子数 - num_NeedRemove = 0; + data_.num_NeedRemove = 0; // 清空成三记录 - millList.clear(); + data_.millList.clear(); // 不选中棋子 currentPos = 0; @@ -401,16 +401,16 @@ bool NineChess::reset() bool NineChess::start() { // 如果游戏已经开始,则返回false - if (phase == GAME_OPENING || phase == GAME_MID) + if (data_.phase == GAME_OPENING || data_.phase == GAME_MID) return false; // 如果游戏结束,则重置游戏,进入未开始状态 - if (phase == GAME_OVER) + if (data_.phase == GAME_OVER) reset(); // 如果游戏处于未开始状态 - if (phase == GAME_NOTSTARTED) { - phase = GAME_OPENING; + if (data_.phase == GAME_NOTSTARTED) { + data_.phase = GAME_OPENING; // 启动计时器 ftime(&startTimeb); } @@ -429,18 +429,18 @@ int NineChess::cp2pos(int c, int p) bool NineChess::place(int c, int p, long time_p /* = -1*/) { // 如果局面为“结局”,返回false - if (phase == GAME_OVER) + if (data_.phase == GAME_OVER) return false; // 如果局面为“未开局”,则开具 - if (phase == GAME_NOTSTARTED) + if (data_.phase == GAME_NOTSTARTED) start(); // 如非“落子”状态,返回false - if (action != ACTION_PLACE) + if (data_.action != ACTION_PLACE) return false; // 如果落子位置在棋盘外、已有子点或禁点,返回false int pos = cp2pos(c, p); - if (!inBoard[pos] || board[pos]) + if (!inBoard[pos] || data_.board[pos]) return false; // 时间的临时变量 long player_ms = -1; @@ -448,28 +448,29 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) // 对于开局落子 char piece = '\x00'; int n = 0; - if (phase == GAME_OPENING) { + if (data_.phase == GAME_OPENING) { // 先手下 - if (turn == PLAYER1) + if (data_.turn == PLAYER1) { - piece = '\x11' + rule.numOfChess - player1_InHand; - board[pos] = piece; - player1_InHand--; - player1_Remain++; + piece = '\x11' + rule.numOfChess - data_.player1_InHand; + data_.board[pos] = piece; + data_.player1_InHand--; + data_.player1_Remain++; } // 后手下 else { - piece = '\x21' + rule.numOfChess - player2_InHand; - board[pos] = piece; - player2_InHand--; - player2_Remain++; + piece = '\x21' + rule.numOfChess - data_.player2_InHand; + data_.board[pos] = piece; + data_.player2_InHand--; + data_.player2_Remain++; } player_ms = update(time_p); + data_.move_ = pos; sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000); cmdlist.push_back(string(cmdline)); currentPos = pos; - step++; + data_.step++; // 如果决出胜负 if (win()) { setTip(); @@ -480,19 +481,19 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) // 开局阶段未成三 if (n == 0) { // 如果双方都无未放置的棋子 - if (player1_InHand == 0 && player2_InHand == 0) { + if (data_.player1_InHand == 0 && data_.player2_InHand == 0) { // 进入中局阶段 - phase = GAME_MID; + data_.phase = GAME_MID; // 进入选子状态 - action = ACTION_CHOOSE; + data_.action = ACTION_CHOOSE; // 清除禁点 cleanForbidden(); // 设置轮到谁走 if (rule.isDefensiveMoveFirst) { - turn = PLAYER2; + data_.turn = PLAYER2; } else { - turn = PLAYER1; + data_.turn = PLAYER1; } // 再决胜负 if (win()) { @@ -509,19 +510,19 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) // 如果成三 else { // 设置去子数目 - num_NeedRemove = rule.removeMore ? n : 1; + data_.num_NeedRemove = rule.removeMore ? n : 1; // 进入去子状态 - action = ACTION_REMOVE; + data_.action = ACTION_REMOVE; } setTip(); return true; } // 对于中局落子 - else if (phase == GAME_MID) { + else if (data_.phase == GAME_MID) { // 如果落子不合法 - if ((turn == PLAYER1 && (player1_Remain > rule.numAtLest || !rule.canFly)) || - (turn == PLAYER2 && (player2_Remain > rule.numAtLest || !rule.canFly))) { + if ((data_.turn == PLAYER1 && (data_.player1_Remain > rule.numAtLest || !rule.canFly)) || + (data_.turn == PLAYER2 && (data_.player2_Remain > rule.numAtLest || !rule.canFly))) { int i; for (i = 0; i < 4; i++) { if (pos == moveTable[currentPos][i]) @@ -533,19 +534,20 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) } // 移子 player_ms = update(time_p); + data_.move_ = (currentPos << 8) | pos; sprintf(cmdline, "(%1u,%1u)->(%1u,%1u) %02u:%02u.%03u", currentPos / SEAT, currentPos % SEAT + 1, c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000); cmdlist.push_back(string(cmdline)); - board[pos] = board[currentPos]; - board[currentPos] = '\x00'; + data_.board[pos] = data_.board[currentPos]; + data_.board[currentPos] = '\x00'; currentPos = pos; - step++; + data_.step++; n = addMills(currentPos); // 中局阶段未成三 if (n == 0) { // 进入选子状态 - action = ACTION_CHOOSE; + data_.action = ACTION_CHOOSE; // 设置轮到谁走 changeTurn(); // 如果决出胜负 @@ -557,9 +559,9 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) // 中局阶段成三 else { // 设置去子数目 - num_NeedRemove = rule.removeMore ? n : 1; + data_.num_NeedRemove = rule.removeMore ? n : 1; // 进入去子状态 - action = ACTION_REMOVE; + data_.action = ACTION_REMOVE; setTip(); } setTip(); @@ -572,20 +574,20 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) bool NineChess::remove(int c, int p, long time_p /* = -1*/) { // 如果局面为"未开局"或“结局”,返回false - if (phase == GAME_NOTSTARTED || phase == GAME_OVER) + if (data_.phase == GAME_NOTSTARTED || data_.phase == GAME_OVER) return false; // 如非“去子”状态,返回false - if (action != ACTION_REMOVE) + if (data_.action != ACTION_REMOVE) return false; // 如果去子完成,返回false - if (num_NeedRemove <= 0) + if (data_.num_NeedRemove <= 0) return false; // 时间的临时变量 long player_ms = -1; int pos = cp2pos(c, p); // 对手 enum Player opponent = PLAYER2; - if (turn == PLAYER2) + if (data_.turn == PLAYER2) opponent = PLAYER1; // 判断去子不是对手棋 if (getWhosPiece(c, p) != opponent) @@ -597,20 +599,21 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/) } // 去子(设置禁点) - if (rule.hasForbidden && phase == GAME_OPENING) - board[pos] = '\x0f'; + if (rule.hasForbidden && data_.phase == GAME_OPENING) + data_.board[pos] = '\x0f'; else // 去子 - board[pos] = '\x00'; - if (turn == PLAYER1) - player2_Remain--; - else if (turn == PLAYER2) - player1_Remain--; + data_.board[pos] = '\x00'; + if (data_.turn == PLAYER1) + data_.player2_Remain--; + else if (data_.turn == PLAYER2) + data_.player1_Remain--; player_ms = update(time_p); + data_.move_ = 0xFF00 | pos; sprintf(cmdline, "-(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000); cmdlist.push_back(string(cmdline)); currentPos = 0; - num_NeedRemove--; - step++; + data_.num_NeedRemove--; + data_.step++; // 去子完成 // 如果决出胜负 @@ -619,28 +622,28 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/) return true; } // 还有其余的子要去吗 - if (num_NeedRemove > 0) { + if (data_.num_NeedRemove > 0) { // 继续去子 return true; } // 所有去子都完成了 else { // 开局阶段 - if (phase == GAME_OPENING) { + if (data_.phase == GAME_OPENING) { // 如果双方都无未放置的棋子 - if (player1_InHand == 0 && player2_InHand == 0) { + if (data_.player1_InHand == 0 && data_.player2_InHand == 0) { // 进入中局阶段 - phase = GAME_MID; + data_.phase = GAME_MID; // 进入选子状态 - action = ACTION_CHOOSE; + data_.action = ACTION_CHOOSE; // 清除禁点 cleanForbidden(); // 设置轮到谁走 if (rule.isDefensiveMoveFirst) { - turn = PLAYER2; + data_.turn = PLAYER2; } else { - turn = PLAYER1; + data_.turn = PLAYER1; } // 再决胜负 if (win()) { @@ -651,7 +654,7 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/) // 如果双方还有子 else { // 进入落子状态 - action = ACTION_PLACE; + data_.action = ACTION_PLACE; // 设置轮到谁走 changeTurn(); // 如果决出胜负 @@ -664,7 +667,7 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/) // 中局阶段 else { // 进入选子状态 - action = ACTION_CHOOSE; + data_.action = ACTION_CHOOSE; // 设置轮到谁走 changeTurn(); // 如果决出胜负 @@ -681,20 +684,20 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/) bool NineChess::choose(int c, int p) { // 如果局面不是"中局”,返回false - if (phase != GAME_MID) + if (data_.phase != GAME_MID) return false; // 如非“选子”或“落子”状态,返回false - if (action != ACTION_CHOOSE && action != ACTION_PLACE) + if (data_.action != ACTION_CHOOSE && data_.action != ACTION_PLACE) return false; int pos = cp2pos(c, p); // 根据先后手,判断可选子 char t ='\0'; - if (turn == PLAYER1) + if (data_.turn == PLAYER1) t = '\x10'; - else if (turn == PLAYER2) + else if (data_.turn == PLAYER2) t = '\x20'; // 判断选子是否可选 - if (board[pos] & t) { + if (data_.board[pos] & t) { // 判断pos处的棋子是否被“闷” if (isSurrounded(pos)) { return false; @@ -702,7 +705,7 @@ bool NineChess::choose(int c, int p) // 选子 currentPos = pos; // 选子完成,进入落子状态 - action = ACTION_PLACE; + data_.action = ACTION_PLACE; return true; } return false; @@ -710,12 +713,12 @@ bool NineChess::choose(int c, int p) bool NineChess::giveup(Player loser) { - if (phase == GAME_MID || phase == GAME_OPENING) + if (data_.phase == GAME_MID || data_.phase == GAME_OPENING) { if (loser == PLAYER1) { - phase = GAME_OVER; - winner = PLAYER2; + data_.phase = GAME_OVER; + data_.winner = PLAYER2; tip = "玩家1投子认负,恭喜玩家2获胜!"; sprintf(cmdline, "Player1 give up!"); cmdlist.push_back(string(cmdline)); @@ -723,8 +726,8 @@ bool NineChess::giveup(Player loser) } else if (loser == PLAYER2) { - phase = GAME_OVER; - winner = PLAYER1; + data_.phase = GAME_OVER; + data_.winner = PLAYER1; tip = "玩家2投子认负,恭喜玩家1获胜!"; sprintf(cmdline, "Player2 give up!"); cmdlist.push_back(string(cmdline)); @@ -801,11 +804,11 @@ bool NineChess::command(const char *cmd) inline long NineChess::update(long time_p /*= -1*/) { long ret = -1; - long *player_ms = (turn == PLAYER1 ? &player1_MS : &player2_MS); - long playerNext_ms = (turn == PLAYER1 ? player2_MS : player1_MS); + long *player_ms = (data_.turn == PLAYER1 ? &(player1_MS) : &(player2_MS)); + long playerNext_ms = (data_.turn == PLAYER1 ? player2_MS : player1_MS); // 根据局面调整计时器 - switch (phase) + switch (data_.phase) { case NineChess::GAME_OPENING: case NineChess::GAME_MID: @@ -847,9 +850,9 @@ inline long NineChess::update(long time_p /*= -1*/) // 是否分出胜负 bool NineChess::win() { - if (phase == GAME_OVER) + if (data_.phase == GAME_OVER) return true; - if (phase == GAME_NOTSTARTED) + if (data_.phase == GAME_NOTSTARTED) return false; // 如果有时间限定 @@ -858,8 +861,8 @@ bool NineChess::win() // 如果玩家1超时 if (player1_MS > rule.maxTime * 60000) { player1_MS = rule.maxTime * 60000; - winner = PLAYER2; - phase = GAME_OVER; + data_.winner = PLAYER2; + data_.phase = GAME_OVER; tip = "玩家1超时,恭喜玩家2获胜!"; sprintf(cmdline, "Time over. Player2 win!"); cmdlist.push_back(string(cmdline)); @@ -868,8 +871,8 @@ bool NineChess::win() // 如果玩家2超时 else if (player2_MS > rule.maxTime * 60000) { player2_MS = rule.maxTime * 60000; - winner = PLAYER1; - phase = GAME_OVER; + data_.winner = PLAYER1; + data_.phase = GAME_OVER; tip = "玩家2超时,恭喜玩家1获胜!"; sprintf(cmdline, "Time over. Player1 win!"); cmdlist.push_back(string(cmdline)); @@ -879,9 +882,9 @@ bool NineChess::win() // 如果有步数限定 if (rule.maxSteps > 0) { - if (step > rule.maxSteps) { - winner = DRAW; - phase = GAME_OVER; + if (data_.step > rule.maxSteps) { + data_.winner = DRAW; + data_.phase = GAME_OVER; sprintf(cmdline, "Steps over. In draw!"); cmdlist.push_back(string(cmdline)); return true; @@ -889,48 +892,48 @@ bool NineChess::win() } // 如果玩家1子数小于赛点,则玩家2获胜 - if (player1_Remain + player1_InHand < rule.numAtLest) { - winner = PLAYER2; - phase = GAME_OVER; + if (data_.player1_Remain + data_.player1_InHand < rule.numAtLest) { + data_.winner = PLAYER2; + data_.phase = GAME_OVER; sprintf(cmdline, "Player2 win!"); cmdlist.push_back(string(cmdline)); return true; } // 如果玩家2子数小于赛点,则玩家1获胜 - else if (player2_Remain + player2_InHand < rule.numAtLest) { - winner = PLAYER1; - phase = GAME_OVER; + else if (data_.player2_Remain + data_.player2_InHand < rule.numAtLest) { + data_.winner = PLAYER1; + data_.phase = GAME_OVER; sprintf(cmdline, "Player1 win!"); cmdlist.push_back(string(cmdline)); return true; } // 如果摆满了,根据规则判断胜负 - else if (player1_Remain + player2_Remain >= SEAT * RING) { + else if (data_.player1_Remain + data_.player2_Remain >= SEAT * RING) { if (rule.isFullLose) { - winner = PLAYER2; - phase = GAME_OVER; + data_.winner = PLAYER2; + data_.phase = GAME_OVER; sprintf(cmdline, "Player2 win!"); cmdlist.push_back(string(cmdline)); return true; } else { - winner = DRAW; - phase = GAME_OVER; + data_.winner = DRAW; + data_.phase = GAME_OVER; sprintf(cmdline, "Full. In draw!"); cmdlist.push_back(string(cmdline)); return true; } } // 如果中局被“闷” - else if (phase == GAME_MID && action == ACTION_CHOOSE && isAllSurrounded(turn)) { + else if (data_.phase == GAME_MID && data_.action == ACTION_CHOOSE && isAllSurrounded(data_.turn)) { // 规则要求被“闷”判负,则对手获胜 if (rule.isNoWayLose) { - if (turn == PLAYER1) + if (data_.turn == PLAYER1) { tip = "玩家1无子可走,恭喜玩家2获胜!"; - winner = PLAYER2; - phase = GAME_OVER; + data_.winner = PLAYER2; + data_.phase = GAME_OVER; sprintf(cmdline, "Player1 no way to go. Player2 win!"); cmdlist.push_back(string(cmdline)); return true; @@ -938,8 +941,8 @@ bool NineChess::win() else { tip = "玩家2无子可走,恭喜玩家1获胜!"; - winner = PLAYER1; - phase = GAME_OVER; + data_.winner = PLAYER1; + data_.phase = GAME_OVER; sprintf(cmdline, "Player2 no way to go. Player1 win!"); cmdlist.push_back(string(cmdline)); return true; @@ -960,12 +963,12 @@ int NineChess::isInMills(int pos) { int n = 0; int pos1, pos2; - char m = board[pos] & '\x30'; + char m = data_.board[pos] & '\x30'; for (int i = 0; i < 3; i++) { pos1 = millTable[pos][i][0]; pos2 = millTable[pos][i][1]; - if (m & board[pos1] & board[pos2]) + if (m & data_.board[pos1] & data_.board[pos2]) n++; } return n; @@ -980,14 +983,14 @@ int NineChess::addMills(int pos) long long mill = 0; int n = 0; int p[3], min, temp; - char m = board[pos] & '\x30'; + char m = data_.board[pos] & '\x30'; for (int i = 0; i < 3; i++) { p[0] = pos; p[1] = millTable[pos][i][0]; p[2] = millTable[pos][i][1]; // 如果成三 - if (m & board[p[1]] & board[p[2]]) { + if (m & data_.board[p[1]] & data_.board[p[2]]) { // 排序 for (int j = 0; j < 2; j++) { min = j; @@ -1002,11 +1005,11 @@ int NineChess::addMills(int pos) } } // 成三 - mill = (((long long)board[p[0]]) << 40) + mill = (((long long)(data_.board[p[0]])) << 40) + (((long long)p[0]) << 32) - + (((long long)board[p[1]]) << 24) + + (((long long)(data_.board[p[1]])) << 24) + (((long long)p[1]) << 16) - + (((long long)board[p[2]]) << 8) + + (((long long)(data_.board[p[2]])) << 8) + (long long)p[2]; // 如果允许相同三连反复去子 @@ -1019,15 +1022,15 @@ int NineChess::addMills(int pos) // 迭代器 list::iterator itor; // 遍历 - for (itor = millList.begin(); itor != millList.end(); itor++) + for (itor = data_.millList.begin(); itor != data_.millList.end(); itor++) { if (mill == *itor) break; } // 如果没找到历史项 - if (itor == millList.end()) { + if (itor == data_.millList.end()) { n++; - millList.push_back(mill); + data_.millList.push_back(mill); } } } @@ -1047,7 +1050,7 @@ bool NineChess::isAllInMills(enum Player player) for (int i = 1; i <= RING; i++) for (int j = 0; j < SEAT; j++) { - if (board[i*SEAT + j] & ch) { + if (data_.board[i*SEAT + j] & ch) { if (!isInMills(i*SEAT + j)) { return false; } @@ -1060,13 +1063,13 @@ bool NineChess::isAllInMills(enum Player player) bool NineChess::isSurrounded(int pos) { // 判断pos处的棋子是否被“闷” - if ((turn == PLAYER1 && (player1_Remain > rule.numAtLest || !rule.canFly)) || - (turn == PLAYER2 && (player2_Remain > rule.numAtLest || !rule.canFly))) + if ((data_.turn == PLAYER1 && (data_.player1_Remain > rule.numAtLest || !rule.canFly)) || + (data_.turn == PLAYER2 && (data_.player2_Remain > rule.numAtLest || !rule.canFly))) { int i, movePos; for (i = 0; i < 4; i++) { movePos = moveTable[pos][i]; - if (movePos && !board[movePos]) + if (movePos && !data_.board[movePos]) break; } // 被围住 @@ -1086,11 +1089,11 @@ bool NineChess::isAllSurrounded(enum Player ply) else if (ply == PLAYER2) t &= '\x20'; // 如果摆满 - if (player1_Remain + player2_Remain >= SEAT * RING) + if (data_.player1_Remain + data_.player2_Remain >= SEAT * RING) return true; // 判断是否可以飞子 - if ((turn == PLAYER1 && (player1_Remain <= rule.numAtLest && rule.canFly)) || - (turn == PLAYER2 && (player2_Remain <= rule.numAtLest && rule.canFly))) + if ((data_.turn == PLAYER1 && (data_.player1_Remain <= rule.numAtLest && rule.canFly)) || + (data_.turn == PLAYER2 && (data_.player2_Remain <= rule.numAtLest && rule.canFly))) { return false; } @@ -1100,10 +1103,10 @@ bool NineChess::isAllSurrounded(enum Player ply) for (int j = 0; j < SEAT; j++) { int movePos; - if (t & board[i*SEAT + j]) { + if (t & data_.board[i*SEAT + j]) { for (int k = 0; k < 4; k++) { movePos = moveTable[i*SEAT + j][k]; - if (movePos && !board[movePos]) + if (movePos && !data_.board[movePos]) return false; } } @@ -1116,70 +1119,70 @@ void NineChess::cleanForbidden() { for (int i = 1; i <= RING; i++) for (int j = 0; j < SEAT; j++) { - if (board[i*SEAT + j] == '\x0f') - board[i*SEAT + j] = '\x00'; + if (data_.board[i*SEAT + j] == '\x0f') + data_.board[i*SEAT + j] = '\x00'; } } enum NineChess::Player NineChess::changeTurn() { // 设置轮到谁走 - return turn = (turn == PLAYER1) ? PLAYER2 : PLAYER1; + return data_.turn = (data_.turn == PLAYER1) ? PLAYER2 : PLAYER1; } void NineChess::setTip() { - switch (phase) + switch (data_.phase) { case NineChess::GAME_NOTSTARTED: - tip = "轮到玩家1落子,剩余" + std::to_string(player1_InHand) + "子"; + tip = "轮到玩家1落子,剩余" + std::to_string(data_.player1_InHand) + "子"; break; case NineChess::GAME_OPENING: - if (action == ACTION_PLACE) { - if (turn == PLAYER1) { - tip = "轮到玩家1落子,剩余" + std::to_string(player1_InHand) + "子"; + if (data_.action == ACTION_PLACE) { + if (data_.turn == PLAYER1) { + tip = "轮到玩家1落子,剩余" + std::to_string(data_.player1_InHand) + "子"; } - else if (turn == PLAYER2) { - tip = "轮到玩家2落子,剩余" + std::to_string(player2_InHand) + "子"; + else if (data_.turn == PLAYER2) { + tip = "轮到玩家2落子,剩余" + std::to_string(data_.player2_InHand) + "子"; } } - else if (action == ACTION_REMOVE) { - if (turn == PLAYER1) { - tip = "轮到玩家1去子,需去" + std::to_string(num_NeedRemove) + "子"; + else if (data_.action == ACTION_REMOVE) { + if (data_.turn == PLAYER1) { + tip = "轮到玩家1去子,需去" + std::to_string(data_.num_NeedRemove) + "子"; } - else if (turn == PLAYER2) { - tip = "轮到玩家2去子,需去" + std::to_string(num_NeedRemove) + "子"; + else if (data_.turn == PLAYER2) { + tip = "轮到玩家2去子,需去" + std::to_string(data_.num_NeedRemove) + "子"; } } break; case NineChess::GAME_MID: - if (action == ACTION_PLACE || action == ACTION_CHOOSE) { - if (turn == PLAYER1) { + if (data_.action == ACTION_PLACE || data_.action == ACTION_CHOOSE) { + if (data_.turn == PLAYER1) { tip = "轮到玩家1选子移动"; } - else if (turn == PLAYER2) { + else if (data_.turn == PLAYER2) { tip = "轮到玩家2选子移动"; } } - else if (action == ACTION_REMOVE) { - if (turn == PLAYER1) { - tip = "轮到玩家1去子,需去" + std::to_string(num_NeedRemove) + "子"; + else if (data_.action == ACTION_REMOVE) { + if (data_.turn == PLAYER1) { + tip = "轮到玩家1去子,需去" + std::to_string(data_.num_NeedRemove) + "子"; } - else if (turn == PLAYER2) { - tip = "轮到玩家2去子,需去" + std::to_string(num_NeedRemove) + "子"; + else if (data_.turn == PLAYER2) { + tip = "轮到玩家2去子,需去" + std::to_string(data_.num_NeedRemove) + "子"; } } break; case NineChess::GAME_OVER: - if (winner == DRAW) + if (data_.winner == DRAW) tip = "超出限定步数,双方平局"; - else if (winner == PLAYER1) { + else if (data_.winner == PLAYER1) { if (tip.find("无子可走") != tip.npos) tip += "恭喜玩家1获胜!"; else tip = "恭喜玩家1获胜!"; } - else if (winner == PLAYER2) { + else if (data_.winner == PLAYER2) { if (tip.find("无子可走") != tip.npos) tip += "恭喜玩家2获胜!"; else @@ -1194,9 +1197,9 @@ void NineChess::setTip() enum NineChess::Player NineChess::getWhosPiece(int c, int p) { int pos = cp2pos(c, p); - if (board[pos] & '\x10') + if (data_.board[pos] & '\x10') return PLAYER1; - else if (board[pos] & '\x20') + else if (data_.board[pos] & '\x20') return PLAYER2; return NOBODY; } @@ -1204,7 +1207,7 @@ enum NineChess::Player NineChess::getWhosPiece(int c, int p) int NineChess::getPieceNum(int c, int p) { int pos = cp2pos(c, p); - int n = 0x0f & board[pos]; + int n = 0x0f & data_.board[pos]; return n; } diff --git a/NineChess/src/ninechess.h b/NineChess/src/ninechess.h index c0e6738a..bce65e59 100644 --- a/NineChess/src/ninechess.h +++ b/NineChess/src/ninechess.h @@ -16,11 +16,12 @@ using std::string; using std::list; // 棋类(在数据模型内,玩家只分先后手,不分黑白) +// 注意:NineChess类不是线程安全的! +// 所以不能跨线程修改NineChess类的静态成员变量,切记! class NineChess { public: - // 公有的结构体和枚举,只是类型定义,不是变量! - // 规则结构体 + // 嵌套的规则结构体 struct Rule { // 规则名称 @@ -86,9 +87,89 @@ public: // 预定义的规则 static const struct Rule RULES[RULENUM]; + // 嵌套的数据结构体 + // 单独提出来,是为了ai计算的时候压栈的数据量少 + struct Data + { + // 当前步数 + int step; + // 局面阶段标识 + enum Phases phase; + // 轮流状态标识 + enum Player turn; + // 动作状态标识 + enum Actions action; + // 赢家 + enum Player winner; + + // 玩家1剩余未放置子数 + int player1_InHand; + // 玩家2剩余未放置子数 + int player2_InHand; + // 玩家1盘面剩余子数 + int player1_Remain; + // 玩家1盘面剩余子数 + int player2_Remain; + // 尚待去除的子数 + int num_NeedRemove; + + /* 棋局,抽象为一个(5×8)的char数组,上下两行留空 + * 0x00代表无棋子 + * 0x0F代表禁点 + * 0x11~0x1C代表先手第1~12子 + * 0x21~0x2c代表后手第1~12子 + * 判断棋子是先手的用(board[i] & 0x10) + * 判断棋子是后手的用(board[i] & 0x20) + */ + char board[(NineChess::RING + 2)*NineChess::SEAT]; + + /* 本打算用如下的结构体来表示“三连” + struct Mill { + char piece1; // “三连”中最小的棋子 + char pos1; // 最小棋子的位置 + char piece2; // 次小的棋子 + char pos2; // 次小棋子的位置 + char piece3; // 最大的棋子 + char pos3; // 最大棋子的位置 + }; + 但为了提高执行效率改用一个64位整数了,规则如下 + 0x 00 00 00 00 00 00 00 00 + unused unused piece1 pos1 piece2 pos2 piece3 pos3 + */ + // “三连列表” + list millList; + + /* 当前招法,AI会用到,如下表示 + 0x 00 00 + pos1 pos2 + 开局落子:0x00??,??为棋盘上的位置 + 移子:0x__??,__为移动前的位置,??为移动后的位置 + 去子:0xFF??,??为棋盘上去子点的位置 + */ + short move_; + }; + +private: + // 空棋盘点位,用于判断一个棋子位置是否在棋盘上 + static const char inBoard[(RING + 2)*SEAT]; + + // 招法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外 + // 这个表跟规则有关,一旦规则改变需要重新修改 + static char moveTable[(RING + 2)*SEAT][4]; + + // 成三表,表示棋盘上各个位置有成三关系的对应位置表 + // 这个表跟规则有关,一旦规则改变需要重新修改 + static char millTable[(RING + 2)*SEAT][3][2]; + public: NineChess(); virtual ~NineChess(); + /* 拷贝构造函数 + 其实NineChess类没有指针类型的成员变量,list内的值也是深拷贝 + 所以没有必要写拷贝构造函数了 + */ + //explicit NineChess(const NineChess &); + // 设置棋局状态和棋盘数据,用于初始化 bool setData(const struct Rule *rule, int s = 0, // 限制步数 @@ -110,15 +191,15 @@ public: // 获取当前点 int getCurrentPos() { return currentPos; } // 获取当前步数 - int getStep() { return step; } + int getStep() { return data_.step; } // 获取局面阶段标识 - enum Phases getPhase() { return phase; } + enum Phases getPhase() { return data_.phase; } // 获取轮流状态标识 - enum Player whosTurn() { return turn; } + enum Player whosTurn() { return data_.turn; } // 获取动作状态标识 - enum Actions getAction() { return action; } + enum Actions getAction() { return data_.action; } // 判断胜负 - enum Player whoWin() { return winner; } + enum Player whoWin() { return data_.winner; } // 玩家1和玩家2的用时 void getPlayer_TimeMS(int &p1_ms, int &p2_ms); // 获取棋局的字符提示 @@ -137,15 +218,15 @@ public: void setStartTimeb(timeb stimeb) { startTimeb = stimeb; } // 玩家1剩余未放置子数 - int getPlayer1_InHand() { return player1_InHand; } + int getPlayer1_InHand() { return data_.player1_InHand; } // 玩家2剩余未放置子数 - int getPlayer2_InHand() { return player2_InHand; } + int getPlayer2_InHand() { return data_.player2_InHand; } // 玩家1盘面剩余子数 - int getPlayer1_Remain() { return player1_Remain; } + int getPlayer1_Remain() { return data_.player1_Remain; } // 玩家1盘面剩余子数 - int getPlayer2_Remain() { return player2_Remain; } + int getPlayer2_Remain() { return data_.player2_Remain; } // 尚待去除的子数 - int getNum_NeedRemove() { return num_NeedRemove; } + int getNum_NeedRemove() { return data_.num_NeedRemove; } // 游戏重置 bool reset(); @@ -189,27 +270,10 @@ protected: private: // 当前使用的规则 struct Rule rule; - // 当前步数 - int step; - // 局面阶段标识 - enum Phases phase; - // 轮流状态标识 - enum Player turn; - // 动作状态标识 - enum Actions action; - // 赢家 - enum Player winner; - - // 玩家1剩余未放置子数 - int player1_InHand; - // 玩家2剩余未放置子数 - int player2_InHand; - // 玩家1盘面剩余子数 - int player1_Remain; - // 玩家1盘面剩余子数 - int player2_Remain; - // 尚待去除的子数 - int num_NeedRemove; + // 棋盘数据 + struct Data data_; + // 选中的棋子在board中的位置 + int currentPos; // 游戏起始时间 timeb startTimeb; @@ -220,40 +284,7 @@ private: // 玩家2用时(毫秒) long player2_MS; - /* 棋局,抽象为一个(5×8)的char数组,上下两行留空 - * 0x00代表无棋子 - * 0x0F代表禁点 - * 0x10~(N-1)+0x10代表先手第1~N子 - * 0x20~(N-1)+0x20代表后手第1~N子 - * 判断棋子是先手的用(board[i] & 0x10) - * 判断棋子是后手的用(board[i] & 0x20) - */ - char board[(RING + 2)*SEAT]; - // 选中的棋子在board中的位置 - int currentPos; - // 空棋盘点位,用于判断一个棋子位置是否在棋盘上 - static const char inBoard[(RING + 2)*SEAT]; - // 招法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外 - static char moveTable[(RING + 2)*SEAT][4]; - // 成三表,表示棋盘上各个位置有成三关系的对应位置表 - static char millTable[(RING + 2)*SEAT][3][2]; - - /* 本打算用如下的结构体来表示“三连” - struct Mill { - char piece1; // “三连”中最小的棋子 - char pos1; // 最小棋子的位置 - char piece2; // 次小的棋子 - char pos2; // 次小棋子的位置 - char piece3; // 最大的棋子 - char pos3; // 最大棋子的位置 - }; - 但为了提高执行效率改用一个64位整数了,规则如下 - 0x 00 00 00 00 00 00 00 00 - unused unused piece1 pos1 piece2 pos2 piece3 pos3 - */ - // “三连列表” - list millList; - + // 招法命令行用于棋谱的显示和解析 // 当前招法的命令行指令,即一招棋谱 char cmdline[32]; // 棋谱 diff --git a/NineChess/src/ninechessai_ab.cpp b/NineChess/src/ninechessai_ab.cpp new file mode 100644 index 00000000..4feaf7ab --- /dev/null +++ b/NineChess/src/ninechessai_ab.cpp @@ -0,0 +1,107 @@ +#include "NineChessAi_ab.h" + +NineChessAi_ab::NineChessAi_ab(): +rootNode(nullptr), +requiredQuit(false), +depth(5) // Ĭ5 +{ +} + +NineChessAi_ab::~NineChessAi_ab() +{ + deleteTree(rootNode); +} + +void NineChessAi_ab::buildChildren(Node *node) +{ + ; +} + +void NineChessAi_ab::sortChildren(Node *node) +{ + // ЧʵӰܴ + // õĻ֦磬ʡʱ + // ڴ˺ķ̫ʱ + ; +} + +void NineChessAi_ab::deleteTree(Node *node) +{ + if (rootNode) { + for (auto i : rootNode->children) { + deleteTree(i); + } + rootNode->children.clear(); + delete rootNode; + } +} + +void NineChessAi_ab::setChess(const NineChess &chess) +{ + this->chess = chess; + chessTemp = chess; + requiredQuit = false; +} + +int NineChessAi_ab::evaluate(Node *node) +{ + // ʼֵΪ0󣬶ԺС + int value = 0; + + + + + // ֵ + node->value = value; + return value; +} + +int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) +{ + // ֵ + int value; + if (!depth || !(node->children.size())) { + node->value = evaluate(node); + return node->value; + } + + // ӽڵ + buildChildren(node); + // ӽڵ + sortChildren(node); + + // ģִMiniMax + // ֣Max + if (chessTemp.whosTurn() == NineChess::PLAYER1) { + for (auto child : node->children) { + value = alphaBetaPruning(depth - 1, alpha, beta, child); + // ȡֵ + if (value > alpha) + alpha = value; + // ֦ + if (alpha >= beta) { + return value; + } + } + // ȡֵ + node->value = alpha; + } + // Ժ֣Min + else { + for (auto child : node->children) { + value = alphaBetaPruning(depth - 1, alpha, beta, child); + // ȡСֵ + if (value < beta) + beta = value; + // ֦ + if (alpha >= beta) { + return value; + } + } + // ȡСֵ + node->value = beta; + } + // + return node->value; +} + diff --git a/NineChess/src/ninechessai_ab.h b/NineChess/src/ninechessai_ab.h new file mode 100644 index 00000000..fd117729 --- /dev/null +++ b/NineChess/src/ninechessai_ab.h @@ -0,0 +1,60 @@ +#ifndef NINECHESSAI_AB +#define NINECHESSAI_AB + +#include "ninechess.h" +#include + +// ע⣺NineChess಻̰߳ȫģ +// Բai޸NineChessľ̬Աмǣ + + +class NineChessAi_ab +{ +public: + // һڵṹ + struct Node{ + int value; // ڵֵ + short move_; // зָͼϱʾΪڵǰ + struct Node * parent; // ڵ + list children; // ӽڵб + }; + +public: + NineChessAi_ab(); + ~NineChessAi_ab(); + + void setChess(const NineChess &chess); + void setDepth(int depth) { this->depth = depth; } + void quit() { requiredQuit = true; } + +protected: + // ӽڵ + void buildChildren(Node *node); + // ӽڵ + void sortChildren(Node *node); + // սڵ + void deleteTree(Node *node); + + // ۺ + int evaluate(Node *node); + // Alpha-Beta֦㷨 + int alphaBetaPruning(int depth, int alpha, int beta, Node *node); + +private: + // ԭʼģ + NineChess chess; + // õģ + NineChess chessTemp; + + // ڵ + Node * rootNode; + + // ʶ֦㷨 + bool requiredQuit; + // ֦㷨IJ + int depth; + // 弫ֵ32λзֵֵ + static const int infinity = 0x7fffffff; +}; + +#endif diff --git a/NineChess/src/ninechesswindow.cpp b/NineChess/src/ninechesswindow.cpp index 60d2127b..926ce61b 100644 --- a/NineChess/src/ninechesswindow.cpp +++ b/NineChess/src/ninechesswindow.cpp @@ -85,6 +85,19 @@ NineChessWindow::NineChessWindow(QWidget *parent) NineChessWindow::~NineChessWindow() { + if (game) { + game->disconnect(); + game->deleteLater(); + } + qDeleteAll(ruleActionList); +} + +void NineChessWindow::closeEvent(QCloseEvent *event) +{ + if (file.isOpen()) + file.close(); + //qDebug() << "closed"; + QMainWindow::closeEvent(event); } bool NineChessWindow::eventFilter(QObject *watched, QEvent *event) @@ -108,20 +121,6 @@ bool NineChessWindow::eventFilter(QObject *watched, QEvent *event) return QMainWindow::eventFilter(watched, event); } -void NineChessWindow::closeEvent(QCloseEvent *event) -{ - if (file.isOpen()) - file.close(); - if (game) { - game->disconnect(); - delete game; - game = nullptr; - } - qDeleteAll(ruleActionList); - //qDebug() << "closed"; - QMainWindow::closeEvent(event); -} - void NineChessWindow::initialize() { // 初始化函数,仅执行一次 @@ -161,10 +160,7 @@ void NineChessWindow::initialize() connect(ui.actionAnimation_A, SIGNAL(toggled(bool)), game, SLOT(setAnimation(bool))); - /* 关联控制器的信号和主窗口控件的槽 - 注意,采用信号和槽而非采用在GameController中直接控制NineChessWindow - 是MVC模型中控制器与视图相分离的方式,有利于程序梳理 */ - + // 关联控制器的信号和主窗口控件的槽 // 更新LCD1,显示玩家1用时 connect(game, SIGNAL(time1Changed(QString)), ui.lcdNumber_1, SLOT(display(QString))); @@ -208,7 +204,7 @@ void NineChessWindow::initialize() connect(ui.actionEnd_E, &QAction::triggered, this, &NineChessWindow::on_actionRowChange); // 手动在listView里选择招法后更新的槽 - connect(ui.listView, &SizeHintListView::currentChangedSignal, + connect(ui.listView, &ManualListView::currentChangedSignal, this, &NineChessWindow::on_actionRowChange); // 更新四个键的状态 on_actionRowChange(); @@ -238,7 +234,6 @@ void NineChessWindow::ruleInfo() void NineChessWindow::actionRules_triggered() { - // setChecked函数会发出toggled信号,在这里响应toggled信号会陷入死循环 // 取消其它规则的选择 for(QAction *action: ruleActionList) action->setChecked(false); @@ -246,6 +241,10 @@ void NineChessWindow::actionRules_triggered() QAction *action = dynamic_cast(sender()); action->setChecked(true); ruleNo = action->data().toInt(); + + // 取消AI设定 + ui.actionEngine1_T->setChecked(false); + ui.actionEngine2_R->setChecked(false); // 重置游戏规则 game->setRule(ruleNo); // 更新规则显示 @@ -441,13 +440,20 @@ void NineChessWindow::on_actionRowChange() // 更新局面 bool changed = game->phaseChange(currentRow); - // 处理自动播放时的动画 + // 处理自动播放时的动画 if (changed && game->isAnimation()) { - int waitTime = game->getDurationTime() + 50; - // 使用QEventLoop进行非阻塞延时,CPU占用低 - QEventLoop loop; - QTimer::singleShot(waitTime, &loop, SLOT(quit())); - loop.exec(); + // 不使用processEvents函数进行非阻塞延时,频繁调用占用CPU较多 + //QElapsedTimer et; + //et.start(); + //while (et.elapsed() < waitTime) { + // qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + //} + + int waitTime = game->getDurationTime() + 50; + // 使用QEventLoop进行非阻塞延时,CPU占用低 + QEventLoop loop; + QTimer::singleShot(waitTime, &loop, SLOT(quit())); + loop.exec(); } } @@ -456,8 +462,8 @@ void NineChessWindow::on_actionAutoRun_A_toggled(bool arg1) { if (!arg1) return; - - int rows = ui.listView->model()->rowCount(); + + int rows = ui.listView->model()->rowCount(); int currentRow = ui.listView->currentIndex().row(); if (rows <= 1) @@ -504,22 +510,6 @@ void NineChessWindow::on_actionAutoRun_A_toggled(bool arg1) // 更新局面 game->phaseChange(currentRow); - // 处理自动播放时的动画 - if (game->isAnimation()) { - int waitTime = game->getDurationTime() + 50; - - // 不使用processEvents函数进行非阻塞延时,频繁调用占用CPU较多 - //QElapsedTimer et; - //et.start(); - //while (et.elapsed() < waitTime) { - // qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - //} - - // 使用QEventLoop进行非阻塞延时,CPU占用低 - QEventLoop loop; - QTimer::singleShot(waitTime, &loop, SLOT(quit())); - loop.exec(); - } } // 自动运行结束后启用所有控件 diff --git a/NineChess/src/pieceitem.cpp b/NineChess/src/pieceitem.cpp index ed8083f0..ac59f036 100644 --- a/NineChess/src/pieceitem.cpp +++ b/NineChess/src/pieceitem.cpp @@ -1,6 +1,7 @@ #include "pieceitem.h" #include "graphicsconst.h" #include +#include #include PieceItem::PieceItem(QGraphicsItem *parent) : QGraphicsItem(parent), @@ -63,11 +64,11 @@ void PieceItem::paint(QPainter *painter, // 如果模型为黑色,则画黑色棋子 if (model == blackPiece) painter->drawPixmap(-size/2, -size/2, size, size, - QPixmap(":/image/Resources/image/black_piece.png")); + QPixmap(":/image/resources/image/black_piece.png")); // 如果模型为白色,则画白色棋子 else if (model == whitePiece) painter->drawPixmap(-size/2, -size/2, size, size, - QPixmap(":/image/Resources/image/white_piece.png")); + QPixmap(":/image/resources/image/white_piece.png")); // 如果模型要求显示序号 if (showNum) diff --git a/NineChess/src/pieceitem.h b/NineChess/src/pieceitem.h index 24efe0be..2e6e169c 100644 --- a/NineChess/src/pieceitem.h +++ b/NineChess/src/pieceitem.h @@ -6,7 +6,8 @@ class PieceItem : public QObject, public QGraphicsItem { Q_OBJECT - // 位置属性 + Q_INTERFACES(QGraphicsItem) + // 位置属性 Q_PROPERTY(QPointF pos READ pos WRITE setPos) public: @@ -43,9 +44,9 @@ public: void setShowNum(bool show = true) { this->showNum = show; } protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); private: // 棋子本质 diff --git a/Readme.md b/Readme.md index d11eb997..4157a3d4 100644 --- a/Readme.md +++ b/Readme.md @@ -64,33 +64,44 @@ ``` MVC ├─Model - │ └─NineChess:用标准C++写的棋类模型,处理下棋过程 + │ ├─NineChess: 用标准C++写的棋类模型,处理下棋过程 + │ └─NineChessAi_ab: 用标准C++写的alpha-beta剪枝算法AI模型,模仿人类下棋 ├─View - │ ├─NineChessWindow:从QMainWindow派生的主窗口类,由Qt自动生成 - │ ├─SizeHintListView:从QListView派生的列表框,用于显示棋谱 - │ ├─GameView:从QGraphicsView派生的视图框,用于显示棋局 - │ ├─GameScene:从QGraphicsScene派生的场景类 - │ ├─BoardItem:从QGraphicsItem派生的棋盘图形类 - │ └─PiecedItem:从QGraphicsItem派生的棋子图形类 + │ ├─NineChessWindow: 从QMainWindow派生的主窗口类,由Qt自动生成 + │ ├─ManualListView: 从QListView派生的列表框,用于显示棋谱 + │ ├─GameView: 从QGraphicsView派生的视图框,用于显示棋局 + │ ├─GameScene: 从QGraphicsScene派生的场景类 + │ ├─BoardItem: 从QGraphicsItem派生的棋盘图形类 + │ └─PiecedItem: 从QGraphicsItem派生的棋子图形类 └─Controller - └─GameController:从QObject派生的控制类 + ├─GameController: 从QObject派生的控制类 + └─AiThread: 从QThread派生的AI线程类 ``` 这个程序用到了很多Qt的特性,其模式后期可以扩展到各种棋类游戏。 -### 许可协议及更新历史 -详见文末Gitee内的License和History文件。请取用的朋友尊重知识产权。 +### AI算法说明 +相见Wiki目录下的《Alpha-Beta剪枝算法在直棋中的运用》 + +### 许可协议 +**本项目所有类代码全部原创。** +详见文末Gitee项目内的License文件。请取用的朋友尊重知识产权。 + +### 更新历史 +详见文末Gitee项目内的History文件。 ## 作者声明 -本项目所有类代码全部原创。由于本人非IT科班出身,未经专业培训,也没有现成的QT棋类游戏源码做参考,源码中肯定有很多不合理,不规范之处。望好心的前辈不吝赐教。对于其它初学者,可以参考,相互学习,共同进步。 +由于本人非IT科班出身,未经专业培训,也没有现成的QT棋类游戏源码做参考,源码中肯定有很多不合理,不规范之处。望好心的前辈不吝赐教。对于同道初学者,可以参考,相互学习,共同进步。 多年前上大学那会儿,笔者就打算做这么个程序出来,然而条件比较艰苦: -一来没有老师教,课上只学了Ç语言和VB,C ++是笔者自学的,一个人啃晦涩过时的MFC; -二来我穷到连个电脑都没有......三嘛,就是贪玩...... +一来没有老师教,课上只学了Ç语言和VB,C++是笔者自学的,一个人啃晦涩过时的MFC; +二来我穷到连个电脑都没有...... +三嘛,就是贪玩...... 工作之后有条件了,我又自学了C#和Qt,但都很肤浅,没深入学,只用来做几个小工具而已。 +这个项目,我在2013年用标准C++写了个模型类,然后扔了不管;2015年自学Qt写了个简单的界面,又扔了不管;直到2018年5月才重新开始做。 如果你发现本程序有什么问题或好的建议,请与本人联系。我的邮箱是:liuweilhy@163.com -> by liuweilhy 2015年11月6日 +> by liuweilhy 2018年11月26日 ## 项目源码及发行版下载 + 源码下载(Gitee):[https://gitee.com/liuweilhy/NineChess](https://gitee.com/liuweilhy/NineChess) -+ 发行版下载(Gitee):[https://gitee.com/liuweilhy/NineChess/releases](https://gitee.com/liuweilhy/NineChess/releases) -+ 如果你没有Gitee账号,可以在本人CSDN资源下载:(链接待补充) -+ 如果你以上都没有,那么用百度云盘吧:(链接待补充) ++ 发行版下载(Gitee),请选择最新版:[https://gitee.com/liuweilhy/NineChess/releases](https://gitee.com/liuweilhy/NineChess/releases) ++ 如果你没有Gitee账号,可以在本人CSDN资源下载(非最新版):(链接待补充) ++ 如果你以上都没有,那么用百度云盘(非最新版):(链接待补充) diff --git a/Wiki/12子棋.PNG b/screenshot/12子棋.PNG similarity index 100% rename from Wiki/12子棋.PNG rename to screenshot/12子棋.PNG diff --git a/Wiki/GUI.PNG b/screenshot/GUI.PNG similarity index 100% rename from Wiki/GUI.PNG rename to screenshot/GUI.PNG diff --git a/Wiki/九连棋.PNG b/screenshot/九连棋.PNG similarity index 100% rename from Wiki/九连棋.PNG rename to screenshot/九连棋.PNG diff --git a/Wiki/莫里斯九子棋.PNG b/screenshot/莫里斯九子棋.PNG similarity index 100% rename from Wiki/莫里斯九子棋.PNG rename to screenshot/莫里斯九子棋.PNG