├── .github └── workflows │ ├── MacOS.yml │ ├── Ubuntu_Deb.yml │ ├── ubuntu.yml │ └── windows.yml ├── .gitignore ├── AboutAuthor.cpp ├── AboutAuthor.h ├── AboutAuthor.ui ├── CMakeLists.txt ├── ChessBoard.cpp ├── ChessBoard.h ├── ChessBoard.ui ├── ChessPieces.cpp ├── ChessPieces.h ├── ChessStep.cpp ├── ChessStep.h ├── ChessVoice.cpp ├── ChessVoice.h ├── ChineseChess.pro ├── ChooseMainWindow.cpp ├── ChooseMainWindow.h ├── LICENSE ├── MachineGame.cpp ├── MachineGame.h ├── NetworkGame.cpp ├── NetworkGame.h ├── PKGBUILD ├── README.md ├── README.zh_CN.md ├── build.bat ├── chooseresource.qrc ├── main.cpp ├── resources ├── debian │ ├── changelog │ ├── compat │ ├── control │ ├── copyright │ ├── rules │ └── source │ │ └── format ├── debian_portable │ ├── ChineseChess.sh │ └── ldd.sh ├── images │ ├── 5abc.png │ ├── b.jpg │ ├── background.jpg │ ├── chess.svg │ └── win.jpg ├── licenses │ └── LICENSE.txt ├── logo │ ├── logo.ico │ ├── logo.png │ ├── logo.svg │ └── resources.rc ├── res.qrc └── sound │ ├── WinSound.wav │ ├── backChess.wav │ ├── eatChess.wav │ ├── generalSound.wav │ ├── moveChess.wav │ └── selectChess.wav ├── setup_package_user.iss └── tech.xmuli.chinesechess └── linglong.yaml /.github/workflows/MacOS.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | on: 3 | push: 4 | paths-ignore: 5 | - '*.md' 6 | pull_request: 7 | paths-ignore: 8 | - '*.md' 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [macos-10.15] # macos-10.14 macos-10.15, macos-11.0, macos-12.6 # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md 16 | qt_ver: [5.15.2] # 参考: https://mirrors.cloud.tencent.com/qt/online/qtsdkrepository/mac_x64/desktop/qt5_5111 17 | qt_arch: [clang_64] 18 | env: 19 | targetName: ChineseChess 20 | targetOS: macos 21 | 22 | steps: 23 | # macos 11.0 后默认环境变了,要指定 24 | - name: prepare env 25 | if: ${{ matrix.os == 'macos-11.0' }} 26 | run: | 27 | softwareupdate --all --install --force 28 | sudo xcode-select --print-path 29 | sudo xcode-select --switch /Library/Developer/CommandLineTools 30 | 31 | - name: Install Qt 32 | uses: jurplel/install-qt-action@v3 33 | with: 34 | version: ${{ matrix.qt_ver }} 35 | 36 | - uses: actions/checkout@v4 37 | with: 38 | fetch-depth: 1 39 | submodules: true 40 | 41 | - name: build macos 42 | run: | 43 | mkdir build 44 | cd build 45 | cmake .. 46 | make 47 | 48 | echo "-------------- debug 1 --------------" 49 | pwd 50 | ls -al 51 | 52 | echo "-------------- debug 2 --------------" 53 | cd bin 54 | ls -al 55 | 56 | - name: NameVersion 57 | id: NameVersion 58 | if: startsWith(github.event.ref, 'refs/tags/') 59 | shell: pwsh 60 | run: | 61 | $systemInfo="${{ env.targetOS }}" 62 | $productVersion="${{ github.ref }}".substring("refs/tags/v".length) 63 | $productName="${{ env.targetName }}-$productVersion-$systemInfo-x64" 64 | 65 | echo "systemInfo=$systemInfo" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 66 | echo "productVersion=$productVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 67 | echo "productName=$productName" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 68 | 69 | # tag打为.zip包 70 | - name: package 71 | id: package 72 | if: startsWith(github.event.ref, 'refs/tags/') 73 | shell: bash 74 | run: | 75 | # 拷贝依赖 76 | mkdir bin 77 | 78 | echo "-------------- debug 1 --------------" 79 | pwd 80 | ls -al 81 | 82 | cp -r build/bin/${{ env.targetName }}.app bin 83 | 84 | echo "-------------- debug 2 --------------" 85 | pwd 86 | ls -al 87 | 88 | echo "-------------- debug 3 --------------" 89 | cd bin 90 | pwd 91 | ls -al 92 | 93 | macdeployqt ${{ env.targetName }}.app -dmg 94 | mv ${{ env.targetName }}.dmg ../${{ env.productName }}.dmg 95 | 96 | 97 | echo "-------------- debug 4 --------------" 98 | pwd 99 | ls -al 100 | 101 | 102 | echo "-------------- debug 5 --------------" 103 | cd ../ 104 | pwd 105 | ls -al 106 | 107 | echo "-------------- debug 6 --------------" 108 | cd bin 109 | ls -al 110 | pwd 111 | 112 | # tag上传Release 113 | - name: uploadRelease 114 | if: startsWith(github.event.ref, 'refs/tags/') 115 | uses: softprops/action-gh-release@v1 116 | env: 117 | GITHUB_TOKEN: ${{ secrets.upload_release }} 118 | with: 119 | draft: false 120 | prerelease: false 121 | files: | 122 | ${{ env.productName }}.dmg 123 | tag: ${{ github.ref }} 124 | overwrite: true -------------------------------------------------------------------------------- /.github/workflows/Ubuntu_Deb.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu_DEB 2 | on: 3 | push: 4 | paths-ignore: 5 | - '*.md' 6 | pull_request: 7 | paths-ignore: 8 | - '*.md' 9 | jobs: 10 | build: 11 | name: Build 12 | # 运行平台, ubuntu-latest 目前是 Ubuntu 20.04 13 | # 参考文档 https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: # 矩阵配置 17 | qt_ver: [5.15.2] # 参考: https://mirrors.cloud.tencent.com/qt/online/qtsdkrepository/linux_x64/desktop/qt5_5152 18 | qt_target: [desktop] 19 | qt_arch: [gcc_64] 20 | arch: [amd64] # arm64 21 | os: [ubuntu-20.04] 22 | env: 23 | targetName: ChineseChess 24 | targetLowerName: chinesechess 25 | targetOS: debian 26 | 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 1 31 | submodules: true 32 | 33 | - name: NameVersion 34 | id: NameVersion 35 | if: startsWith(github.event.ref, 'refs/tags/') 36 | shell: pwsh 37 | run: | 38 | $systemInfo="${{ env.targetOS }}-x64" 39 | $productVersion="${{ github.ref }}".substring("refs/tags/v".length) 40 | # $productName="${{ env.targetName }}-$productVersion-protable-$systemInfo" 41 | $productDebName="${{ env.targetLowerName }}-$productVersion" 42 | 43 | echo "systemInfo=$systemInfo" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 44 | echo "productVersion=$productVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 45 | # echo "productName=$productName" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 46 | echo "productDebName=$productDebName" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 47 | 48 | # 安装一些包 49 | - name: AptInstallTool 50 | id: AptInstallTool 51 | if: startsWith(github.event.ref, 'refs/tags/') 52 | shell: bash 53 | run: | 54 | sudo apt clean 55 | sudo apt update 56 | sudo apt install vim wget tar dh-make debmake lintian cmake qtbase5-dev qt5-default libqt5svg5-dev qtmultimedia5-dev qttools5-dev libqt5x11extras5-dev 57 | 58 | # tag 打包 .deb,无动态库 59 | - name: DebPackage 60 | id: DebPackage 61 | if: startsWith(github.event.ref, 'refs/tags/') 62 | shell: bash 63 | run: | 64 | echo "-------------- debug 0 --------------" 65 | pwd 66 | 67 | cd .. 68 | cp -r ${{ env.targetName }} ${{ env.productDebName }} 69 | tar -cvzf ${{ env.productDebName }}.tar.gz ${{ env.productDebName }} 70 | 71 | echo "-------------- debug 1 --------------" 72 | ls -al 73 | 74 | cat >> ~/.bashrc < 5 | 6 | #include "AboutAuthor.h" 7 | #include "ui_AboutAuthor.h" 8 | #include 9 | #include 10 | #include 11 | 12 | AboutAuthor::AboutAuthor(QWidget *parent) : 13 | QDialog(parent), 14 | ui(new Ui::AboutAuthor) 15 | { 16 | this->setWindowIcon(QIcon(":/images/chess.svg")); 17 | ui->setupUi(this); 18 | 19 | QPalette pl = ui->textBrowser->palette(); 20 | pl.setBrush(QPalette::Base,QBrush(QColor(255,0,0,0))); 21 | ui->textBrowser->setPalette(pl); 22 | } 23 | 24 | AboutAuthor::~AboutAuthor() 25 | { 26 | delete ui; 27 | } 28 | 29 | void AboutAuthor::paintEvent(QPaintEvent *event) 30 | { 31 | QPainter painter(this); 32 | painter.drawPixmap(rect(), QPixmap(":/images/background.jpg")); 33 | 34 | QDialog::paintEvent(event); 35 | } 36 | -------------------------------------------------------------------------------- /AboutAuthor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef ABOUTAUTHOR_H 7 | #define ABOUTAUTHOR_H 8 | 9 | #include 10 | #include 11 | 12 | namespace Ui 13 | { 14 | class AboutAuthor; 15 | } 16 | 17 | class AboutAuthor : public QDialog 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit AboutAuthor(QWidget* parent = 0); 23 | ~AboutAuthor(); 24 | 25 | protected: 26 | virtual void paintEvent(QPaintEvent* event) override; 27 | 28 | private: 29 | Ui::AboutAuthor* ui; 30 | }; 31 | 32 | #endif // ABOUTAUTHOR_H 33 | -------------------------------------------------------------------------------- /AboutAuthor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AboutAuthor 4 | 5 | 6 | 7 | 0 8 | 0 9 | 973 10 | 641 11 | 12 | 13 | 14 | Qt::NoFocus 15 | 16 | 17 | false 18 | 19 | 20 | Dialog 21 | 22 | 23 | 0 24 | 25 | 26 | Qt::RightToLeft 27 | 28 | 29 | 30 | 31 | 32 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 33 | <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> 34 | p, li { white-space: pre-wrap; } 35 | hr { height: 1px; border-width: 0; } 36 | li.unchecked::marker { content: "\2610"; } 37 | li.checked::marker { content: "\2612"; } 38 | </style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> 39 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'华文楷体';">作者:</span></p> 40 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'华文楷体';"> Copyright © 2019-2024 </span><a href="https://github.com/XMuli"><span style=" text-decoration: underline; color:#007af4;">偕臧</span></a><span style=" font-family:'华文楷体';"> </span></p> 41 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'华文楷体'; text-decoration: underline; color:#007af4;"><br /></p> 42 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">贡献者: </span></p> 43 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/Bruce-Ch"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">Bruce-Ch</span></a></p> 44 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/BlueArvin"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">BlueArvin</span></a></p> 45 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/Ubuntuser2012"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">Ubuntuser2012</span></a></p> 46 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/kira-yamatoo"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">kira-yamatoo</span></a></p> 47 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/hmsjy2017"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">hmsjy2017</span></a></p> 48 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/zjuyk"><span style=" text-decoration: underline; color:#007af4;">zjuyk</span></a></p> 49 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> - </span><a href="https://github.com/ryanfortner"><span style=" text-decoration: underline; color:#007af4;">ryanfortner</span></a></p> 50 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'FangSong';"><br /></p> 51 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">项目:</span></p> 52 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> 此为开源项目,兴趣之做;许可证 </span><a href="https://github.com/XMuli/ChineseChess/blob/master/LICENSE"><span style=" text-decoration: underline; color:#007af4;">GPL-3.0</span></a></p> 53 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> 项目源码: </span><a href="https://github.com/XMuli/ChineseChess"><span style=" text-decoration: underline; color:#007af4;">GitHub</span></a><span style=" font-family:'FangSong';">, 说明都在这里 [</span><a href="https://github.com/XMuli/chineseChess/blob/master/README.zh_CN.md"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">中文</span></a><span style=" font-family:'FangSong';"> | </span><a href="https://github.com/XMuli/chineseChess/blob/master/README.md"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">English</span></a><span style=" font-family:'FangSong';">]</span></p> 54 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'FangSong';"><br /></p> 55 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">其他: </span></p> 56 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> 对仓库 </span><a href="https://github.com/XMuli/chineseChess"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">ChineseChess</span></a><span style=" font-family:'FangSong';"> 的 star 和 fork 才是给我的最大鼓励,其次才是一杯加冰的快乐水,</span></p> 57 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">​ 当然欢迎任何人提交在提交 PR,帮助丰富它, 对应开发教程和源码已开源,供大家学习参考;</span></p> 58 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';"> 所有参与贡献的,亦都会留名在此。​热爱开源,热爱生命,热爱生活。</span></p> 59 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'FangSong';"><br /></p> 60 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">Bolg: </span><a href="https://xmuli.tech"><span style=" text-decoration: underline; color:#007af4;">xmuli.tech</span></a></p> 61 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">Gmail: xmulitech@gmail.com</span></p> 62 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'FangSong';">Telegram: </span><a href="https://t.me/xmuli"><span style=" font-family:'FangSong'; text-decoration: underline; color:#007af4;">https://t.me/xmuli</span></a></p> 63 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'FangSong';"><br /></p></body></html> 64 | 65 | 66 | true 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # Project created by QtCreator 2019-01-22T19:52:58 3 | # 4 | # 关于作者: 5 | # 偕臧 xmulitech@gmail.com 6 | # 项目完成时间: 2019-02-01 7 | # 功能更新时间: 2024-01-24 8 | # 其他:如果觉得该作品对你有用,或者有疑惑或者感谢,可以联系作者或者打赏; 9 | # 对我的 Star 和 Fork 是最大鼓励;当然有人欢迎你提交在 GitHub 提交 PR, 10 | # 已将源码和思路开源公布于我的github和博客,供大家学习参考 11 | # 12 | # 联系作者: 13 | # GitHub: https://github.com/XMuli/ChineseChess 14 | # Site: https://chinesechess.xmuli.tech 15 | # Telegram: https://t.me/xmuli 16 | # CSDN Bolg: https://blog.csdn.net/qq_33154343 17 | # My Blog: https://xmuli.tech 18 | #------------------------------------------------- 19 | cmake_minimum_required(VERSION 3.5) 20 | 21 | set(project_name ChineseChess) 22 | set(project_version_major 6) 23 | set(project_version_minor 3) 24 | set(project_version ${project_version_major}.${project_version_minor}) 25 | project(${project_name} VERSION ${project_version} LANGUAGES CXX) 26 | 27 | add_definitions(-DXBUILD_TIME="2023.12.14") 28 | 29 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 30 | set(CMAKE_AUTOUIC ON) 31 | set(CMAKE_AUTOMOC ON) 32 | set(CMAKE_AUTORCC ON) 33 | set(CMAKE_CXX_STANDARD 17) 34 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 35 | set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/bin") # qtcreator + msvc 可执行文件的输出目录 36 | set(CMAKE_BINARY_DIR "${EXECUTABLE_OUTPUT_PATH}") # visual studio 2022 可执行的输出目录 37 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}) # 创建输出目录 38 | 39 | #set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) 40 | 41 | # 需要配置环境变量QT5_DIR 42 | #set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} $ENV{QT5_DIR}) 43 | 44 | set(qt_moduls Widgets Gui OpenGL Network Xml Svg Multimedia) # Network Multimedia WebSockets 45 | set(qt_version_moduls) 46 | foreach(it ${qt_moduls}) 47 | list(APPEND qt_version_moduls Qt${QT_VERSION_MAJOR}::${it}) 48 | message("--->qt_moduls:" Qt${QT_VERSION_MAJOR}::${it}) 49 | endforeach() 50 | 51 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS ${qt_moduls} LinguistTools) 52 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS ${qt_moduls} LinguistTools) # LinguistTools No link 53 | 54 | set(src_files 55 | main.cpp 56 | ChessBoard.h 57 | ChessBoard.cpp 58 | ChessBoard.ui 59 | ChessPieces.h 60 | ChessPieces.cpp 61 | ChessStep.h 62 | ChessStep.cpp 63 | ChessVoice.h 64 | ChessVoice.cpp 65 | MachineGame.h 66 | MachineGame.cpp 67 | NetworkGame.h 68 | NetworkGame.cpp 69 | ChooseMainWindow.h 70 | ChooseMainWindow.cpp 71 | AboutAuthor.h 72 | AboutAuthor.cpp 73 | AboutAuthor.ui 74 | 75 | resources/res.qrc 76 | resources/logo/resources.rc 77 | ) 78 | 79 | #********************************************** 判断且定义 x64/x86 变量 (get kit architecture bit) **************************** 80 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 81 | set(arch_bit "86") 82 | set(is_x64bit false) 83 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 84 | set(arch_bit "64") 85 | set(is_x64bit true) 86 | endif() 87 | 88 | # 定义一些 qt bin 的基础变量 89 | set(qt_binray_dir "${Qt5_DIR}/../../../bin") # C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5/../../../bin 90 | 91 | if(UNIX) # using apt install qt5-devtools* 92 | # set(lupdate_path "lupdate") 93 | # set(lrelease_path "lrelease") 94 | 95 | execute_process(COMMAND lsb_release -i OUTPUT_VARIABLE LSB_ID) 96 | if (LSB_ID MATCHES "Deepin" OR LSB_ID MATCHES "UOS") 97 | set(lupdate_path "/usr/lib/qt5/bin/lupdate") 98 | set(lrelease_path "/usr/lib/qt5/bin/lrelease") 99 | message("This is a Deepin or UOS system.") 100 | else() 101 | set(lupdate_path "lupdate") 102 | set(lrelease_path "lrelease") 103 | message("This is other linux system.") 104 | endif() 105 | 106 | else() 107 | set(lupdate_path "${qt_binray_dir}/lupdate") 108 | set(lrelease_path "${qt_binray_dir}/lrelease") 109 | 110 | if(WIN32) 111 | set(windeployqt "${qt_binray_dir}/windeployqt.exe") 112 | elseif(APPLE) 113 | set(windeployqt "${qt_binray_dir}/macdeployqt") 114 | elseif(UNIX) 115 | # custom deployqt 116 | endif() 117 | endif() 118 | 119 | message("Qt5_DIR:" ${Qt5_DIR}) 120 | message("qt_binray_dir:" ${qt_binray_dir}) 121 | message("windeployqt:" ${windeployqt}) 122 | message("lupdate_path:" ${lupdate_path}) 123 | message("lrelease_path:" ${lrelease_path}) 124 | message("EXECUTABLE_OUTPUT_PATH:" ${EXECUTABLE_OUTPUT_PATH}) 125 | message("CMAKE_BINARY_DIR:" ${CMAKE_BINARY_DIR}) 126 | message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}") 127 | message("CMAKE_RUNTIME_OUTPUT_DIRECTORY: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") 128 | message("CMAKE_RUNTIME_OUTPUT_DIRECTORY: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") # exe 和 dll 运行的输出路径 129 | message("CMAKE_LIBRARY_OUTPUT_DIRECTORY: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") # 动态链接库(DLL、SO 等)的输出目录(实际不生效) 130 | message("CMAKE_ARCHIVE_OUTPUT_DIRECTORY: ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}") # 静态库的输出目录 131 | #************************************************* 拷贝 .ini 和资源文件 ******************************************************* 132 | # copy "resources" 文件夹下的指定文件夹 133 | set(folders_to_copy "licenses" "logo" "debian" "debian_portable") # "cpack" 134 | set(source_root "${CMAKE_SOURCE_DIR}/resources") 135 | set(traget_root "${EXECUTABLE_OUTPUT_PATH}/resources") 136 | 137 | # 遍历复制文件夹集合中的每个文件夹 138 | foreach(it ${folders_to_copy}) 139 | set(copy_source_dir "${source_root}/${it}") 140 | file(COPY ${copy_source_dir} DESTINATION ${traget_root}) 141 | endforeach() 142 | 143 | #file(COPY "${CMAKE_SOURCE_DIR}/xconfig.ini" DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") 144 | #******************************************* ********************************************** 145 | 146 | add_executable(${project_name} ${src_files}) 147 | target_link_libraries(${project_name} PRIVATE ${qt_version_moduls}) 148 | 149 | set_target_properties(${project_name} PROPERTIES 150 | MACOSX_BUNDLE_GUI_IDENTIFIER https://chinesechess.xmuli.tech 151 | ${BUNDLE_ID_OPTION} 152 | MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} 153 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 154 | MACOSX_BUNDLE TRUE 155 | WIN32_EXECUTABLE TRUE 156 | ) 157 | 158 | # Define some variables that can be used in *.cpp 159 | target_compile_definitions(${project_name} PRIVATE XPROJECT_NAME="${project_name}") 160 | target_compile_definitions(${project_name} PRIVATE XPROJECT_VERSION="${project_version}") 161 | target_compile_definitions(${project_name} PRIVATE XARCH_BIT="${arch_bit}") 162 | target_compile_definitions(${project_name} PRIVATE XCOMPILER="${CMAKE_HOST_SYSTEM_PROCESSOR}") # i386/i686/x86_64/unknown Win: AMD64 163 | target_compile_definitions(${project_name} PRIVATE XCOMPILER_ID="${CMAKE_CXX_COMPILER_ID}") # Clang/GCC/MSVC or GNU 164 | 165 | message("------------BRGIN------------") 166 | message("XPROJECT_NAME:${project_name}") 167 | message("XPROJECT_VERSION:${project_version}") 168 | message("XARCH_BIT:${arch_bit}") 169 | message("XCOMPILER:${CMAKE_HOST_SYSTEM_PROCESSOR}") 170 | message("XCOMPILER_ID:${CMAKE_CXX_COMPILER_ID}") 171 | 172 | message("CMake Path:" 173 | "\nPROJECT_NAME:" ${project_name} 174 | "\nCMAKE_INSTALL_PREFIX:" ${CMAKE_INSTALL_PREFIX} 175 | "\nPROJECT_BINARY_DIR:" ${PROJECT_BINARY_DIR} 176 | "\nCMAKE_INSTALL_BINDIR:" ${CMAKE_INSTALL_BINDIR} 177 | "\nCMAKE_INSTALL_LIBDIR:" ${CMAKE_INSTALL_LIBDIR} 178 | "\nCMAKE_INSTALL_INCLUDEDIR:" ${CMAKE_INSTALL_INCLUDEDIR}) 179 | message("------------END------------") 180 | 181 | target_compile_definitions(${project_name} PRIVATE UNICODE _UNICODE) # 定义 XWIDGET_LIBRARY 宏( ET 后面没有 S),表明为导出。后期将导出为 动态库 封装 182 | 183 | if(MSVC) 184 | # 设置默认启动 project 185 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${project_name}) 186 | # Fix: Visual Studio 2022 生成的目标文件的输出目录, 移除掉 Release/Debug 的多一层文件夹 187 | set_target_properties(${project_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${EXECUTABLE_OUTPUT_PATH}") 188 | set_target_properties(${project_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${EXECUTABLE_OUTPUT_PATH}") 189 | set_target_properties(${project_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${EXECUTABLE_OUTPUT_PATH}") 190 | set_target_properties(${project_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${EXECUTABLE_OUTPUT_PATH}") 191 | set_target_properties(${project_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${EXECUTABLE_OUTPUT_PATH}") 192 | set_target_properties(${project_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${EXECUTABLE_OUTPUT_PATH}") 193 | set_target_properties(${project_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${EXECUTABLE_OUTPUT_PATH}") 194 | set_target_properties(${project_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${EXECUTABLE_OUTPUT_PATH}") 195 | 196 | # 开启 MSVC 终端上的中文不乱码 197 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") 198 | add_compile_options(/source-charset:utf-8 /execution-charset:utf-8) 199 | # add_compile_options("$<$:/utf-8>") 200 | # add_compile_options("$<$:/utf-8>") 201 | # 开启 UNICODE 等常规 202 | target_compile_definitions(${project_name} PRIVATE 203 | WIN32_LEAN_AND_MEAN # Header files containing only the common APIs 204 | _CRT_SECURE_NO_WARNINGS # Unsafe functions such as strcpy, scanf, etc. are allowed) 205 | ) 206 | endif() 207 | 208 | # msvc multicore compilation 209 | if (WIN32) 210 | if(MSVC) 211 | add_definitions(-DUNICODE -D_UNICODE) # 设置 DUNICODE 编码 212 | OPTION(USE_MP "use multiple" ON) 213 | OPTION(ProjectConfig_Global_COMPILE_FLAGS_WITH_MP 214 | "Set The Global Option COMPILE_FLAGS /MP to target." ON) 215 | if(ProjectConfig_Global_COMPILE_FLAGS_WITH_MP OR USE_MP) 216 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") 217 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") 218 | endif() 219 | set(VS_STARTUP_PROJECT ${project_name}) 220 | endif(MSVC) 221 | endif() 222 | 223 | #******************************************* 拷贝 ssl 和对应的 qt 依赖 ******************************************************* 224 | if(APPLE) 225 | #file(COPY "/usr/local/Cellar/openssl@3/3.1.1/lib/libcrypto.3.dylib" DESTINATION "${EXECUTABLE_OUTPUT_PATH}") 226 | #file(COPY "/usr/local/Cellar/openssl@3/3.1.1/lib/libssl.3.dylib" DESTINATION "${exe_output_dir}") 227 | add_custom_command(TARGET ${project_name} POST_BUILD COMMAND "${windeployqt}" "${EXECUTABLE_OUTPUT_PATH}/${project_name}.app" "-verbose=1") 228 | add_custom_command(TARGET ${project_name} POST_BUILD COMMAND "${windeployqt}" "${EXECUTABLE_OUTPUT_PATH}/${project_name}.app" "-dmg") 229 | elseif(UNIX) 230 | elseif(WIN32) 231 | # if(${is_x64bit}) 232 | # set(ssl_dir "C:/Qt/Tools/OpenSSL/Win_x64/") 233 | # set(ssl_file "libssl-1_1-x64.dll" "libcrypto-1_1-x64.dll") 234 | # else() 235 | # set(ssl_dir "C:/Qt/Tools/OpenSSL/Win_x86/") 236 | # set(ssl_file "libssl-1_1.dll" "libcrypto-1_1.dll") 237 | # endif() 238 | 239 | # foreach(it ${ssl_file}) 240 | # file(COPY "${ssl_dir}/bin/${it}" DESTINATION "${EXECUTABLE_OUTPUT_PATH}") 241 | # message("--->it:" "${ssl_dir}/bin/${it}") 242 | # endforeach() 243 | 244 | add_custom_command(TARGET ${project_name} POST_BUILD COMMAND "${windeployqt}" "${EXECUTABLE_OUTPUT_PATH}/${project_name}.exe" --no-opengl-sw --no-translations) 245 | endif() 246 | #****************************************************** ********************************************************************* 247 | 248 | if(APPLE) 249 | elseif(WIN32) 250 | # install(TARGETS ${project_name} RUNTIME) 251 | else() 252 | install(TARGETS ${project_name} RUNTIME DESTINATION /usr/bin) 253 | endif() 254 | -------------------------------------------------------------------------------- /ChessBoard.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "ChessBoard.h" 7 | #include "ui_ChessBoard.h" 8 | #include 9 | 10 | ChessBoard::ChessBoard(QWidget *parent) : 11 | QMainWindow(parent), 12 | ui(new Ui::ChessBoard) 13 | { 14 | init(); 15 | 16 | //计时器部分 17 | m_timer = new QTimer; //初始化定时器 18 | m_timeRecord = new QTime(0, 0, 0); //初始化时间 19 | m_bIsStart = false; //初始为还未计时 20 | connect(m_timer,SIGNAL(timeout()),this,SLOT(updateTime())); 21 | 22 | m_pAbout = new AboutAuthor(); 23 | 24 | this->setWindowIcon(QIcon(":/images/chess.svg")); 25 | ui->setupUi(this); 26 | } 27 | 28 | ChessBoard::~ChessBoard() 29 | { 30 | delete ui; 31 | } 32 | 33 | void ChessBoard::init() 34 | { 35 | for(int i = 0; i<32; i++) 36 | m_ChessPieces[i].init(i); 37 | 38 | m_ChessSteps.clear(); //重置步数 39 | m_nSelectID = -1; 40 | m_nCheckedID = -1; 41 | m_bIsTcpServer = true; 42 | m_bIsRed = true; 43 | m_bIsOver = false; 44 | m_bIsShowStep = true; 45 | } 46 | 47 | bool ChessBoard:: isRed(int id) 48 | { 49 | return m_ChessPieces[id].m_bRed; 50 | } 51 | 52 | 53 | void ChessBoard:: killStone(int id) 54 | { 55 | if(id== -1) 56 | return; 57 | m_ChessPieces[id].m_bDead= true; 58 | } 59 | 60 | void ChessBoard:: reliveStone(int id) 61 | { 62 | if(id== -1) 63 | return; 64 | m_ChessPieces[id].m_bDead= false; 65 | } 66 | 67 | void ChessBoard:: moveStone(int moveid, int row, int col) 68 | { 69 | m_ChessPieces[moveid].m_nRow= row; 70 | m_ChessPieces[moveid].m_nCol= col; 71 | 72 | m_bIsRed= !m_bIsRed; //换边 73 | } 74 | 75 | bool ChessBoard::sameColor(int moveId,int killId) 76 | { 77 | if(moveId== -1 || killId== -1) 78 | return false; 79 | 80 | return isRed(moveId)== isRed(killId); 81 | } 82 | 83 | bool ChessBoard::isDead(int id) 84 | { 85 | if(id == -1) 86 | return true; 87 | 88 | return m_ChessPieces[id].m_bDead; 89 | } 90 | 91 | int ChessBoard::getStoneId(int row, int col) 92 | { 93 | for(int i=0; i<32; ++i) 94 | { 95 | if(m_ChessPieces[i].m_nRow == row && m_ChessPieces[i].m_nCol == col && !isDead(i)) 96 | return i; 97 | } 98 | 99 | return -1; 100 | } 101 | 102 | int ChessBoard::getStoneCountAtLine(int row1, int col1, int row2, int col2) 103 | { 104 | int ret = 0; 105 | if(row1 != row2 && col1 != col2) 106 | return -1; 107 | if(row1 == row2 && col1 == col2) 108 | return -1; 109 | 110 | if(row1 == row2) 111 | { 112 | int min = col1 < col2 ? col1 : col2; 113 | int max = col1 < col2 ? col2 : col1; 114 | for(int col = min+1; colcentralwidget->width() - ui->verticalWidget->width()) / 0.9), ui->label->height()); 199 | painter.scale(side / 960.0, side / 960.0); 200 | 201 | m_nOffSet = 60; //距离界面的边距 202 | m_nD = 90; //间距为50px 203 | m_nR = m_nD/2; //棋子半径为d/2 204 | 205 | //*******************绘画棋盘******************* 206 | //绘画10条横线 207 | for(int i = 0; i <= 9; i++) 208 | painter.drawLine(QPoint(m_nOffSet, m_nOffSet+i*m_nD), QPoint(m_nOffSet+8*m_nD, m_nOffSet+i*m_nD)); 209 | 210 | //绘画9条竖线 211 | for(int i = 0; i <= 8; i++) 212 | { 213 | if(i==0 || i==8) 214 | { 215 | painter.drawLine(QPoint(m_nOffSet+i*m_nD, m_nOffSet), QPoint(m_nOffSet+i*m_nD, m_nOffSet+9*m_nD)); 216 | } 217 | else 218 | { 219 | painter.drawLine(QPoint(m_nOffSet+i*m_nD, m_nOffSet), QPoint(m_nOffSet+i*m_nD, m_nOffSet+4*m_nD)); 220 | painter.drawLine(QPoint(m_nOffSet+i*m_nD, m_nOffSet+5*m_nD), QPoint(m_nOffSet+i*m_nD, m_nOffSet+9*m_nD)); 221 | } 222 | } 223 | 224 | //绘画4条斜线 225 | painter.drawLine(QPoint(m_nOffSet+3*m_nD, m_nOffSet), QPoint(m_nOffSet+5*m_nD, m_nOffSet+2*m_nD)); 226 | painter.drawLine(QPoint(m_nOffSet+3*m_nD, m_nOffSet+2*m_nD), QPoint(m_nOffSet+5*m_nD, m_nOffSet)); 227 | painter.drawLine(QPoint(m_nOffSet+3*m_nD, m_nOffSet+7*m_nD), QPoint(m_nOffSet+5*m_nD, m_nOffSet+9*m_nD)); 228 | painter.drawLine(QPoint(m_nOffSet+3*m_nD, m_nOffSet+9*m_nD), QPoint(m_nOffSet+5*m_nD, m_nOffSet+7*m_nD)); 229 | 230 | QRect rect1(m_nOffSet+m_nD, m_nOffSet+4*m_nD, m_nD, m_nD); 231 | QRect rect2(m_nOffSet+2*m_nD, m_nOffSet+4*m_nD, m_nD, m_nD); 232 | QRect rect3(m_nOffSet+5*m_nD, m_nOffSet+4*m_nD, m_nD, m_nD); 233 | QRect rect4(m_nOffSet+6*m_nD, m_nOffSet+4*m_nD, m_nD, m_nD); 234 | painter.setFont(QFont("FangSong", m_nR * 5 / 6, 800)); 235 | painter.drawText(rect1, "楚", QTextOption(Qt::AlignCenter)); 236 | painter.drawText(rect2, "河", QTextOption(Qt::AlignCenter)); 237 | painter.drawText(rect3, "汉", QTextOption(Qt::AlignCenter)); 238 | painter.drawText(rect4, "界", QTextOption(Qt::AlignCenter)); 239 | 240 | //*******************绘画棋子******************* 241 | //绘制上次移动棋子的起止位置 242 | if(m_bIsShowStep) 243 | drawLastStep(painter,m_ChessSteps); 244 | 245 | for(int i = 0; i < 32; i++) 246 | drawChessPieces(painter, i); 247 | 248 | //绘制文本棋谱 249 | drawTextStep(); 250 | } 251 | 252 | void ChessBoard::drawChessPieces(QPainter &painter, int id) //绘画单个具体的棋子 253 | { 254 | if(m_ChessPieces[id].m_bDead) 255 | return; 256 | 257 | QPoint temp = center(id); 258 | QRect rect(temp.x()-m_nR, temp.y()-m_nR, m_nD, m_nD); 259 | 260 | if(m_nSelectID == id) 261 | painter.setBrush(QBrush(QColor(64,64,196, 80))); 262 | else 263 | painter.setBrush(QBrush(QColor(64,64,196, 10))); 264 | 265 | painter.setPen(QColor(0, 0, 0)); 266 | painter.drawEllipse(center(id), m_nR, m_nR); //绘画圆形 267 | painter.setFont(QFont("FangSong", m_nR * 5 / 6, 2700)); 268 | 269 | if(id < 16) 270 | painter.setPen(QColor(0, 0, 0)); 271 | else 272 | painter.setPen(QColor(255, 0, 0)); 273 | 274 | painter.drawText(rect, m_ChessPieces[id].getnName(m_ChessPieces[id].m_bRed), QTextOption(Qt::AlignCenter)); //绘画圆形里面的汉字 275 | } 276 | 277 | void ChessBoard:: drawLastStep(QPainter &painter,QVector& steps) 278 | { 279 | if (this->m_ChessSteps.size() == 0) 280 | return; 281 | 282 | QPoint stepFrom = center(steps.last()->m_nRowFrom,steps.last()->m_nColFrom); 283 | QRect rectFrom(stepFrom.x()-m_nR, stepFrom.y()-m_nR, m_nD, m_nD); 284 | painter.setBrush(QColor(0, 0, 0, 0.3 * 255)); 285 | QPen pen(Qt::SolidLine); 286 | painter.setPen(Qt::black); 287 | painter.drawRect(rectFrom); 288 | 289 | QPoint stepTo = center(steps.last()->m_nRowTo,steps.last()->m_nnColTo); 290 | QRect rectTo(stepTo.x()-m_nR, stepTo.y()-m_nR, m_nD, m_nD); 291 | painter.setBrush(QColor(0, 0, 0, 0.2 * 255)); 292 | pen.setStyle(Qt::SolidLine); 293 | pen.setColor(Qt::black); 294 | painter.setPen(pen); 295 | painter.drawRect(rectTo); 296 | } 297 | 298 | void ChessBoard::drawTextStep() 299 | { 300 | ui->labelTextStep->setText(textStepRecord); 301 | } 302 | 303 | // true 产生"对将" 情景了;false 无"对将"情况 304 | bool ChessBoard::hongMenFeast() 305 | { 306 | if (m_ChessPieces[4].m_bDead || m_ChessPieces[20].m_bDead) 307 | return false; 308 | 309 | int colBlack = m_ChessPieces[4].m_nCol; 310 | int colRed = m_ChessPieces[20].m_nCol; 311 | int rowBlack = m_ChessPieces[4].m_nRow; 312 | int rowRed = m_ChessPieces[20].m_nRow; 313 | 314 | bool bColEmpty = true; 315 | if (colBlack == colRed){ 316 | for (int row = rowBlack + 1; row < rowRed ; ++row) { 317 | if (havePieces(row, colBlack)) 318 | bColEmpty = false; // 将之间有棋子;非此列为空 319 | } 320 | } else { 321 | bColEmpty = false; 322 | } 323 | 324 | return bColEmpty; 325 | } 326 | 327 | // 判断某格子是否有棋子在其上 328 | bool ChessBoard::havePieces(int row, int col) 329 | { 330 | for (auto pieces : m_ChessPieces) { 331 | if (pieces.m_bDead) 332 | continue; 333 | 334 | if (pieces.m_nRow == row && pieces.m_nCol == col) 335 | return true; 336 | } 337 | 338 | return false; 339 | } 340 | 341 | // 胜负已分,重置 342 | void ChessBoard::reset() 343 | { 344 | m_Chessvoice.voiceWin(); 345 | m_bIsOver = true; 346 | //游戏结束 则计时停止 & 计时控制按钮不再可用 直到用户重新游戏 347 | if(m_bIsStart) 348 | { 349 | m_timer->stop(); 350 | m_bIsStart = false; 351 | } 352 | 353 | ui->pushButton_start->setEnabled(false); 354 | } 355 | 356 | void ChessBoard::winMessageBox(QString title, QString msg) 357 | { 358 | QMessageBox message(QMessageBox::Information, title, msg); 359 | message.setIconPixmap(QPixmap(":/images/win.jpg")); 360 | message.setFont(QFont("FangSong", 16, QFont::Bold)); 361 | message.exec(); 362 | } 363 | 364 | QPoint ChessBoard::getRealPoint(QPoint pt) 365 | { 366 | int side = qMin(int((ui->centralwidget->width() - ui->verticalWidget->width()) / 0.9), ui->label->height()); 367 | QPoint ret; 368 | 369 | ret.setX(pt.x() / double(side) * 960.0); 370 | ret.setY(pt.y() / double(side) * 960.0); 371 | 372 | return ret; 373 | } 374 | 375 | bool ChessBoard:: isGeneral() 376 | { 377 | int generalId=20; //当前回合方将军id 378 | if(!m_bIsRed) 379 | generalId=4; 380 | 381 | int row= m_ChessPieces[generalId].m_nRow; //当前回合方的将军row 382 | int col= m_ChessPieces[generalId].m_nCol; //当前回合方的将军col 383 | 384 | for(int i=0; i<32; ++i) 385 | { 386 | if(i>=16&& m_bIsRed) //红方时采用黑子0-15 黑方时采用红子16-32 387 | break; 388 | 389 | if(canMove(i,generalId,row,col) && !m_ChessPieces[i].m_bDead) //依次遍历存活子能否移动到指定坐标 390 | { 391 | return true; 392 | } 393 | } 394 | return false; 395 | } 396 | 397 | void ChessBoard::showNetworkGui(const bool &show) 398 | { 399 | ui->networkGroup->setVisible(show); 400 | } 401 | 402 | //鼠标按下事件 403 | //void ChessBoard::mousePressEvent(QMouseEvent *ev) 404 | //{ 405 | // //只响应鼠标左键的单击操作 防止游戏结束重复弹框 406 | // if(ev->button() != Qt::LeftButton || ev->type() != QEvent::Type::MouseButtonPress) 407 | // return; 408 | 409 | // QPoint pt = ev->pos(); 410 | // pt = getRealPoint(pt); 411 | // //将pt转化成棋盘的像行列值 412 | // //判断这个行列值上面有没有棋子 413 | // int row, col; 414 | 415 | // //点击棋盘外面就不做处理 416 | // if(!isChecked(pt, row, col)) 417 | // return; 418 | 419 | // if(m_bIsOver) 420 | // { 421 | // QMessageBox message(QMessageBox::Information, "提示", "本局已结束,请重新开始."); 422 | // message.setIconPixmap(QPixmap(":/images/win.jpg")); 423 | // message.setFont(QFont("FangSong",16,QFont::Bold)); 424 | // message.exec(); 425 | // return; 426 | // } 427 | 428 | // //判断是哪一个棋子被选中,根据ID(这里的局部i)来记录下来 429 | // int i; 430 | // m_nCheckedID = -1; 431 | 432 | // for(i = 0; i <= 31; i++) 433 | // { 434 | // if(m_ChessPieces[i].m_nRow == row && m_ChessPieces[i].m_nCol == col && !m_ChessPieces[i].m_bDead) 435 | // break; 436 | // } 437 | 438 | // if(0<=i && i<32) 439 | // m_nCheckedID = i; //选中的棋子的ID 440 | 441 | // bool newbIsRed = m_bIsRed; 442 | // clickPieces(m_nCheckedID, row, col); 443 | 444 | // // 刚执棋落子完成,出现对将 445 | // if (hongMenFeast() && m_nSelectID == -1 && newbIsRed != m_bIsRed) 446 | // { 447 | // winMessageBox("提示", "可将军,直接取胜"); 448 | // // TODO: 可将军,直接提示直接取胜的音效 449 | // } 450 | 451 | // update(); 452 | // whoWin(); 453 | //} 454 | 455 | //void ChessBoard::clickPieces(int checkedID, int& row, int& col) 456 | //{ 457 | // m_nCheckedID = checkedID; 458 | 459 | // if(m_nSelectID == -1) //选中棋子 460 | // { 461 | // // whoPlay(m_nCheckedID); 462 | 463 | // if(m_nCheckedID != -1) 464 | // { 465 | // if(m_bIsRed == m_ChessPieces[m_nCheckedID].m_bRed) 466 | // { 467 | // m_nSelectID = m_nCheckedID; 468 | // m_Chessvoice.voiceSelect(); //选棋音效 469 | // } 470 | // } 471 | // } 472 | // else//走棋子 473 | // { 474 | // if(canMove(m_nSelectID, m_nCheckedID, row, col )) 475 | // { 476 | // //m_nSelectID为第一次点击选中的棋子, 477 | // //m_nCheckedID为第二次点击||被杀的棋子ID,准备选中棋子下子的地方 478 | // m_ChessPieces[m_nSelectID].m_nRow = row; 479 | // m_ChessPieces[m_nSelectID].m_nCol = col; 480 | // if(m_nCheckedID != -1) 481 | // { 482 | // m_ChessPieces[m_nCheckedID].m_bDead = true; 483 | // m_Chessvoice.voiceEat(); //吃子音效 484 | // } 485 | // m_Chessvoice.voiceMove(); //移动音效 486 | 487 | // m_nSelectID = -1; 488 | // m_bIsRed = !m_bIsRed; 489 | // } 490 | // } 491 | //} 492 | 493 | 494 | //总的移动规则,选中准备下的棋子,被杀的棋子, 准备移动到的目的行列值 495 | //bool ChessBoard::canMove(int moveId, int killId, int row, int col) 496 | //{ 497 | // //1.确定是选择其它棋子还是走棋 498 | // //2.是否需要使用到canMoveXXX()来做限制 499 | // //3.罗列出所有情况,和需要的得到的结果值 ==> 然后进行中间的逻辑层判断※不要受到别人的代码框架的束缚※ 500 | 501 | // if(isRed(moveId) == m_ChessPieces[killId].m_bRed) //选择其它棋子,返回false 502 | // { 503 | // if(killId == -1) //其中有一个特殊情况,黑+m_ChessPieces[-1].m_bRed ==> 也需要判断能否 504 | // { 505 | // switch (m_ChessPieces[moveId].m_emType) 506 | // { 507 | // case ChessPieces::JIANG: 508 | // return canMoveJIANG(moveId, killId, row, col); 509 | // case ChessPieces::SHI: 510 | // return canMoveSHI(moveId, killId, row, col); 511 | // case ChessPieces::XIANG: 512 | // return canMoveXIANG(moveId, killId, row, col); 513 | // case ChessPieces::MA: 514 | // return canMoveMA(moveId, killId, row, col); 515 | // case ChessPieces::CHE: 516 | // return canMoveCHE(moveId, killId, row, col); 517 | // case ChessPieces::PAO: 518 | // return canMovePAO(moveId, killId, row, col); 519 | // case ChessPieces::BING: 520 | // return canMoveBING(moveId, killId, row, col); 521 | // } 522 | // } 523 | // m_nSelectID = killId; 524 | 525 | // return false; 526 | // } 527 | // else //选择其走棋,返回true 528 | // { 529 | // switch (m_ChessPieces[moveId].m_emType) 530 | // { 531 | // case ChessPieces::JIANG: 532 | // return canMoveJIANG(moveId, killId, row, col); 533 | // case ChessPieces::SHI: 534 | // return canMoveSHI(moveId, killId, row, col); 535 | // case ChessPieces::XIANG: 536 | // return canMoveXIANG(moveId, killId, row, col); 537 | // case ChessPieces::MA: 538 | // return canMoveMA(moveId, killId, row, col); 539 | // case ChessPieces::CHE: 540 | // return canMoveCHE(moveId, killId, row, col); 541 | // case ChessPieces::PAO: 542 | // return canMovePAO(moveId, killId, row, col); 543 | // case ChessPieces::BING: 544 | // return canMoveBING(moveId, killId, row, col); 545 | // } 546 | 547 | // return true; 548 | 549 | // } 550 | //} 551 | 552 | //总的移动规则 553 | bool ChessBoard::canMove(int moveId, int killId, int row, int col) 554 | { 555 | //选棋id和吃棋id同色,则选择其它棋子并返回 556 | if(sameColor(moveId,killId)) 557 | { 558 | //换选棋子 559 | m_nSelectID=killId; 560 | update(); 561 | return false; 562 | } 563 | 564 | switch (m_ChessPieces[moveId].m_emType) 565 | { 566 | case ChessPieces::JIANG: 567 | return canMoveJIANG(moveId, killId, row, col); 568 | 569 | case ChessPieces::SHI: 570 | return canMoveSHI(moveId, killId, row, col); 571 | 572 | case ChessPieces::XIANG: 573 | return canMoveXIANG(moveId, killId, row, col); 574 | 575 | case ChessPieces::MA: 576 | return canMoveMA(moveId, killId, row, col); 577 | 578 | case ChessPieces::CHE: 579 | return canMoveCHE(moveId, killId, row, col); 580 | 581 | case ChessPieces::PAO: 582 | return canMovePAO(moveId, killId, row, col); 583 | 584 | case ChessPieces::BING: 585 | return canMoveBING(moveId, killId, row, col); 586 | 587 | default: break; 588 | } 589 | 590 | return true; 591 | } 592 | 593 | bool ChessBoard::canMoveJIANG(int moveId, int killId, int row, int col) 594 | { 595 | //对将的情况 596 | if (killId != -1 && m_ChessPieces[killId].m_emType == m_ChessPieces->JIANG) 597 | return canMoveCHE(moveId, killId, row, col ); 598 | 599 | if(isRed(moveId)) //红 将 600 | { 601 | if(row < 7 || col < 3 || col > 5) return false; 602 | } 603 | else //黑 将 604 | { 605 | if(row > 2 || col < 3 || col > 5) return false; 606 | } 607 | 608 | int d=relation(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 609 | if(d == 1 || d == 10) 610 | return true; 611 | 612 | return false; 613 | } 614 | 615 | bool ChessBoard::canMoveSHI(int moveId, int killId, int row, int col) 616 | { 617 | Q_UNUSED(killId); 618 | if(isRed(moveId)) //红 士 619 | { 620 | if(row < 7 || col < 3 || col > 5) return false; 621 | } 622 | else //黑 士 623 | { 624 | if(row > 2 || col < 3 || col > 5) return false; 625 | } 626 | 627 | int d=relation(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 628 | if(d == 11) 629 | return true; 630 | 631 | return false; 632 | } 633 | 634 | bool ChessBoard::canMoveXIANG(int moveId, int killId, int row, int col) 635 | { 636 | Q_UNUSED(killId); 637 | int d=relation(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 638 | if(d!= 22) 639 | return false; 640 | 641 | int row_eye= (m_ChessPieces[moveId].m_nRow+ row)/ 2; 642 | int col_eye= (m_ChessPieces[moveId].m_nCol+ col)/ 2; 643 | 644 | //堵象眼 645 | if(getStoneId(row_eye,col_eye)!= -1) 646 | return false; 647 | 648 | //象不可过河 649 | if(isRed(moveId)) //红 650 | { 651 | if(row< 4) 652 | return false; 653 | } 654 | else //黑 655 | { 656 | if(row> 5) 657 | return false; 658 | } 659 | 660 | return true; 661 | } 662 | 663 | bool ChessBoard::canMoveMA(int moveId, int killId, int row, int col) 664 | { 665 | Q_UNUSED(killId); 666 | int d=relation(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 667 | if(d!=12 && d!=21) 668 | return false; 669 | 670 | //蹩马脚 671 | if(d==12) 672 | { 673 | if(getStoneId(m_ChessPieces[moveId].m_nRow, (m_ChessPieces[moveId].m_nCol+ col) /2) != -1) 674 | return false; 675 | } 676 | else 677 | { 678 | if(getStoneId((m_ChessPieces[moveId].m_nRow+ row) /2 ,m_ChessPieces[moveId].m_nCol) != -1) 679 | return false; 680 | } 681 | 682 | return true; 683 | } 684 | 685 | bool ChessBoard::canMoveCHE(int moveId, int killId, int row, int col) 686 | { 687 | Q_UNUSED(killId); 688 | int ret = getStoneCountAtLine(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 689 | if(ret == 0) 690 | return true; 691 | 692 | return false; 693 | } 694 | 695 | bool ChessBoard::canMovePAO(int moveId, int killId, int row, int col) 696 | { 697 | int ret = getStoneCountAtLine(row, col, m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol); 698 | if(killId != -1) 699 | { 700 | if(ret == 1) 701 | return true; 702 | } 703 | else 704 | { 705 | if(ret == 0) 706 | return true; 707 | } 708 | return false; 709 | } 710 | 711 | bool ChessBoard::canMoveBING(int moveId, int killId, int row, int col) 712 | { 713 | Q_UNUSED(killId); 714 | int d=relation(m_ChessPieces[moveId].m_nRow, m_ChessPieces[moveId].m_nCol, row, col); 715 | if(d!= 1 && d!= 10) 716 | return false; 717 | 718 | if(isRed(moveId)) //红 719 | { 720 | //兵卒不可后退 721 | if(row> m_ChessPieces[moveId].m_nRow) 722 | return false; 723 | 724 | //兵卒没过河不可横着走 725 | if(m_ChessPieces[moveId].m_nRow>= 5 && m_ChessPieces[moveId].m_nRow== row) 726 | return false; 727 | } 728 | else //黑 729 | { 730 | if(row< m_ChessPieces[moveId].m_nRow) 731 | return false; 732 | if(m_ChessPieces[moveId].m_nRow<= 4 && m_ChessPieces[moveId].m_nRow== row) 733 | return false; 734 | } 735 | 736 | return true; 737 | } 738 | 739 | bool ChessBoard:: canSelect(int id) 740 | { 741 | return m_bIsRed== m_ChessPieces[id].m_bRed; 742 | } 743 | 744 | void ChessBoard::mouseReleaseEvent(QMouseEvent *ev) 745 | { 746 | if (ev->button() != Qt::LeftButton || m_bIsOver== true) { // 排除鼠标右键点击 游戏已结束则直接返回 747 | return; 748 | } 749 | QPoint pt= ev->pos(); //获取当前鼠标位置坐标 750 | pt=getRealPoint(pt); //转换至实际像素坐标 751 | click(pt); 752 | } 753 | 754 | void ChessBoard::click(QPoint pt) 755 | { 756 | // 看有没有点中象棋 757 | // 将pt转化成象棋的行列值 758 | // 判断这个行列值上面有没有棋子 759 | int row, col; 760 | bool bClicked = isChecked(pt, row, col); 761 | if (!bClicked) { 762 | return; 763 | } 764 | 765 | int id = getStoneId(row, col); 766 | clickPieces(id, row, col); 767 | 768 | } 769 | 770 | void ChessBoard::clickPieces(int id, int &row, int &col) 771 | { 772 | if (this->m_nSelectID == -1) { // 如果点中的棋子之前未被选中 773 | trySelectStone(id); 774 | } 775 | else { 776 | tryMoveStone(id, row, col); 777 | } 778 | 779 | // 初次按下时,自启动计时器 780 | std::once_flag flag; 781 | std::call_once(flag, [&]() { 782 | m_bIsStart = false; 783 | on_pushButton_start_clicked(); 784 | }); 785 | } 786 | 787 | void ChessBoard::trySelectStone(int id) 788 | { 789 | if (id == -1) { 790 | return; 791 | } 792 | 793 | if (!canSelect(id)) { 794 | return; 795 | } 796 | 797 | m_nSelectID = id; 798 | update(); 799 | m_Chessvoice.voiceSelect(); 800 | } 801 | 802 | void ChessBoard::tryMoveStone(int killid, int row, int col) 803 | { 804 | if (killid != -1 && sameColor(killid, m_nSelectID)) { 805 | trySelectStone(killid); 806 | return; 807 | } 808 | 809 | bool ret = canMove(m_nSelectID, killid, row, col); 810 | if (ret) { 811 | doMoveStone(m_nSelectID, killid, row, col); 812 | m_nSelectID = -1; 813 | update(); 814 | } 815 | } 816 | 817 | void ChessBoard::doMoveStone(int moveid, int killid, int row, int col) 818 | { 819 | saveStep(moveid, killid, row, col, m_ChessSteps); 820 | 821 | killStone(killid); 822 | moveStone(moveid, row, col); 823 | whoWin(); 824 | 825 | if(killid== -1) 826 | m_Chessvoice.voiceMove(); //移动音效 827 | else 828 | m_Chessvoice.voiceEat(); //吃子音效 829 | 830 | if(isGeneral()) 831 | m_Chessvoice.voiceGeneral(); //将军音效 832 | } 833 | 834 | void ChessBoard::saveStep(int moveid, int killid, int row, int col, QVector& steps) 835 | { 836 | ChessStep* step = new ChessStep; 837 | step->m_nColFrom = m_ChessPieces[moveid].m_nCol; 838 | step->m_nnColTo = col; 839 | step->m_nRowFrom = m_ChessPieces[moveid].m_nRow; 840 | step->m_nRowTo = row; 841 | step->m_nMoveID = moveid; 842 | step->m_nKillID = killid; 843 | 844 | steps.append(step); 845 | textStepRecord= textStep(moveid, row, col); 846 | } 847 | 848 | QString ChessBoard::textStep(int id, int row, int col) 849 | { 850 | int rowFrom= m_ChessPieces[id].m_nRow; 851 | int rowTo= row; 852 | int colFrom= m_ChessPieces[id].m_nCol; 853 | int colTo= col; 854 | 855 | QString temp=""; 856 | QString name=m_ChessPieces[id].getnName(m_ChessPieces[id].m_bRed); 857 | QString textCol= m_ChessPieces[id].getColText(colFrom); 858 | QString textRow= m_ChessPieces[id].getRowText(rowTo); 859 | temp.append(name).append(textCol).append(textRow); 860 | 861 | //兵炮车将 862 | if(m_ChessPieces[id].m_emType==6 || m_ChessPieces[id].m_emType==5 || m_ChessPieces[id].m_emType==4 || m_ChessPieces[id].m_emType==0) 863 | { 864 | //行相等 865 | if(rowFrom== rowTo) 866 | { 867 | temp.append(m_ChessPieces[id].getColText(colTo)); 868 | return temp; 869 | } 870 | //移动的格数 871 | temp.append(m_ChessPieces[id].getMoveText(rowFrom, rowTo)); 872 | } 873 | else //马相士 874 | { 875 | //移动后所在列 876 | temp.append(m_ChessPieces[id].getColText(colTo)); 877 | } 878 | return temp; 879 | 880 | } 881 | 882 | void ChessBoard::backOne() 883 | { 884 | if (this->m_ChessSteps.size() == 0 || m_bIsOver) { 885 | return; 886 | } 887 | 888 | ChessStep* step = this->m_ChessSteps.last(); 889 | m_ChessSteps.removeLast(); 890 | back(step); 891 | 892 | update(); 893 | delete step; 894 | m_Chessvoice.voiceBack(); 895 | } 896 | 897 | void ChessBoard::back(ChessStep* step) 898 | { 899 | reliveStone(step->m_nKillID); 900 | moveStone(step->m_nMoveID, step->m_nRowFrom, step->m_nColFrom); 901 | } 902 | 903 | void ChessBoard::back() 904 | { 905 | backOne(); 906 | } 907 | 908 | //刷新时间 909 | void ChessBoard::updateTime() 910 | { 911 | *m_timeRecord = m_timeRecord->addSecs(1); 912 | ui->lcdNumber->display(m_timeRecord->toString("hh:mm:ss")); 913 | 914 | if(m_bIsStart == false) 915 | ui->pushButton_start->setText("开始"); 916 | else if(m_bIsStart == true) 917 | ui->pushButton_start->setText("暂停"); 918 | } 919 | 920 | void ChessBoard::on_pushButton_start_clicked() 921 | { 922 | if(!m_bIsStart) //尚未开始 开始计时 923 | { 924 | m_timer->start(1000); 925 | ui->pushButton_start->setText("暂停"); 926 | } 927 | else //已经开始,暂停 928 | { 929 | m_timer->stop(); 930 | ui->pushButton_start->setText("继续"); 931 | } 932 | 933 | m_bIsStart = !m_bIsStart; 934 | } 935 | 936 | void ChessBoard::on_pushButton_reset_clicked() 937 | { 938 | m_timer->stop(); //计时器停止 939 | m_timeRecord->setHMS(0,0,0); //时间设为0 940 | ui->lcdNumber->display(m_timeRecord->toString("hh:mm:ss")); //显示00:00:00 941 | m_bIsStart = false; 942 | ui->pushButton_start->setText("开始"); 943 | ui->pushButton_start->setEnabled(true); 944 | } 945 | 946 | void ChessBoard::on_pushButton_about_clicked() 947 | { 948 | m_pAbout->setWindowTitle("关于作者"); 949 | m_pAbout->show(); 950 | } 951 | 952 | void ChessBoard::on_pushButton_restart_clicked() 953 | { 954 | init(); 955 | on_pushButton_reset_clicked(); 956 | update(); 957 | } 958 | 959 | void ChessBoard::on_pushButton_back_clicked() 960 | { 961 | back(); 962 | update(); 963 | } 964 | 965 | void ChessBoard::on_pushButton_showStep_clicked() 966 | { 967 | m_bIsShowStep=!m_bIsShowStep; 968 | update(); 969 | } 970 | 971 | void ChessBoard::on_pushButton_toMenu_clicked() 972 | { 973 | emit this->toMenu(); 974 | } 975 | 976 | 977 | -------------------------------------------------------------------------------- /ChessBoard.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef CHESSBOARD_H 7 | #define CHESSBOARD_H 8 | 9 | /*** 10 | * ┌─┐ ┌─┐ + + 11 | * ┌──┘ ┴───────┘ ┴──┐++ 12 | * │ │ 13 | * │ ─── │++ + + + 14 | * ███████───███████ │+ 15 | * │ │+ 16 | * │ ─┴─ │ 17 | * │ │ 18 | * └───┐ ┌───┘ 19 | * │ │ 20 | * │ │ + + 21 | * │ │ 22 | * │ └──────────────┐ 23 | * │ │ 24 | * │ ├─┐ 25 | * │ ┌─┘ 26 | * │ │ 27 | * └─┐ ┐ ┌───────┬──┐ ┌──┘ + + + + 28 | * │ ─┤ ─┤ │ ─┤ ─┤ 29 | * └──┴──┘ └──┴──┘ + + + + 30 | * 神兽保佑 31 | * 代码无BUG! 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include "ChessPieces.h" 44 | #include "AboutAuthor.h" 45 | #include "ChessVoice.h" 46 | #include "ChessStep.h" 47 | 48 | namespace Ui { 49 | class ChessBoard; 50 | } 51 | 52 | class ChessBoard : public QMainWindow 53 | { 54 | Q_OBJECT 55 | 56 | public: 57 | explicit ChessBoard(QWidget *parent = 0); 58 | ~ChessBoard(); 59 | 60 | bool isRed(int id); 61 | bool isDead(int id); 62 | void killStone(int id); // 吃子 63 | void reliveStone(int id); // 死者苏生 64 | void moveStone(int moveid, int row, int col); // 移动棋子 65 | bool sameColor(int moveId, int killId); // 棋子是否同色 66 | int getStoneId(int row, int col); 67 | // 车、炮的功能辅助函数 判断两个点是否在一个直线上面,且返回直线之间的棋子个数 68 | int getStoneCountAtLine(int row1, int col1, int row2, int col2); 69 | void whoWin(); // 谁胜谁负 70 | bool isChecked(QPoint pt, int& row, int& col); // 是否选中该枚棋子。pt为输入参数; row, col为输出参数 71 | int relation(int row1, int col1, int row2, int col2); // 计算选中的棋子的位置和要移动的位置之间的位置关系 72 | QPoint getRealPoint(QPoint pt); // 使mouseMoveEvent取得的坐标同Painter的坐标一致 73 | bool isGeneral(); // 校验将移动后位置是否将死 74 | void showNetworkGui(const bool& show = false); 75 | 76 | private: 77 | bool hongMenFeast(); // 鸿门宴:对将 78 | bool havePieces(int row, int col); // 判断某一格子,是否有棋子 79 | void reset(); // 胜负已分,重置 80 | void winMessageBox(QString title, QString msg); 81 | 82 | public: 83 | //视图相关 84 | QPoint center(int row, int col); // 象棋的棋盘的坐标转换成界面坐标 85 | QPoint center(int id); 86 | virtual void paintEvent(QPaintEvent *); // 绘画棋盘 87 | void drawChessPieces(QPainter& painter, int id); // 绘画单个具体的棋子 88 | void drawLastStep(QPainter &painter, QVector& steps); // 绘制上次移动棋子的起止位置 89 | void drawTextStep(); // 绘制文本棋谱 90 | // virtual void mousePressEvent(QMouseEvent *); // 鼠标点击事件 91 | // virtual void clickPieces(int checkedID, int& row, int& col); 92 | 93 | // 象棋移动的规则[将 士 象 马 车 炮 兵] 94 | bool canMove(int moveId, int killId, int row, int col); 95 | bool canMoveJIANG(int moveId, int killId, int row, int col); 96 | bool canMoveSHI(int moveId, int killId, int row, int col); 97 | bool canMoveXIANG(int moveId, int killId, int row, int col); 98 | bool canMoveMA(int moveId, int killId, int row, int col); 99 | bool canMoveCHE(int moveId, int killId, int row, int col); 100 | bool canMovePAO(int moveId, int killId, int row, int col); 101 | bool canMoveBING(int moveId, int killId, int row, int col); 102 | bool canSelect(int id); 103 | void init(); 104 | 105 | //移动相关 106 | virtual void mouseReleaseEvent(QMouseEvent *ev); // 鼠标释放事件 107 | void click(QPoint pt); // 点击转换像素 108 | virtual void clickPieces(int id, int& row, int& col); // 点击选棋 109 | void trySelectStone(int id); // 尝试选棋 110 | void tryMoveStone(int killid, int row, int col); // 尝试移动 111 | void doMoveStone(int moveid, int killid, int row, int col); // 执行移动棋子 112 | void saveStep(int moveid, int killid, int row, int col, QVector& steps); // 保存步数 113 | QString textStep(int moveid, int row, int col); // 文本棋谱 114 | 115 | void backOne(); // 悔棋一子 116 | void back(ChessStep* step); // 悔棋到指定步数 117 | virtual void back(); // 悔棋 118 | 119 | ChessPieces m_ChessPieces[32]; // 所有棋子 120 | QVector m_ChessSteps; // 悔棋步数 121 | ChessVoice m_Chessvoice; // 下棋音效 122 | int m_nR; // 棋子半径 123 | int m_nOffSet; // 距离界面的边距 124 | int m_nD; // 间距为50px 125 | int m_nSelectID; // 选中棋子[-1:选棋子 || 非-1:走棋子] 126 | int m_nCheckedID; // 将要被击杀的棋子ID 127 | bool m_bIsRed; // 是否是红方回合 128 | bool m_bIsTcpServer; 129 | bool m_bIsOver; // 是否已经游戏结束 130 | bool m_bIsShowStep; // 是否显示步数 131 | QString textStepRecord; // 文本棋谱字符串 132 | 133 | signals: 134 | void toMenu(); 135 | 136 | private slots: 137 | void updateTime(); 138 | void on_pushButton_start_clicked(); 139 | void on_pushButton_reset_clicked(); 140 | void on_pushButton_about_clicked(); 141 | void on_pushButton_restart_clicked(); 142 | void on_pushButton_back_clicked(); 143 | void on_pushButton_showStep_clicked(); 144 | void on_pushButton_toMenu_clicked(); 145 | 146 | protected: 147 | Ui::ChessBoard *ui; 148 | 149 | private: 150 | QTimer* m_timer; // 定时器 每秒更新时间 151 | QTime* m_timeRecord; // 记录时间 152 | bool m_bIsStart; // 记录是否已经开始计时 153 | AboutAuthor* m_pAbout; 154 | }; 155 | 156 | #endif // CHESSBOARD_H 157 | -------------------------------------------------------------------------------- /ChessBoard.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ChessBoard 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1156 10 | 940 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 0 20 | 21 | 22 | 0 23 | 24 | 25 | 0 26 | 27 | 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 0 36 | 37 | 38 | 39 | 40 | 41 | 42 | false 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 0 51 | 0 52 | 53 | 54 | 55 | #verticalWidget{ 56 | border-image: url(:/images/b.jpg); 57 | } 58 | 59 | 60 | 61 | 62 | 63 | 64 | 18 65 | 66 | 67 | 68 | 对战计时: 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 0 77 | 0 78 | 79 | 80 | 81 | 82 | 0 83 | 83 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 0 92 | 93 | 94 | 95 | 96 | 97 | 0 98 | 0 99 | 100 | 101 | 102 | 开始 103 | 104 | 105 | 106 | 107 | 108 | 109 | Qt::Horizontal 110 | 111 | 112 | 113 | 40 114 | 20 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 0 124 | 0 125 | 126 | 127 | 128 | 重置 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 重新游戏 138 | 139 | 140 | 141 | 142 | 143 | 144 | 悔棋 145 | 146 | 147 | 148 | 149 | 150 | 151 | 显示/隐藏步数 152 | 153 | 154 | 155 | 156 | 157 | 158 | 返回主菜单 159 | 160 | 161 | 162 | 163 | 164 | 165 | Qt::Vertical 166 | 167 | 168 | 169 | 20 170 | 40 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 请输入服务器IP和prot: 179 | 180 | 181 | 182 | 0 183 | 184 | 185 | 186 | 187 | <html><head/><body><p><a href="https://github.com/XMuli/ChineseChess/wiki/%E7%BD%91%E7%BB%9C%E5%AF%B9%E6%88%98%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE"><span style=" text-decoration: underline; color:#007af4;">📖 Wiki</span></a></p></body></html> 188 | 189 | 190 | true 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 0 199 | 0 200 | 201 | 202 | 203 | 204 | 60 205 | 0 206 | 207 | 208 | 209 | 210 | 60 211 | 16777215 212 | 213 | 214 | 215 | 连接 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 0 224 | 0 225 | 226 | 227 | 228 | 229 | 0 230 | 0 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 等待操作中 254 | 255 | 256 | true 257 | 258 | 259 | 260 | 261 | 262 | 263 | IP: 264 | 265 | 266 | 267 | 268 | 269 | 270 | Port: 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 0 279 | 0 280 | 281 | 282 | 283 | 284 | 0 285 | 0 286 | 287 | 288 | 289 | 290 | 60 291 | 16777215 292 | 293 | 294 | 295 | 65535 296 | 297 | 298 | 9999 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 宋体 310 | 20 311 | 312 | 313 | 314 | labelTextStep 315 | 316 | 317 | 318 | 319 | 320 | 321 | 0 322 | 323 | 324 | 325 | 326 | Qt::Horizontal 327 | 328 | 329 | 330 | 40 331 | 20 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 0 341 | 0 342 | 343 | 344 | 345 | 关于作者 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 0 360 | 0 361 | 1156 362 | 17 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | -------------------------------------------------------------------------------- /ChessPieces.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "ChessPieces.h" 7 | 8 | //1、定义结构体tPOS 9 | struct POS 10 | { 11 | int t_nRow; 12 | int t_nCol; 13 | ChessPieces::m_emTYPE t_emType; 14 | }; 15 | 16 | //定义基础的16棋子[预定作为上方使用,黑棋使用] 17 | POS tPos[16]= { 18 | {0, 0, ChessPieces::CHE}, 19 | {0, 1, ChessPieces::MA}, 20 | {0, 2, ChessPieces::XIANG}, 21 | {0, 3, ChessPieces::SHI}, 22 | {0, 4, ChessPieces::JIANG}, 23 | {0, 5, ChessPieces::SHI}, 24 | {0, 6, ChessPieces::XIANG}, 25 | {0, 7, ChessPieces::MA}, 26 | {0, 8, ChessPieces::CHE}, 27 | 28 | {2, 1, ChessPieces::PAO}, 29 | {2, 7, ChessPieces::PAO}, 30 | {3, 0, ChessPieces::BING}, 31 | {3, 2, ChessPieces::BING}, 32 | {3, 4, ChessPieces::BING}, 33 | {3, 6, ChessPieces::BING}, 34 | {3, 8, ChessPieces::BING} 35 | }; 36 | 37 | ChessPieces::ChessPieces() 38 | { 39 | } 40 | 41 | ChessPieces::~ChessPieces() 42 | { 43 | } 44 | 45 | //初始化 对每一个棋子进行检验判断而后赋相应的值 46 | void ChessPieces::init(int id) 47 | { 48 | if(id <16) 49 | { 50 | m_nRow = tPos[id].t_nRow; 51 | m_nCol = tPos[id].t_nCol; 52 | m_emType = tPos[id].t_emType; 53 | m_bRed = false; 54 | } 55 | else 56 | { 57 | m_nRow = 9-tPos[id-16].t_nRow; 58 | m_nCol = 8-tPos[id-16].t_nCol; 59 | m_emType = tPos[id-16].t_emType; 60 | m_bRed = true; 61 | } 62 | 63 | m_bDead = false; 64 | } 65 | 66 | QString ChessPieces::getnName(bool isRedSide) 67 | { 68 | if(isRedSide){ 69 | switch (m_emType) { 70 | case CHE: 71 | return "俥"; 72 | case MA: 73 | return "傌"; 74 | case PAO: 75 | return "炮"; 76 | case BING: 77 | return "兵"; 78 | case JIANG: 79 | return "帥"; 80 | case SHI: 81 | return "仕"; 82 | case XIANG: 83 | return "相"; 84 | default: 85 | return "null"; 86 | } 87 | } 88 | else{ 89 | switch (m_emType) { 90 | case CHE: 91 | return "車"; 92 | case MA: 93 | return "馬"; 94 | case PAO: 95 | return "砲"; 96 | case BING: 97 | return "卒"; 98 | case JIANG: 99 | return "將"; 100 | case SHI: 101 | return "士"; 102 | case XIANG: 103 | return "象"; 104 | default: 105 | return "null"; 106 | } 107 | } 108 | return "ERROR"; 109 | } 110 | 111 | /** 112 | * @brief 获取棋子所在列 返回文本棋谱 113 | * @return QString 114 | */ 115 | QString ChessPieces::getColText(int col) 116 | { 117 | QString colText; 118 | if(m_bRed) 119 | { 120 | colText= colTextRed[col]; 121 | } 122 | else 123 | { 124 | colText= colTextBlack[col]; 125 | } 126 | return colText; 127 | } 128 | 129 | /** 130 | * @brief 获取棋子所在行 返回文本棋谱 131 | * @param rowTo 132 | * @return QString 133 | */ 134 | QString ChessPieces::getRowText(int rowTo) 135 | { 136 | QString temp=""; 137 | if(m_nRow== rowTo) 138 | { 139 | temp.append("平"); 140 | return temp; 141 | } 142 | if(m_nRow> rowTo) 143 | { 144 | if(m_bRed){ 145 | temp.append("进"); 146 | } 147 | else 148 | { 149 | temp.append("退"); 150 | } 151 | } 152 | else 153 | { 154 | if(m_bRed){ 155 | temp.append("退"); 156 | } 157 | else 158 | { 159 | temp.append("进"); 160 | } 161 | } 162 | return temp; 163 | } 164 | 165 | /** 166 | * @brief 获取棋子移动的格数 返回文本棋谱 167 | * @param rowFrom 168 | * @param rowTo 169 | * @return QString 170 | */ 171 | QString ChessPieces::getMoveText(int rowFrom, int rowTo) 172 | { 173 | QString temp=""; 174 | if(m_bRed) 175 | { 176 | temp.append(colTextRedTurn[abs(rowFrom-rowTo) -1]); 177 | } 178 | else 179 | { 180 | temp.append(colTextBlack[abs(rowFrom-rowTo) -1]); 181 | } 182 | return temp; 183 | } 184 | -------------------------------------------------------------------------------- /ChessPieces.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef CHESSPIECES_H 7 | #define CHESSPIECES_H 8 | 9 | #include 10 | 11 | class ChessPieces 12 | { 13 | public: 14 | ChessPieces(); 15 | ~ChessPieces(); 16 | 17 | void init(int id); //初始化 18 | QString getnName(bool isRedSide); //棋子对应的汉字 19 | QString getColText(int col); 20 | QString getRowText(int rowTo); 21 | QString getMoveText(int rowFrom, int rowTo); 22 | 23 | enum m_emTYPE{JIANG, SHI, XIANG, MA, CHE, PAO, BING}; 24 | 25 | int m_nRow; // 行 26 | int m_nCol; // 列 27 | int m_nID; // ID号 28 | bool m_bDead; // 死亡状态 29 | bool m_bRed; // 是否是红方 30 | m_emTYPE m_emType; // 具体哪一个棋子 31 | 32 | QString colTextRed[9]={"九", "八", "七", "六", "五", "四", "三", "二", "一"}; 33 | QString colTextBlack[9]={"1", "2", "3", "4", "5", "6", "7", "8", "9"}; 34 | QString colTextRedTurn[9]={"一", "二", "三", "四", "五", "六", "七", "八", "九"}; 35 | }; 36 | 37 | #endif // CHESSPIECES_H 38 | -------------------------------------------------------------------------------- /ChessStep.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "ChessStep.h" 7 | 8 | ChessStep::ChessStep(QObject *parent) : QObject(parent) 9 | { 10 | } 11 | 12 | ChessStep::~ChessStep() 13 | { 14 | } 15 | 16 | -------------------------------------------------------------------------------- /ChessStep.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef CHESSSTEP_H 7 | #define CHESSSTEP_H 8 | 9 | #include 10 | 11 | class ChessStep : public QObject 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit ChessStep(QObject *parent = 0); 16 | ~ChessStep(); 17 | 18 | int m_nMoveID; // 移动棋子ID 19 | int m_nKillID; // 将要被击杀的棋子ID 20 | int m_nRowFrom; // 原位置的行 21 | int m_nColFrom; // 原位置的列 22 | int m_nRowTo; // 目的位置的行 23 | int m_nnColTo; // 目的位置的列 24 | }; 25 | 26 | #endif // CHESSSTEP_H 27 | -------------------------------------------------------------------------------- /ChessVoice.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "ChessVoice.h" 7 | 8 | ChessVoice::ChessVoice(QObject *parent) : QObject(parent) 9 | { 10 | 11 | } 12 | ChessVoice:: ~ChessVoice() 13 | { 14 | 15 | } 16 | 17 | void ChessVoice:: voiceWin() 18 | { 19 | if(m_win!= nullptr) 20 | this->m_win->play(); 21 | } 22 | 23 | void ChessVoice::voiceSelect() 24 | { 25 | if(m_select!= nullptr) 26 | this->m_select->play(); 27 | } 28 | 29 | void ChessVoice:: voiceMove() 30 | { 31 | if(m_move!= nullptr) 32 | this->m_move->play(); 33 | } 34 | 35 | void ChessVoice:: voiceEat() 36 | { 37 | if(m_eat!= nullptr) 38 | this->m_eat->play(); 39 | } 40 | 41 | void ChessVoice:: voiceBack() 42 | { 43 | if(m_back!= nullptr) 44 | this->m_back->play(); 45 | } 46 | 47 | void ChessVoice:: voiceGeneral() 48 | { 49 | if(m_general!= nullptr) 50 | this->m_general->play(); 51 | } 52 | -------------------------------------------------------------------------------- /ChessVoice.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef CHESSVOICE_H 7 | #define CHESSVOICE_H 8 | 9 | #include 10 | #include 11 | 12 | class ChessVoice : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit ChessVoice(QObject *parent = nullptr); 17 | ~ChessVoice(); 18 | 19 | QSound *m_win =new QSound(":/sound/WinSound.wav",this); 20 | QSound *m_select =new QSound(":/sound/selectChess.wav",this); 21 | QSound *m_move =new QSound(":/sound/moveChess.wav",this); 22 | QSound *m_eat =new QSound(":/sound/eatChess.wav",this); 23 | QSound *m_back =new QSound(":/sound/backChess.wav",this); 24 | QSound *m_general =new QSound(":/sound/generalSound.wav",this); 25 | 26 | void voiceWin(); // 胜利音效 27 | void voiceSelect(); // 选棋音效 28 | void voiceMove(); // 移动音效 29 | void voiceEat(); // 吃子音效 30 | void voiceBack(); // 悔棋音效 31 | void voiceGeneral(); // 将军音效 32 | 33 | }; 34 | 35 | #endif // CHESSVOICE_H 36 | -------------------------------------------------------------------------------- /ChineseChess.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # Project created by QtCreator 2019-01-22T19:52:58 3 | # 4 | # 关于作者: 5 | # 与子偕臧 xmulitech@gmail.com 6 | # 项目完成时间:2019-02-01 7 | # 其他:如果觉得该作品对你有用,或者有疑惑或者感谢,可以联系作者或者打赏; 8 | # 对我的 star 和 fork 是最大鼓励;当然有人欢迎你提交在 github 提交 pr, 9 | # 已将源码和思路开源公布于我的github和博客,供大家学习参考 10 | # 11 | # 联系作者: 12 | # GitHub: https://github.com/XMuli 13 | # Telegram: https://t.me/xmuli 14 | # CSDN Bolg: https://blog.csdn.net/qq_33154343 15 | # My Blog: https://ifmet.cn 16 | #------------------------------------------------- 17 | 18 | QT += core gui network multimedia 19 | 20 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 21 | 22 | TARGET = ChineseChess 23 | TEMPLATE = app 24 | 25 | 26 | SOURCES += main.cpp\ 27 | ChessBoard.cpp \ 28 | ChessPieces.cpp \ 29 | ChessStep.cpp \ 30 | ChessVoice.cpp \ 31 | MachineGame.cpp \ 32 | NetworkGame.cpp \ 33 | ChooseMainWindow.cpp \ 34 | AboutAuthor.cpp 35 | 36 | HEADERS += ChessBoard.h \ 37 | ChessPieces.h \ 38 | ChessStep.h \ 39 | ChessVoice.h \ 40 | MachineGame.h \ 41 | NetworkGame.h \ 42 | ChooseMainWindow.h \ 43 | AboutAuthor.h 44 | 45 | FORMS += ChessBoard.ui \ 46 | AboutAuthor.ui 47 | 48 | RESOURCES += \ 49 | chooseresource.qrc 50 | 51 | RC_FILE = res.rc 52 | 53 | -------------------------------------------------------------------------------- /ChooseMainWindow.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "ChooseMainWindow.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | ChooseMainWindow::ChooseMainWindow(QWidget *parent) : QDialog(parent) 15 | { 16 | this->setWindowTitle(QString("选择游戏方式 %1").arg(XPROJECT_VERSION)); 17 | this->setFixedSize(360, 160); 18 | this->setWindowIcon(QIcon(":/images/chess.svg")); 19 | 20 | QVBoxLayout* lay = new QVBoxLayout(this); 21 | lay->addWidget(m_buttons[0] = new QPushButton("玩家自己对战")); 22 | lay->addWidget(m_buttons[1] = new QPushButton("玩家和AI对战")); 23 | lay->addWidget(m_buttons[2] = new QPushButton("双人网络对战")); 24 | 25 | /*游戏方式一: 自己和自己下棋【同一台PC机器】*/ 26 | connect(m_buttons[0], &QPushButton::clicked,[=](){ 27 | this->hide(); 28 | m_pAgainstYourself = new ChessBoard(); 29 | m_pAgainstYourself->showNetworkGui(false); 30 | m_pAgainstYourself->setWindowTitle(QString("玩家自己对战 %1").arg(XPROJECT_VERSION)); 31 | m_pAgainstYourself->show(); 32 | 33 | //返回主窗口 34 | connect(m_pAgainstYourself,&ChessBoard::toMenu,[=](){ 35 | m_pAgainstYourself->close(); 36 | this->show(); 37 | }); 38 | }); 39 | 40 | /*游戏方式二: 自己和电脑下棋【同一台PC机器】*/ 41 | connect(m_buttons[1], &QPushButton::clicked,[=](){ 42 | this->hide(); 43 | 44 | m_pMachineGame = new MachineGame(); 45 | m_pMachineGame->showNetworkGui(false); 46 | m_pMachineGame->setWindowTitle(QString("玩家和AI对战 %1").arg(XPROJECT_VERSION)); 47 | m_pMachineGame->show(); 48 | 49 | //返回主窗口 50 | connect(m_pMachineGame,&ChessBoard::toMenu,[=](){ 51 | m_pMachineGame->close(); 52 | this->show(); 53 | }); 54 | }); 55 | 56 | /*游戏方式三: 双人网络对战下棋【可在局域网/广域网的不同台PC机器】 57 | - 一台实体主机: 一台主机,一台虚拟机,网络桥接模式 58 | - 两台实体主机: 同一局域网,或者都具有公网IP的广域网*/ 59 | connect(m_buttons[2], &QPushButton::clicked,[=](){ 60 | this->hide(); 61 | QMessageBox::StandardButtons ret = QMessageBox::question( 62 | this, 63 | "提示", 64 | "是否作为[服务器]启动?
" 65 | "- Yes: 服务器, 属红方
" 66 | "- No: 客户端, 属黑方

" 67 | "📢: 📖 Wiki", 68 | QMessageBox::Yes | QMessageBox::No 69 | ); 70 | 71 | const bool& bServer = ret == QMessageBox::Yes ? true : false; 72 | 73 | m_pNetworkGame = new NetworkGame(bServer); 74 | m_pNetworkGame->showNetworkGui(true); 75 | const QString& title = QString("双人网络对战 [%1] [%2]").arg(bServer ? "服务器 - 红方" : "客户端 - 黑方").arg(XPROJECT_VERSION) ; 76 | m_pNetworkGame->setWindowTitle(title); 77 | m_pNetworkGame->show(); 78 | 79 | //返回主窗口 80 | connect(m_pNetworkGame,&ChessBoard::toMenu,[=](){ 81 | m_pNetworkGame->close(); 82 | this->show(); 83 | }); 84 | }); 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /ChooseMainWindow.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef CHOOSEMAINWINDOW_H 7 | #define CHOOSEMAINWINDOW_H 8 | 9 | #include 10 | #include "ChessBoard.h" 11 | #include "MachineGame.h" 12 | #include "NetworkGame.h" 13 | #include "ChessBoard.h" 14 | 15 | class ChooseMainWindow : public QDialog 16 | { 17 | Q_OBJECT 18 | public: 19 | explicit ChooseMainWindow(QWidget *parent = nullptr); 20 | virtual ~ChooseMainWindow() = default; 21 | 22 | private: 23 | QPushButton* m_buttons[3]; 24 | ChessBoard* m_pAgainstYourself; 25 | MachineGame* m_pMachineGame; 26 | NetworkGame* m_pNetworkGame; 27 | }; 28 | 29 | #endif // CHOOSEMAINWINDOW_H 30 | -------------------------------------------------------------------------------- /MachineGame.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "MachineGame.h" 7 | 8 | MachineGame::MachineGame() 9 | { 10 | } 11 | 12 | MachineGame::~MachineGame() 13 | { 14 | } 15 | 16 | //辅助函: 选棋或移动棋子 17 | void MachineGame::chooseOrMovePieces(int tempID, int& row, int& col) 18 | { 19 | if(m_nSelectID == -1) //选择棋子 20 | { 21 | if(m_nCheckedID != -1) 22 | { 23 | if(m_ChessPieces[m_nCheckedID].m_bRed) 24 | { 25 | m_nSelectID = tempID; 26 | } 27 | else 28 | { 29 | m_nSelectID = -1; 30 | return; 31 | } 32 | } 33 | } 34 | else 35 | { 36 | if(canMove(m_nSelectID, m_nCheckedID, row, col )) 37 | { 38 | //_selectId为第一次点击选中的棋子, 39 | //_clickId为第二次点击||被杀的棋子ID,准备选中棋子下子的地方 40 | m_ChessPieces[m_nSelectID].m_nRow = row; 41 | m_ChessPieces[m_nSelectID].m_nCol = col; 42 | if(m_nCheckedID != -1) 43 | m_ChessPieces[m_nCheckedID].m_bDead = true; 44 | 45 | m_nSelectID = -1; 46 | m_bIsRed = !m_bIsRed; 47 | } 48 | } 49 | 50 | whoWin(); 51 | update(); 52 | } 53 | 54 | void MachineGame::saveStep(int selectID, int checkedID, int row, int col, QVector &steps) 55 | { 56 | ChessStep* step = new ChessStep; 57 | step->m_nRowFrom = m_ChessPieces[selectID].m_nRow; 58 | step->m_nColFrom = m_ChessPieces[selectID].m_nCol; 59 | step->m_nRowTo = row; 60 | step->m_nnColTo = col; 61 | step->m_nMoveID = selectID; 62 | step->m_nKillID = checkedID; 63 | 64 | steps.append(step); 65 | } 66 | 67 | void MachineGame::getAllPossibleMoveStep(QVector &steps) 68 | { 69 | for(int id = 0; id<16; id++) //存在的黑棋, 能否走到这些盘棋盘里面的格子 70 | { 71 | if(m_ChessPieces[id].m_bDead) 72 | continue; 73 | 74 | for(int row=0; row<10; row++) 75 | { 76 | for(int col=0; col<9; col++) 77 | { 78 | int i = 16; 79 | for( ; i <= 31; i++) 80 | { 81 | if(m_ChessPieces[i].m_nRow == row && m_ChessPieces[i].m_nCol == col && m_ChessPieces[i].m_bDead == false) 82 | break; 83 | } 84 | 85 | if(i!=32) 86 | { 87 | if(canMove(id, i, row, col)) 88 | saveStep(id, i, row, col, steps); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | 95 | void MachineGame::getAllPossibleMoveStepAndNoKill(QVector &steps) 96 | { 97 | for(int id = 0; id<16; id++) //存在的黑棋, 能否走到这些盘棋盘里面的格子 98 | { 99 | if(m_ChessPieces[id].m_bDead) 100 | continue; 101 | 102 | for(int row=0; row<10; row++) 103 | { 104 | for(int col=0; col<9; col++) 105 | { 106 | 107 | int i = 0; 108 | for(; i <= 31; i++) 109 | { 110 | if(m_ChessPieces[i].m_nRow == row && m_ChessPieces[i].m_nCol == col && m_ChessPieces[i].m_bDead == false) 111 | break; 112 | } 113 | 114 | if(id < 16 && i == 32) 115 | { 116 | if(canMove(id, -1, row, col)) 117 | saveStep(id, -1, row, col, steps); 118 | } 119 | } 120 | } 121 | } 122 | } 123 | 124 | void MachineGame::mousePressEvent(QMouseEvent *ev) 125 | { 126 | if(ev->button() != Qt::LeftButton) 127 | return; 128 | 129 | int row, col; 130 | if(!isChecked(ev->pos(), row, col)) 131 | return; 132 | 133 | m_nCheckedID = -1; 134 | 135 | //TODO Fix (升级 Qt6): https://github.com/XMuli/chinessChess/issues/23 136 | int i =0; 137 | for( ; i < 32; i++) 138 | { 139 | if(m_ChessPieces[i].m_nRow == row && m_ChessPieces[i].m_nCol == col && m_ChessPieces[i].m_bDead == false) 140 | break; 141 | } 142 | 143 | if(0<=i && i<32) 144 | m_nCheckedID = i; 145 | 146 | clickPieces(m_nCheckedID, row, col); 147 | 148 | if(m_bIsRed) //红方玩家时间 149 | { 150 | chooseOrMovePieces(i, row, col); 151 | 152 | if(!m_bIsRed) //黑方紧接着进行游戏 153 | { 154 | machineChooseAndMovePieces(); 155 | //ToDo: 机器 黑方时间 156 | } 157 | } 158 | 159 | 160 | 161 | } 162 | 163 | void MachineGame::clickPieces(int checkedID, int &row, int &col) 164 | { 165 | if(m_bIsRed) //红方玩家时间 166 | { 167 | chooseOrMovePieces(checkedID, row, col); 168 | 169 | if(!m_bIsRed) //黑方紧接着进行游戏 170 | machineChooseAndMovePieces(); 171 | //ToDo: 机器 黑方时间 172 | } 173 | } 174 | 175 | //假装移动棋子 176 | void MachineGame::fakeMove(ChessStep *step) 177 | { 178 | if(step->m_nKillID != -1) 179 | m_ChessPieces[step->m_nKillID].m_bDead = true; 180 | 181 | m_ChessPieces[step->m_nMoveID].m_nRow = step->m_nRowTo; 182 | m_ChessPieces[step->m_nMoveID].m_nCol = step->m_nnColTo; 183 | m_bIsRed = !m_bIsRed; 184 | } 185 | 186 | //撤回先前假装移动棋子的步骤 187 | void MachineGame::unFakeMove(ChessStep *step) 188 | { 189 | if(step->m_nKillID != -1) 190 | m_ChessPieces[step->m_nKillID].m_bDead = false; 191 | 192 | m_ChessPieces[step->m_nMoveID].m_nRow = step->m_nRowFrom; 193 | m_ChessPieces[step->m_nMoveID].m_nCol = step->m_nColFrom; 194 | m_bIsRed = !m_bIsRed; 195 | } 196 | 197 | //计算最好的局面分 198 | int MachineGame::calcScore() 199 | { 200 | //enum m_emTYPE{JIANG, SHI, XIANG, MA, CHE, PAO, BING}; 201 | //黑棋分数 - 红旗分数 202 | int redGrossScore = 0; 203 | int blackGrossScore = 0; 204 | 205 | static int chessScore[]={200, 20, 40, 60, 100, 80, 10}; 206 | 207 | for(int i=0; i<16; i++) 208 | { 209 | if(m_ChessPieces[i].m_bDead) 210 | continue; 211 | blackGrossScore += chessScore[m_ChessPieces[i].m_emType]; 212 | } 213 | 214 | for(int i=16; i<32; i++) 215 | { 216 | if(m_ChessPieces[i].m_bDead) 217 | continue; 218 | redGrossScore += chessScore[m_ChessPieces[i].m_emType]; 219 | } 220 | 221 | return (blackGrossScore - redGrossScore); 222 | } 223 | 224 | 225 | //获得最好的移动步骤 226 | //第一此玩了一把,发现我居然下不赢自己写的算法。哭了哭了哭了555555........ 227 | ChessStep* MachineGame::getBestMove() 228 | { 229 | int maxScore = -10000; 230 | ChessStep* retStep = NULL; 231 | 232 | //------------------------ 233 | //有可击杀的红棋子就走击杀红棋子最优的一步 234 | // 1.看看有那些步骤可以走 235 | QVector steps; 236 | getAllPossibleMoveStep(steps); // 黑棋吃红棋的所有可能的步骤 237 | 238 | //------------------------ 239 | //没有可击杀的红棋子就走最后的一步 240 | QVector stepsAndNoKill; 241 | getAllPossibleMoveStepAndNoKill(stepsAndNoKill); // 黑棋移动所有可能的步骤(不吃红棋子) 242 | 243 | //2.试着走一下 244 | for(QVector::iterator it = steps.begin(); it!=steps.end(); it++) 245 | { 246 | ChessStep* step = *it; 247 | fakeMove(step); 248 | int score = calcScore(); //3.计算最好的局面分 249 | unFakeMove(step); 250 | 251 | if(score > maxScore) 252 | { 253 | maxScore = score; 254 | retStep = step; 255 | } 256 | } 257 | 258 | if(retStep != NULL) 259 | return retStep; 260 | 261 | //2.试着走一下 262 | //从这种不击杀红棋子,只是单纯移动黑棋steps里面,随机抽选一种进行下棋 263 | int nStepsCount = stepsAndNoKill.count(); 264 | qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); //随机数种子, 0~MAX 265 | int temp =qrand()% nStepsCount; 266 | QVector::iterator it = stepsAndNoKill.begin(); 267 | retStep = it[temp]; 268 | 269 | if(retStep == NULL) 270 | whoWin(); 271 | 272 | //4.取最好的结果作为参考 273 | return retStep; 274 | } 275 | 276 | void MachineGame::machineChooseAndMovePieces() 277 | { 278 | ChessStep* step = getBestMove(); 279 | 280 | if(step->m_nKillID == -1) //黑棋没有可以击杀的红棋子,只好走能够走的过程中最后一步棋 281 | { 282 | m_ChessPieces[step->m_nMoveID].m_nRow = step->m_nRowTo; 283 | m_ChessPieces[step->m_nMoveID].m_nCol = step->m_nnColTo; 284 | 285 | } 286 | else //黑棋有可以击杀的红棋子,故击杀红棋子 287 | { 288 | m_ChessPieces[step->m_nKillID].m_bDead = true; 289 | m_ChessPieces[step->m_nMoveID].m_nRow = m_ChessPieces[step->m_nKillID].m_nRow; 290 | m_ChessPieces[step->m_nMoveID].m_nCol = m_ChessPieces[step->m_nKillID].m_nCol; 291 | m_nSelectID = -1; 292 | } 293 | 294 | m_bIsRed = !m_bIsRed; 295 | } 296 | -------------------------------------------------------------------------------- /MachineGame.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef MACHINEGAME_H 7 | #define MACHINEGAME_H 8 | 9 | #include "ChessBoard.h" 10 | #include "ChessStep.h" 11 | #include 12 | 13 | class MachineGame : public ChessBoard 14 | { 15 | public: 16 | MachineGame(); 17 | ~MachineGame(); 18 | 19 | void chooseOrMovePieces(int tempID, int& row, int& col); // 辅助函: 选棋或移动棋子 20 | void saveStep(int moveID, int checkedID, int row, int col, QVector& steps); // 保存棋子步骤 21 | void getAllPossibleMoveStep(QVector& steps); // 获得所有可能的移动步骤(击杀) 22 | void getAllPossibleMoveStepAndNoKill(QVector& steps); // 获得所有可能的移动步骤(不击杀) 23 | 24 | virtual void mousePressEvent(QMouseEvent *); // 鼠标点击事件 25 | void clickPieces(int checkedID, int& row, int& col); 26 | 27 | void fakeMove(ChessStep* step); // 假装移动棋子 28 | void unFakeMove(ChessStep* step); // 撤回先前假装移动棋子的步骤 29 | int calcScore(); // 计算最好的局面分 30 | ChessStep* getBestMove(); // 获得最好的移动步骤 31 | void machineChooseAndMovePieces(); // 机器 黑方时间: 进行选棋+下棋 32 | }; 33 | 34 | #endif // MACHINEGAME_H 35 | -------------------------------------------------------------------------------- /NetworkGame.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include "NetworkGame.h" 7 | #include 8 | #include "ui_ChessBoard.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | NetworkGame::NetworkGame(bool isServer) 15 | { 16 | m_bIsTcpServer = isServer; 17 | m_tcpServer = NULL; 18 | m_tcpSocket = NULL; 19 | 20 | QNetworkProxyFactory::setUseSystemConfiguration(false); 21 | 22 | initUI(); 23 | 24 | if(m_bIsTcpServer) //作为服务器端 25 | { 26 | m_tcpServer = new QTcpServer(this); 27 | onBtnTryConnect(); 28 | connect(m_tcpServer, SIGNAL(newConnection()),this, SLOT(slotNewConnection())); 29 | } 30 | else //作为客户端 31 | { 32 | m_tcpSocket = new QTcpSocket(this); 33 | connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(slotRecv())); 34 | } 35 | 36 | connect(ChessBoard::ui->btnTcpConnect, &QPushButton::released, this, &NetworkGame::onBtnTryConnect); 37 | } 38 | 39 | void NetworkGame::initUI() 40 | { 41 | auto& ui = ChessBoard::ui; 42 | QString ip = ui->leIp->text(); 43 | QString port = ui->sbPort->text(); 44 | 45 | if(m_bIsTcpServer) { //作为服务器端 46 | QList interfaces = QNetworkInterface::allInterfaces(); 47 | 48 | // 遍历每个接口 49 | foreach (QNetworkInterface interface, interfaces) { 50 | // 如果接口处于活动状态且不是回环接口 51 | if (interface.isValid() && interface.flags().testFlag(QNetworkInterface::IsUp) && !interface.flags().testFlag(QNetworkInterface::IsLoopBack)) { 52 | foreach (QNetworkAddressEntry entry, interface.addressEntries()) { 53 | // 输出IPv4地址 54 | if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) { 55 | ip = entry.ip().toString(); 56 | qDebug() << "Interface:" << interface.humanReadableName() << "IPv4 Address:" << entry.ip().toString(); 57 | break; 58 | } 59 | } 60 | } 61 | } 62 | 63 | ui->networkGroup->setTitle("服务器-红方的IP和Port"); 64 | ui->btnTcpConnect->setText("监听"); 65 | ui->leIp->setText(ip); 66 | ui->sbPort->setValue(port.toLong()); 67 | ui->leIp->setReadOnly(true); 68 | ui->leIp->setDisabled(true); 69 | // ui->lePort->setReadOnly(true); 70 | } else { 71 | ui->networkGroup->setTitle("请输入[服务器]的IP和Port"); 72 | ui->btnTcpConnect->setText("连接"); 73 | ui->btnTcpConnect->show(); 74 | ui->leIp->setText(ip); 75 | ui->sbPort->setValue(port.toLong()); 76 | } 77 | } 78 | 79 | void NetworkGame::clickPieces(int checkedID, int &row, int &col) 80 | { 81 | //不能够替对方选棋和下棋 82 | if(m_bIsTcpServer) //作为服务器一方 不能替黑棋下棋 83 | { 84 | //选棋[非下棋]这一步过程,使得其无法选择中黑棋 85 | if(m_nSelectID == -1 && m_nCheckedID != -1 ) 86 | { 87 | if(m_bIsTcpServer != m_ChessPieces[checkedID].m_bRed ) 88 | return ; 89 | } 90 | } 91 | else //作为客户端一方 不能替红棋下棋 92 | { 93 | //选棋[非下棋]这一步过程,使得其无法选择中红棋 94 | if(m_nSelectID == -1 && m_nCheckedID != -1) 95 | { 96 | if(m_bIsTcpServer != m_ChessPieces[checkedID].m_bRed ) 97 | return ; 98 | } 99 | } 100 | 101 | whoWin(); 102 | 103 | ChessBoard::clickPieces(checkedID, row, col); 104 | char arry[3]; 105 | arry[0] = checkedID; 106 | arry[1] = row; 107 | arry[2] = col; 108 | 109 | if(m_tcpSocket) 110 | m_tcpSocket->write(arry, 3); 111 | } 112 | 113 | void NetworkGame::slotNewConnection() 114 | { 115 | if(m_tcpSocket) return; 116 | 117 | static std::once_flag flag; 118 | std::call_once(flag, [&]() { 119 | QString text = QString("Client Connection Successful"); 120 | ui->labConnectStatus->setText(text); 121 | }); 122 | 123 | 124 | if (m_tcpServer) { 125 | m_tcpSocket = m_tcpServer->nextPendingConnection(); 126 | connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(slotRecv())); 127 | } 128 | } 129 | 130 | void NetworkGame::slotRecv() 131 | { 132 | QByteArray arry = m_tcpSocket->readAll(); 133 | 134 | int nCheckedID = arry[0]; 135 | int nRow = arry[1]; 136 | int nCol = arry[2]; 137 | 138 | //qDebug()<leIp->text().isEmpty() || ui->sbPort->text().isEmpty()) { 147 | text = "IP或Port为空,请设置后重试"; 148 | qDebug() << text; 149 | ui->labConnectStatus->setText(text); 150 | return; 151 | } 152 | 153 | if(m_bIsTcpServer) { // 服务器-重设端口号 154 | if (!m_tcpServer) return; 155 | if (m_tcpServer->isListening()) { 156 | qDebug() << "Stopping server..."; 157 | m_tcpServer->close(); 158 | } 159 | 160 | // 监听指定地址和端口 161 | if (m_tcpServer->listen(QHostAddress::Any, ui->sbPort->text().toLong())) { 162 | text = QString("Server is listening on \"%1\" port \"%2\"").arg(m_tcpServer->serverAddress().toString()).arg(m_tcpServer->serverPort()); 163 | } else { 164 | text = QString("Server failed to start: %1").arg(m_tcpServer->errorString()); 165 | } 166 | 167 | } else { // 客户端-输入IP+Port尝试连接服务器 168 | if (!m_tcpSocket) return; 169 | const QString& ip = ui->leIp->text(); 170 | const QString& port = ui->sbPort->text(); 171 | m_tcpSocket->connectToHost(QHostAddress(ip), port.toInt()); 172 | // 等待连接成功或失败 173 | if (m_tcpSocket->waitForConnected()) { 174 | text = "Server Connection Successful: " + ip + ":" + port; 175 | } else { 176 | text = "Server connection failed: " + m_tcpSocket->errorString(); 177 | } 178 | } 179 | 180 | qDebug() << text; 181 | ui->labConnectStatus->setText(text); 182 | 183 | } 184 | -------------------------------------------------------------------------------- /NetworkGame.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #ifndef NETWORKGAME_H 7 | #define NETWORKGAME_H 8 | 9 | #include "ChessBoard.h" 10 | #include 11 | #include 12 | 13 | //定义协议: 14 | //第一个字节:表示点击的棋子ID;第二个字节:表示点击的行row,第三个字节:表示点击的列col 15 | 16 | class NetworkGame : public ChessBoard 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | NetworkGame(bool isServer); 22 | ~NetworkGame() = default; 23 | void initUI(); 24 | void clickPieces(int checkedID, int& row, int& col) override; 25 | 26 | public slots: 27 | void slotNewConnection(); 28 | void slotRecv(); 29 | void onBtnTryConnect(); 30 | 31 | private: 32 | QTcpServer* m_tcpServer; 33 | QTcpSocket* m_tcpSocket; 34 | }; 35 | 36 | #endif // NETWORKGAME_H 37 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # This is an example PKGBUILD file. Use this as a start to creating your own, 2 | # and remove these comments. For more information, see 'man PKGBUILD'. 3 | # NOTE: Please fill out the license field for your package! If it is unknown, 4 | # then please put 'unknown'. 5 | 6 | # Maintainer: xmuli # 包的维护者 7 | pkgname=chinesschess # 包的名称(由小写字母 @ . _ + - 构成) 8 | _pkgname=chinessChess # 自己添加的变量 (因 pkgname 要求全小写,而仓库源码中有大写) 9 | _pkgname2=ChineseChess # 自己添加的变量 (最后项目生成的文件名) 10 | pkgver=5.6.0 # 包的版本号 (不可有连字符 -) 11 | pkgrel=1 # 包的发布号码 12 | epoch= # 用于强制升级软件包 (一般不允许使用) 13 | pkgdesc="Network battle game written in Qt (available on LAN)" # 软件包的详细描述 14 | arch=('x86_64') # 包所能够生成并且使用的架构的序列 15 | url="https://github.com/XMuli/chinessChess" # 包的官网 16 | license=('GPL3') # 采用的许可证 17 | groups=() # 软件包所在的包组 18 | depends=() # 软件包的生成和运行时,必须先行安装的软件列表 19 | makedepends=() # 仅在软件生成时,需要的软件包列表 20 | checkdepends=() # 运行测试组件时需要,而运行时不需要的包列表 21 | optdepends=() # 可选的软件包(可看作本软件的插件) 22 | provides=() # 说明当前包提供的功能 (若使用,则需加上替代版本号) 23 | conflicts=() # 与当前软件包发生冲突的包 与功能的列表 24 | replaces=() # 会因安装当前包而取代的过时的包的列表 25 | backup=() # 当包被升级或卸载时,应当备份的文件(的路径)序列 26 | options=() # 允许重载 makepkg 的部分 (在 /etc/makepkg.conf 中) 27 | install= # .install 脚本的名称 (值应和 pkgname 相同) 28 | changelog= # 软件包的更新日志的文件名 29 | source=("$_pkgname-$pkgver::https://github.com/XMuli/$_pkgname/archive/v$pkgver.tar.gz") # 源码的下载地址 30 | noextract=() # 在 source 中列出,但不应该在运行 makepkg 时被解包的文件列表 31 | md5sums=('5abae73968ea0104e99b816bf0b720fe') # 完整性校验值 32 | validpgpkeys=() # PGP 指纹列表 33 | 34 | 35 | prepare() { # 准备 36 | cd $srcdir 37 | echo $srcdir 38 | } 39 | 40 | build() { # 构建 41 | cd $_pkgname-$pkgver 42 | mkdir bin 43 | cd bin 44 | qmake .. 45 | make -j$(nproc) 46 | } 47 | 48 | check() { # 检查 49 | cd $_pkgname-$pkgver 50 | } 51 | 52 | package() { # 包 53 | cd $_pkgname-$pkgver 54 | # make install 55 | cd bin/ 56 | ./$_pkgname2 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChineseChess 2 | 3 |
4 | 5 |
6 | 7 | 8 |
9 | 10 | ## Introduction 11 | 12 |


English | 简体中文

13 | 14 | ![](https://img.shields.io/github/license/XMuli/chineseChess) ![](https://img.shields.io/github/v/release/XMuli/ChineseChess?style=flat&color=birightgreen)![](https://img.shields.io/badge/powered%20by-XMuli-ff69b4)![](https://img.shields.io/github/stars/XMuli/ChineseChess?style=social) ![](https://img.shields.io/github/forks/XMuli/ChineseChess?style=social&label=Fork) 15 | 16 | [![macos-badge](https://github.com/xmuli/ChineseChess/workflows/MacOS/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/MacOS/badge.svg) [![win-badge](https://github.com/xmuli/ChineseChess/workflows/Windows/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/Windows/badge.svg) [![ubuntu-badge](https://github.com/xmuli/ChineseChess/workflows/Ubuntu/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/Ubuntu/badge.svg) ![](https://img.shields.io/github/languages/code-size/XMuli/ChineseChess) ![](https://img.shields.io/github/downloads/XMuli/ChineseChess/total) 17 | 18 | 19 | > The Chinese chess online battle platform (including communication function) developed based on `Qt5` realizes the function of chess game in a single or networked state, no matter whether it is single or multiple players, regardless of whether the system is the same. 20 | 21 |
22 | 23 | 24 | 25 | ## characteristic 26 | 27 | **The main functional modules of the project are divided into:** 28 | 29 | ⅰ Players play against themselves 30 | 31 | ⅱ Play against the computer AI 32 | 33 | ⅲ Multiplayer network battle (can cross different systems) 34 | 35 | ⅳ Battle timing 36 | 37 | ⅴ Repent (multiple moves possible) 38 | 39 | ⅵ track of chess moves 40 | 41 | ⅵ About the work information 42 | 43 |
44 | 45 | # Run the demo 46 | 47 | **Video presentation:** 48 | [ChineseChess QT-based cross-platform online chess game demonstration](https://www.bilibili.com/video/av45509758) 49 | 50 |
51 | 52 | **Win10 running example:** 53 | 54 | 55 | 56 |
57 | 58 | **Linux running example:** 59 | 60 | 61 | 62 |
63 | 64 | **MacOS running example:** 65 | 66 | 67 | 68 |
69 | 70 | **Examples of cross-platform battles:** **MacOS 10.14 vs Win10** 71 | 72 | 73 | 74 |
75 | 76 | **About the program:**  77 | 78 | 79 | 80 |
81 | 82 | ## Update (2022-2024 v6.x) 83 | 84 | ### Features 85 | 86 | - Add regret function, unlimited regret 87 | - Show move track, current move 88 | - Restart game, click to restart 89 | - Code logic optimization, new comments 90 | - Update chess interface, use ancient chess characters 91 | - Update about program, add contributor name 92 | - Linux ARM Raspberry Pi support: [apt.raspbian-addons.org](https://apt.raspbian-addons.org/debian/pool/main/c/chinesechess/), both 32 and 64-bit 93 | 94 |
95 | 96 | ### Show 97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 | ## Development tutorial 105 | 106 | - [Project actual combat: Qt5/C++: QT chess [Basic version]](https://blog.csdn.net/qq_33154343/article/details/80931400) 107 | 108 | - [QT5/C++ project: QT-based cross-platform online battle chess (1)](https://blog.csdn.net/qq_33154343/article/details/89284983) 109 | 110 | - [QT5/C++ project: QT-based cross-platform online battle chess (2)](https://blog.csdn.net/qq_33154343/article/details/89285968) 111 | 112 | - [QT5/C++ project: QT-based cross-platform online battle chess (3)](https://blog.csdn.net/qq_33154343/article/details/89286553) 113 | 114 |
115 | 116 | In addition, the source code summary is accompanied by detailed code comments for easy understanding. 117 | 118 |
119 | 120 | ## Build 121 | 122 | 1. Install Qt (Qt >= 5.12.11)and other dependencies 123 | 124 | For Debian and Ubuntu, run: 125 | 126 | ```bash 127 | $ sudo apt install cmake qtbase5-dev qt5-default libqt5svg5-dev qtmultimedia5-dev qttools5-dev libqt5x11extras5-dev 128 | ``` 129 | 130 | 2. Run the command:: 131 | 132 | ```bash 133 | $ git clone https://github.com/XMuli/ChineseChess.git 134 | $ cd ChineseChess 135 | $ mkdir build && cd build 136 | $ cmake .. # or qmake 137 | $ make 138 | ``` 139 | 140 | 141 | Or you can skip the second step and use Qt Creator to compile and run. 142 | 143 |
144 | 145 | ## Contributor 146 | 147 | Thanks for the contributions submitted by the friends 🥳🥳: 148 | 149 |
150 | 151 | 152 | 153 | 159 | 165 | 171 | 177 | 182 | 188 | 199 | 200 |
154 | 155 |
156 | XMuli 157 |
158 |
160 | 161 |
162 | Bruce-Ch 163 |
164 |
166 | 167 |
168 | BlueArvin 169 |
170 |
172 | 173 |
174 | Ubuntuser2012 175 |
176 |
178 | 179 |
180 | kirayamatoo 181 |
183 | 184 |
185 | hmsjy2017 186 |
187 |
189 | 190 |
191 | ryanfortner 192 |
193 |
194 | 195 |
196 | zjuyk 197 |
198 |
201 | 202 | 203 | 204 | 205 | 206 | If it helps you, or find it useful, you can click on the item's **⭐Star** **🍴 Fork**  of the two icons, conveniently lift the hand between, said a point of praise the hand, There is a fragrance in your hand;The next best thing is to buy me a cold Coke. 207 | 208 |
209 | 210 | ## Author 211 | 212 | [![alt text](https://img.shields.io/badge/QQ-%E5%81%95%E8%87%A7-brightgreen)](https://sighttp.qq.com/authd?IDKEY=31f3ef7312b39e2c8dc822ae2f4c3b3118e1a6f31cc83373) [![alt text](https://img.shields.io/badge/GitHub-XMuli-brightgreen)](https://github.com/XMuli) [![alt text](https://img.shields.io/badge/Blog-%E5%81%95%E8%87%A7%E7%9A%84%E5%B0%8F%E7%AB%99-ff69b4)](https://ifmet.cn/) 213 | 214 |
215 | 216 | ## Tutorial Series 217 | 218 | [QtExamples](https://github.com/XMuli/QtExamples) Welcome to `star` ⭐ and `fork` 🍴 This series of `C++ / QT / DTK` studies, where you can learn how to write this kind of software yourself, is a complete series of tutorials. And **FREE**! 219 | 220 | -------------------------------------------------------------------------------- /README.zh_CN.md: -------------------------------------------------------------------------------- 1 | # ChineseChess 2 | 3 |
4 | 5 |
6 |
7 | 8 | ## 项目介绍 9 | 10 |


English | 简体中文

11 | 12 | ![](https://img.shields.io/github/license/XMuli/chineseChess) ![](https://img.shields.io/github/v/release/XMuli/ChineseChess?style=flat&color=birightgreen)![](https://img.shields.io/badge/powered%20by-XMuli-ff69b4)![](https://img.shields.io/github/stars/XMuli/ChineseChess?style=social) ![](https://img.shields.io/github/forks/XMuli/ChineseChess?style=social&label=Fork) 13 | 14 | [![macos-badge](https://github.com/xmuli/ChineseChess/workflows/MacOS/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/MacOS/badge.svg) [![win-badge](https://github.com/xmuli/ChineseChess/workflows/Windows/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/Windows/badge.svg) [![ubuntu-badge](https://github.com/xmuli/ChineseChess/workflows/Ubuntu/badge.svg)](https://github.com/xmuli/ChineseChess/workflows/Ubuntu/badge.svg) ![](https://img.shields.io/github/languages/code-size/XMuli/ChineseChess) ![](https://img.shields.io/github/downloads/XMuli/ChineseChess/total) 15 |
16 | 17 | > 基于`Qt5`开发的中国象棋网络对战平台(含通讯功能),实现了在单机或联网状态下,无论是单人还是多人,无论使用系统是否相同,均可以实现象棋游戏功能。 18 | 19 |
20 | 21 | ## 特性 22 | 23 | **该项目主要功能模块分为:** 24 | 25 | ⅰ 玩家与自己对战 26 | 27 | ⅱ 玩家与电脑AI对战 28 | 29 | ⅲ 多人网络对战(可跨不同系统) 30 | 31 | ⅳ 对战计时 32 | 33 | ⅴ 悔棋(可多步) 34 | 35 | ⅵ 下棋轨迹 36 | 37 | ⅵ 关于作品信息 38 | 39 |
40 | 41 | # 运行演示: 42 | 43 | **视频演示:** 44 | 45 | [ChineseChess 基于QT的跨平台网络象棋对战演示](https://www.bilibili.com/video/av45509758) 46 | 47 |
48 | 49 | **win10系统演示:** 50 | 51 | 52 | 53 |
54 | 55 | **Linux系统演示:** 56 | 57 | 58 | 59 |
60 | 61 | **MacOS系统演示:** 62 | 63 | 64 | 65 |
66 | 67 | **跨平台对战演示:** **MacOS 10.14 vs Win10** 68 | 69 | 70 | 71 |
72 | 73 | **作者作品详情:**  74 | 75 | 76 | 77 |
78 | 79 | ## 更新(2022-2024 v6.x) 80 | 81 | ### 功能 82 | 83 | - 添加悔棋功能,无限制悔棋 84 | - 显示下棋轨迹,当前执手 85 | - 重新开始游戏,点击重开 86 | - 代码逻辑优化,新增注释 87 | - 下棋界面更新,使用古象棋棋字 88 | - 更新关于程序,添加贡献者姓名 89 | - Linux ARM64 deb 树莓派支持: [apt.raspbian-addons.org](https://apt.raspbian-addons.org/debian/pool/main/c/chinesechess/) 90 | 91 |
92 | 93 | ### 演示 94 | 95 | 96 | 97 | 98 | 99 |
100 | 101 | ## 开发教程 102 | 103 | - [项目实战:Qt5/C++:QT象棋【初版】](https://blog.csdn.net/qq_33154343/article/details/80931400) 104 | 105 | - [QT5/C++项目:基于QT的跨平台网络对战象棋(一)](https://blog.csdn.net/qq_33154343/article/details/89284983) 106 | 107 | - [QT5/C++项目:基于QT的跨平台网络对战象棋(二)](https://blog.csdn.net/qq_33154343/article/details/89285968) 108 | 109 | - [QT5/C++项目:基于QT的跨平台网络对战象棋(三)](https://blog.csdn.net/qq_33154343/article/details/89286553) 110 | 111 | ## 构建 112 | 113 | 1. 安装 Qt (Qt >= 5.12.11)和其他依赖 114 | 115 | 以 Debian 和 Ubuntu 为例,执行: 116 | 117 | ```bash 118 | $ sudo apt install cmake qtbase5-dev qt5-default libqt5svg5-dev qtmultimedia5-dev qttools5-dev libqt5x11extras5-dev 119 | ``` 120 | 121 | 2. 运行命令: 122 | 123 | ```bash 124 | $ git clone https://github.com/XMuli/ChineseChess.git 125 | $ cd ChineseChess 126 | $ mkdir build && cd build 127 | $ cmake .. # or qmake 128 | $ make 129 | ``` 130 | 131 | 132 | 或者,你可以跳过第 2 步,直接使用 Qt Creator 进行编译和运行。 133 | 134 |
135 | 136 | ## 贡献者 137 | 138 | 感谢的小伙伴提交的贡献 🥳🥳: 139 | 140 |
141 | 142 | 143 | 144 | 150 | 156 | 162 | 168 | 173 | 179 | 190 | 191 |
145 | 146 |
147 | XMuli 148 |
149 |
151 | 152 |
153 | Bruce-Ch 154 |
155 |
157 | 158 |
159 | BlueArvin 160 |
161 |
163 | 164 |
165 | Ubuntuser2012 166 |
167 |
169 | 170 |
171 | kirayamatoo 172 |
174 | 175 |
176 | hmsjy2017 177 |
178 |
180 | 181 |
182 | ryanfortner 183 |
184 |
185 | 186 |
187 | zjuyk 188 |
189 |
192 | 193 | 194 | 195 |
196 | 197 | 若是帮助到了你,或者觉得有用,可以点击该项目的的 **⭐Star** **🍴 Fork** 的两个图标,方便抬手之间,表示点个赞,手有余香,其次才是一份冰的肥宅快乐水。 198 | 199 |
200 | 201 | ## 作者 202 | 203 | [![alt text](https://img.shields.io/badge/QQ-%E5%81%95%E8%87%A7-brightgreen)](https://sighttp.qq.com/authd?IDKEY=31f3ef7312b39e2c8dc822ae2f4c3b3118e1a6f31cc83373) [![alt text](https://img.shields.io/badge/GitHub-XMuli-brightgreen)](https://github.com/XMuli) [![alt text](https://img.shields.io/badge/Blog-%E5%81%95%E8%87%A7%E7%9A%84%E5%B0%8F%E7%AB%99-ff69b4)](https://ifmet.cn/) 204 | 205 |
206 | 207 | ## 系列教程 208 | 209 | [QtExamples](https://github.com/XMuli/QtExamples) 欢迎 `star` ⭐ 和 `fork` 🍴 这个系列的 `C++ / QT / DTK` 学习,这里你可以学到如何亲自编写这类软件的经验,这是一系列完整的教程,并且**免费**! 210 | 211 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal enabledelayedexpansion 4 | 5 | :: Define the new path you want to prepend 6 | set new_path=C:\Qt\5.15.2\msvc2019_64\bin 7 | 8 | :: Check if the path already exists in PATH 9 | echo !PATH! | findstr /C:"%new_path%" > nul 10 | if !errorlevel! == 1 ( 11 | :: If the path doesn't exist, prepend it to PATH 12 | set "PATH=%new_path%;!PATH!" 13 | echo Updated PATH: !PATH! 14 | ) else ( 15 | echo PATH already contains %new_path% 16 | ) 17 | 18 | ::delete build dir 19 | if "%1"=="delete" goto _DEL 20 | 21 | if not exist build md build 22 | 23 | cd build 24 | cmake -G "Visual Studio 17 2022" -A x64 .. 25 | goto _END 26 | 27 | :_DEL 28 | rd build/s/q 29 | goto _END 30 | 31 | :_END -------------------------------------------------------------------------------- /chooseresource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/5abc.png 4 | images/b.jpg 5 | images/Alipay.png 6 | images/WeChat.png 7 | images/background.jpg 8 | images/win.jpg 9 | images/chess.svg 10 | sound/moveChess.wav 11 | sound/selectChess.wav 12 | sound/WinSound.wav 13 | sound/eatChess.wav 14 | sound/generalSound.wav 15 | sound/backChess.wav 16 | 17 | 18 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // SPDX-FileCopyrightText: 2019-2024 XMuli & Contributors 3 | // SPDX-GitHub: https://github.com/XMuli/ChineseChess 4 | // SPDX-Author: XMuli 5 | 6 | #include 7 | #include "ChooseMainWindow.h" 8 | 9 | /*** 10 | * 佛曰: 11 | * 写字楼里写字间,写字间里程序员; 12 | * 程序人员写程序,又拿程序换酒钱。 13 | * 酒醒只在网上坐,酒醉还来网下眠; 14 | * 酒醉酒醒日复日,网上网下年复年。 15 | * 但愿老死电脑间,不愿鞠躬老板前; 16 | * 奔驰宝马贵者趣,公交自行程序员。 17 | * 别人笑我忒疯癫,我笑自己命太贱; 18 | * 不见满街漂亮妹,哪个归得程序员? 19 | */ 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | QApplication a(argc, argv); 24 | 25 | ChooseMainWindow c; 26 | c.show(); 27 | 28 | return a.exec(); 29 | } 30 | -------------------------------------------------------------------------------- /resources/debian/changelog: -------------------------------------------------------------------------------- 1 | chinesechess (6.1-1) unstable; urgency=medium 2 | 3 | * Use CMake + GitHub action to automatically build CI/CD and generate a runnable application for the corresponding platform 4 | 5 | -- XMuli Sat, 30 Apr 2022 14:49:38 +0800 6 | 7 | 8 | picshot (0.1.2-1) unstable; urgency=medium 9 | 10 | * try build .deb on Linux(ubuntu 20.04) 11 | 12 | -- XMuli Sun, 27 Mar 2022 16:16:38 +0800 13 | -------------------------------------------------------------------------------- /resources/debian/compat: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /resources/debian/control: -------------------------------------------------------------------------------- 1 | Source: chinesechess 2 | Section: unknown 3 | Priority: optional 4 | Maintainer: XMuli 5 | Build-Depends: 6 | cmake (>= 3.13~), 7 | debhelper (>= 11), 8 | qtbase5-dev (>= 5.12.0~), 9 | qt5-default (>= 5.12.0~), 10 | libqt5svg5-dev (>= 5.12.0~), 11 | qtmultimedia5-dev (>= 5.12.0~), 12 | libqt5x11extras5-dev 13 | # qttools5-dev (>= 5.12.0~), 14 | Standards-Version: 4.4.1 15 | Homepage: https://github.com/XMuli 16 | #Vcs-Browser: https://salsa.debian.org/debian/ChineseChess 17 | #Vcs-Git: https://salsa.debian.org/debian/ChineseChess.git 18 | 19 | Package: chinesechess 20 | Architecture: any 21 | Depends: ${shlibs:Depends}, ${misc:Depends} 22 | Description: Open source cross-platform Chinese Chess 23 | Cross-platform and online battle platform game based on Qt: Chinese Chess. Also known as:『Xiangqi』『中国象棋』 24 | 25 | -------------------------------------------------------------------------------- /resources/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #export DH_VERBOSE = 1 5 | 6 | 7 | # see FEATURE AREAS in dpkg-buildflags(1) 8 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 9 | 10 | # see ENVIRONMENT in dpkg-buildflags(1) 11 | # package maintainers to append CFLAGS 12 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 13 | # package maintainers to append LDFLAGS 14 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 15 | 16 | 17 | %: 18 | dh $@ 19 | 20 | 21 | # dh_make generated override targets 22 | # This is example for Cmake (See https://bugs.debian.org/641051 ) 23 | #override_dh_auto_configure: 24 | # dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) 25 | 26 | -------------------------------------------------------------------------------- /resources/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /resources/debian_portable/ChineseChess.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | appname=`basename $0 | sed s,\.sh$,,` #获取\和.sh之间的字符串 3 | 4 | dirname=`dirname $0` 5 | tmp="${dirname#?}" 6 | 7 | #绝对路径 8 | if [ "${dirname%$tmp}" != "/" ]; then 9 | dirname=$PWD/$dirname 10 | fi 11 | 12 | LD_LIBRARY_PATH=$dirname 13 | export LD_LIBRARY_PATH 14 | $dirname/$appname "$@" #"$@" 脚本参数 15 | 16 | -------------------------------------------------------------------------------- /resources/debian_portable/ldd.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | EXE='ChineseChess' # 我的程序名 3 | PWD=`pwd` # 打包的路径 4 | files=`ldd $EXE | awk '{ if(match($3,"^/"))printf("%s "),$3 }'` 5 | cp $files $PWD 6 | 7 | -------------------------------------------------------------------------------- /resources/images/5abc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/images/5abc.png -------------------------------------------------------------------------------- /resources/images/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/images/b.jpg -------------------------------------------------------------------------------- /resources/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/images/background.jpg -------------------------------------------------------------------------------- /resources/images/chess.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 象棋32 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /resources/images/win.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/images/win.jpg -------------------------------------------------------------------------------- /resources/logo/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/logo/logo.ico -------------------------------------------------------------------------------- /resources/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/logo/logo.png -------------------------------------------------------------------------------- /resources/logo/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 象棋128 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /resources/logo/resources.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON ICON DISCARDABLE "logo.ico" -------------------------------------------------------------------------------- /resources/res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/5abc.png 4 | images/b.jpg 5 | images/background.jpg 6 | images/chess.svg 7 | images/win.jpg 8 | sound/backChess.wav 9 | sound/eatChess.wav 10 | sound/generalSound.wav 11 | sound/moveChess.wav 12 | sound/selectChess.wav 13 | sound/WinSound.wav 14 | 15 | 16 | -------------------------------------------------------------------------------- /resources/sound/WinSound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/WinSound.wav -------------------------------------------------------------------------------- /resources/sound/backChess.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/backChess.wav -------------------------------------------------------------------------------- /resources/sound/eatChess.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/eatChess.wav -------------------------------------------------------------------------------- /resources/sound/generalSound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/generalSound.wav -------------------------------------------------------------------------------- /resources/sound/moveChess.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/moveChess.wav -------------------------------------------------------------------------------- /resources/sound/selectChess.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/resources/sound/selectChess.wav -------------------------------------------------------------------------------- /setup_package_user.iss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XMuli/ChineseChess/c2c56819bea4d76dae7e0dd3ae40b691b87ab65b/setup_package_user.iss -------------------------------------------------------------------------------- /tech.xmuli.chinesechess/linglong.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | id: tech.xmuli.chinesechess 3 | name: chinesechess 4 | version: 6.2 5 | kind: app 6 | description: | 7 | Cross-platform and online battle platform game based on Qt: Chinese Chess. Also known as: Xiangqi 8 | 9 | runtime: 10 | id: org.deepin.Runtime 11 | version: 23.0.0 12 | 13 | depends: 14 | - id: icu 15 | version: 63.1 16 | type: runtime 17 | 18 | source: 19 | kind: git 20 | url: "https://github.com/XMuli/ChineseChess.git" 21 | commit: 80bdb58e08f06579c6b90c31001d5309e0d48ce5 22 | 23 | build: 24 | kind: qmake 25 | --------------------------------------------------------------------------------