├── chessApp.rc ├── media ├── give.wav └── check.wav ├── images ├── cannon_0.png ├── cannon_1.png ├── horse_0.png ├── horse_1.png ├── advisor_0.png ├── advisor_1.png ├── chariot_0.png ├── chariot_1.png ├── chessIcon.icns ├── chessIcon.ico ├── chessboard.png ├── elephant_0.png ├── elephant_1.png ├── general_0.png ├── general_1.png ├── snapshot1.png ├── soldier_0.png └── soldier_1.png ├── chesspos.cpp ├── chesspos.h ├── pieceitem.cpp ├── readme.md ├── waitdialog.cpp ├── waitdialog.h ├── pieceitem.h ├── connectdialog.h ├── main.cpp ├── doc ├── jsonFormat.md └── manual.md ├── .gitignore ├── chessresource.qrc ├── waitdialog.ui ├── chessboard.h ├── chesspiece.h ├── connectdialog.cpp ├── mainwindow.h ├── netserver.h ├── connectdialog.ui ├── ChineseChess.pro ├── graphicsscene.h ├── gamecenter.h ├── gamecenter.cpp ├── mainwindow.ui ├── chesspiece.cpp ├── mainwindow.cpp ├── chessboard.cpp ├── LICENSE ├── netserver.cpp └── graphicsscene.cpp /chessApp.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "./images/chessIcon.ico" -------------------------------------------------------------------------------- /media/give.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/media/give.wav -------------------------------------------------------------------------------- /media/check.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/media/check.wav -------------------------------------------------------------------------------- /images/cannon_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/cannon_0.png -------------------------------------------------------------------------------- /images/cannon_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/cannon_1.png -------------------------------------------------------------------------------- /images/horse_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/horse_0.png -------------------------------------------------------------------------------- /images/horse_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/horse_1.png -------------------------------------------------------------------------------- /images/advisor_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/advisor_0.png -------------------------------------------------------------------------------- /images/advisor_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/advisor_1.png -------------------------------------------------------------------------------- /images/chariot_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/chariot_0.png -------------------------------------------------------------------------------- /images/chariot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/chariot_1.png -------------------------------------------------------------------------------- /images/chessIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/chessIcon.icns -------------------------------------------------------------------------------- /images/chessIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/chessIcon.ico -------------------------------------------------------------------------------- /images/chessboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/chessboard.png -------------------------------------------------------------------------------- /images/elephant_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/elephant_0.png -------------------------------------------------------------------------------- /images/elephant_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/elephant_1.png -------------------------------------------------------------------------------- /images/general_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/general_0.png -------------------------------------------------------------------------------- /images/general_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/general_1.png -------------------------------------------------------------------------------- /images/snapshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/snapshot1.png -------------------------------------------------------------------------------- /images/soldier_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/soldier_0.png -------------------------------------------------------------------------------- /images/soldier_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renzibei/ChineseChess/master/images/soldier_1.png -------------------------------------------------------------------------------- /chesspos.cpp: -------------------------------------------------------------------------------- 1 | #include "chesspos.h" 2 | 3 | ChessPos::ChessPos(int x, int y): 4 | x(x), y(y) 5 | { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /chesspos.h: -------------------------------------------------------------------------------- 1 | #ifndef CHESSPOS_H 2 | #define CHESSPOS_H 3 | 4 | 5 | class ChessPos 6 | { 7 | public: 8 | ChessPos(int x, int y); 9 | int x,y; 10 | }; 11 | 12 | #endif // CHESSPOS_H 13 | -------------------------------------------------------------------------------- /pieceitem.cpp: -------------------------------------------------------------------------------- 1 | #include "pieceitem.h" 2 | 3 | PieceItem::PieceItem(ChessPiece* piece, const QPixmap &pixmap): 4 | QGraphicsPixmapItem (pixmap),_chessPiece(piece) 5 | { 6 | this->setFlag(QGraphicsItem::ItemIsSelectable, true); 7 | } 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ChineseChess 中国象棋 XiangQi 2 | 3 | 此为中国象棋联机对战软件,采用qt编写。网络采取c2c模式。 4 | 5 | ![截图1](./images/snapshot1.png) 6 | 7 | 8 | 9 | 目前在retina macbook pro 15 inch、高分屏windows与普通屏windows上进行过测试。 10 | 11 | 针对macbook和普通屏windows,编译时gamecenter.h里的`#define LOW_DPI`要保留,对于高分屏windows,要注释掉`#define LOW_DPI` 12 | 13 | 14 | 15 | 更多信息请参考`doc/manual.md` 16 | 17 | -------------------------------------------------------------------------------- /waitdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "waitdialog.h" 2 | #include "ui_waitdialog.h" 3 | 4 | 5 | waitDialog::waitDialog(QWidget *parent) : 6 | QDialog(parent), 7 | ui(new Ui::waitDialog) 8 | { 9 | ui->setupUi(this); 10 | connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(close())); 11 | } 12 | 13 | waitDialog::~waitDialog() 14 | { 15 | delete ui; 16 | } 17 | -------------------------------------------------------------------------------- /waitdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef WAITDIALOG_H 2 | #define WAITDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class waitDialog; 8 | } 9 | 10 | class waitDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit waitDialog(QWidget *parent = nullptr); 16 | 17 | ~waitDialog(); 18 | 19 | private: 20 | Ui::waitDialog *ui; 21 | }; 22 | 23 | #endif // WAITDIALOG_H 24 | -------------------------------------------------------------------------------- /pieceitem.h: -------------------------------------------------------------------------------- 1 | #ifndef PIECEITEM_H 2 | #define PIECEITEM_H 3 | 4 | #include 5 | #include "chesspiece.h" 6 | 7 | class PieceItem : public QGraphicsPixmapItem 8 | { 9 | public: 10 | PieceItem(ChessPiece* piece, const QPixmap &pixmap); 11 | ChessPiece* chessPiece() const { 12 | return this->_chessPiece; 13 | } 14 | 15 | protected: 16 | ChessPiece* _chessPiece; 17 | }; 18 | 19 | #endif // PIECEITEM_H 20 | -------------------------------------------------------------------------------- /connectdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CONNECTDIALOG_H 2 | #define CONNECTDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class ConnectDialog; 8 | } 9 | 10 | class ConnectDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit ConnectDialog(QWidget *parent = nullptr); 16 | ~ConnectDialog(); 17 | 18 | private: 19 | Ui::ConnectDialog *ui; 20 | private slots: 21 | void cancelButtonPushed(); 22 | void okButtonPushed(); 23 | 24 | }; 25 | 26 | #endif // CONNECTDIALOG_H 27 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 9 | QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 10 | //QDesktopWidget* desktop = QApplication::desktop(); 11 | //QScreen * screen = QGuiApplication::primaryScreen(); 12 | 13 | MainWindow w; 14 | w.show(); 15 | 16 | return a.exec(); 17 | } 18 | -------------------------------------------------------------------------------- /doc/jsonFormat.md: -------------------------------------------------------------------------------- 1 | # jsonFormat 2 | 3 | 开头四个字节为包长度 4 | 5 | 后面为json数据 6 | 7 | json构成为 {"packageType":number ...} 8 | 9 | *** 10 | 11 | packageType = 0 12 | 13 | 反馈包 14 | 15 | result = 0代表正常,1代表出错 16 | 17 | {"packageType", "result":number} 18 | 19 | *** 20 | 21 | packageType = 1 22 | 23 | 走棋包,{"packageType" , "from":{"x":number, "y":number}, "to":{x, y}} 24 | 25 | *** 26 | 27 | 2 28 | 29 | 将军losType为1,认输loseType为2, 超时loseType为3, 对将为4 30 | 31 | 输包{"packageType", "loseType":number 32 | 33 | 34 | 35 | *** 36 | 37 | 3 38 | 39 | 新游戏 40 | 41 | gameMode 为0时代表新游戏,为1时代表残局模式,并传送残局地图 42 | 43 | {"packageType", "gameMode":number, hostColor":bool, "map":string} 44 | 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.dll 10 | *.dylib 11 | 12 | # Qt-es 13 | object_script.*.Release 14 | object_script.*.Debug 15 | *_plugin_import.cpp 16 | /.qmake.cache 17 | /.qmake.stash 18 | *.pro.user 19 | *.pro.user.* 20 | *.qbs.user 21 | *.qbs.user.* 22 | *.moc 23 | moc_*.cpp 24 | moc_*.h 25 | qrc_*.cpp 26 | ui_*.h 27 | *.qmlc 28 | *.jsc 29 | Makefile* 30 | *build-* 31 | 32 | # Qt unit tests 33 | target_wrapper.* 34 | 35 | # QtCreator 36 | *.autosave 37 | 38 | # QtCreator Qml 39 | *.qmlproject.user 40 | *.qmlproject.user.* 41 | 42 | # QtCreator CMake 43 | CMakeLists.txt.user* 44 | 45 | #windows 46 | .DS_store 47 | -------------------------------------------------------------------------------- /chessresource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/chessboard.png 4 | images/general_0.png 5 | images/advisor_0.png 6 | images/elephant_0.png 7 | images/horse_0.png 8 | images/chariot_0.png 9 | images/cannon_0.png 10 | images/soldier_0.png 11 | images/soldier_1.png 12 | images/general_1.png 13 | images/elephant_1.png 14 | images/advisor_1.png 15 | images/cannon_1.png 16 | images/horse_1.png 17 | images/chariot_1.png 18 | media/give.wav 19 | media/check.wav 20 | 21 | 22 | -------------------------------------------------------------------------------- /doc/manual.md: -------------------------------------------------------------------------------- 1 | # ChineseChess 中国象棋 使用说明 2 | 3 | 4 | 5 | 1. 简要说明 6 | 7 | 此软件采取端到端的去中心化网络连接,一方新建游戏等待连接,一方输入对方ip连接,建立游戏。 8 | 9 | 2. 简单规则说明 10 | 11 | 游戏遵循基本象棋规则。 12 | 13 | - 不能对将,移动导致对将者判负。 14 | - 每回合限制思考时间60s,超时判负。 15 | 16 | 3. 功能介绍 17 | 18 | - 进行联机象棋游戏功能 19 | - 保存棋盘功能,生成存档文本文件 20 | - 读取棋盘存档功能,可以用存档建立新比赛 21 | - 走棋音效和将军音效 22 | - 可以认输 23 | 24 | 4. 程序架构介绍 25 | 26 | 1. 采取OOP设计思想,运用单例模式、委托模式等设计模式。 27 | 28 | 2. 主要的类有ChessPiece, ChessBoard, GameCenter, NetServer, GraphicsScene, PieceItem, MainWindow等。其中ChessPiece是棋子类,储存有棋子的数据,ChessBoard为棋盘类,有棋盘信息,并充当棋子工厂,GameCenter为后台数据中心,储存有游戏信息并管理,NetServer为网络服务委托类,可以通过其收发数据,GraphicsScene为继承了QGraphicsScene的场景类,管理棋子、棋盘的视图、屏幕位置、鼠标交互操作等。PieceItem为棋子的视图Item类。 29 | 30 | 3. 工作流程 31 | 32 | 1. 在主程序的菜单栏选择新建游戏,NetServer开始监听 33 | 2. 另一客户端加入游戏,建立连接,双方的GameCenter开始运转 34 | 3. 交互过程中双方传输数据,通过NetServer并用GameCenter处理、同步。 35 | 36 | 4. 数据交换格式 37 | 38 | 先用网络字节序传送4个字节的整形表示包长度,然后传输json包装的信息。包内容详情见`doc/jsonFormat.md`. 39 | 40 | 5. 编译安装 41 | 42 | 见readme.md -------------------------------------------------------------------------------- /waitdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | waitDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | <h1> 等待连接..</h1> 23 | 24 | 25 | 26 | 27 | 28 | 29 | 取消 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /chessboard.h: -------------------------------------------------------------------------------- 1 | #ifndef CHESSBOARD_H 2 | #define CHESSBOARD_H 3 | 4 | #include 5 | #include "chesspiece.h" 6 | #include "chesspos.h" 7 | #include 8 | #include 9 | 10 | using std::vector; 11 | 12 | class ChessBoard 13 | { 14 | public: 15 | ChessBoard(); 16 | ChessPiece *at(int x, int y) const { 17 | return this->pieces[x][y]; 18 | } 19 | ChessPiece *at(const ChessPos &pos) const { 20 | return this->pieces[pos.x][pos.y]; 21 | } 22 | 23 | void loadSavedFile(QTextStream &in); 24 | 25 | vector &getPieces(); 26 | void addPiece(ChessPiece *piece); 27 | void removePieceAt(const ChessPos &pos); 28 | void removePiece(ChessPiece* piece); 29 | void movePieceTo(ChessPiece* piece, int x, int y); 30 | void movePieceTo(ChessPiece* piece, const ChessPos &pos); 31 | void clearChessBoard(); 32 | bool generalFaced() const; 33 | 34 | QString getSaveContent(); 35 | protected: 36 | ChessPiece *pieces[10][9]; 37 | 38 | vector remainingPieces; 39 | // ChessPos* generalPos[2]; 40 | }; 41 | 42 | #endif // CHESSBOARD_H 43 | -------------------------------------------------------------------------------- /chesspiece.h: -------------------------------------------------------------------------------- 1 | #ifndef CHESSPIECE_H 2 | #define CHESSPIECE_H 3 | 4 | 5 | #include "chesspos.h" 6 | #include 7 | 8 | enum PieceType {General = 2, Advisor = 3, Elephant = 4, Horse = 5, Chariot = 6, Cannon = 7, Soldier = 8}; 9 | 10 | 11 | 12 | class ChessPiece 13 | { 14 | public: 15 | ChessPiece(const ChessPos &chessPos, PieceType type, bool belong); 16 | ChessPiece(int x, int y, PieceType type, bool belong); 17 | int canMoveTo(int x, int y) const; 18 | int canMoveTo(ChessPos chesspos) const; 19 | ChessPos pos() const; 20 | static const QString pieceNames[7]; 21 | /** 22 | * @brief 代表属于玩家0还是玩家1 23 | * @return 24 | */ 25 | bool belong() const; 26 | int x() const; 27 | int y() const; 28 | PieceType type() const; 29 | virtual ~ChessPiece(); 30 | 31 | /** 32 | * @brief moveTo 如果可以移动且能吃子,则返回吃的子的类型枚举,能移动但不能吃子则返回1,不能移动返回0 33 | * @param x 34 | * @param y 35 | * @return 36 | */ 37 | int moveTo(int x, int y); 38 | int moveTo(ChessPos pos); 39 | 40 | protected: 41 | ChessPos _pos; 42 | PieceType _type; 43 | bool _belong; 44 | 45 | 46 | }; 47 | 48 | 49 | 50 | 51 | 52 | #endif // CHESSPIECE_H 53 | -------------------------------------------------------------------------------- /connectdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "connectdialog.h" 2 | #include "ui_connectdialog.h" 3 | #include "gamecenter.h" 4 | #include 5 | 6 | ConnectDialog::ConnectDialog(QWidget *parent) : 7 | QDialog(parent), 8 | ui(new Ui::ConnectDialog) 9 | { 10 | ui->setupUi(this); 11 | connect(ui->okButton, SIGNAL(clicked()), this, SLOT(okButtonPushed())); 12 | connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(cancelButtonPushed())); 13 | } 14 | 15 | 16 | 17 | bool isLegalIp(QString ipAddress) 18 | { 19 | QHostAddress test; 20 | if (!test.setAddress(ipAddress)) 21 | { 22 | //ui->statusBar->showMessage("ERROR : Invalid ip address."); 23 | return false; 24 | } 25 | return true; 26 | 27 | } 28 | 29 | void ConnectDialog::okButtonPushed() 30 | { 31 | QString ipString = ui->lineEdit->text(); 32 | if(isLegalIp(ipString)) { 33 | GameCenter::getInstance()->netServer->setHostIp(ipString); 34 | GameCenter::getInstance()->netServer->connectServer(); 35 | this->close(); 36 | } 37 | else QMessageBox::information(this, tr("错误"), tr("ip地址格式错误")); 38 | } 39 | 40 | void ConnectDialog::cancelButtonPushed() 41 | { 42 | this->close(); 43 | } 44 | 45 | ConnectDialog::~ConnectDialog() 46 | { 47 | delete ui; 48 | } 49 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | 5 | #include 6 | #include "graphicsscene.h" 7 | #include 8 | #include 9 | 10 | 11 | namespace Ui { 12 | class MainWindow; 13 | } 14 | 15 | class MainWindow : public QMainWindow 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit MainWindow(QWidget *parent = nullptr); 21 | static MainWindow* getInstance(); 22 | ~MainWindow(); 23 | GraphicsScene* getGraphicsScene() { 24 | return this->graphicsScene; 25 | } 26 | void changeNewScene(); 27 | void displayTime(int remainTime); 28 | 29 | public slots: 30 | void gameOver(bool whoseWinner, int winType); 31 | 32 | private: 33 | Ui::MainWindow *ui; 34 | GraphicsScene *graphicsScene; 35 | static MainWindow* instance; 36 | QSound *moveSound; 37 | QSound *gameOverSound; 38 | 39 | void createMenu(); 40 | 41 | bool checkJiangjun(int type); 42 | 43 | 44 | private slots: 45 | void createNewGame(); 46 | void joinGame(); 47 | void readOldGame(); 48 | void saveGame(); 49 | void quitGame(); 50 | void giveUpGame(); 51 | void beginGame(); 52 | void prepareSound(); 53 | void playJiangjun(bool winner, int type); 54 | }; 55 | 56 | #endif // MAINWINDOW_H 57 | -------------------------------------------------------------------------------- /netserver.h: -------------------------------------------------------------------------------- 1 | #ifndef NETSERVER_H 2 | #define NETSERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "chesspos.h" 8 | 9 | class NetServer : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | NetServer(); 14 | static NetServer* getInstance() { 15 | if(NetServer::_instance == nullptr) 16 | NetServer::_instance = new NetServer; 17 | return NetServer::_instance; 18 | } 19 | void setHostIp(const QString& ipAddress); 20 | 21 | void connectServer(); 22 | int readIntoBuffer(QByteArray& buffer, int len); 23 | int sendObjectMessage(const QJsonObject& object); 24 | int sendMessage(const QByteArray& message); 25 | void initServer(); 26 | void sendMoveMessage(ChessPos oldPos, ChessPos newPos); 27 | void sendLossMessage(int loseType = 1); 28 | ~NetServer(); 29 | 30 | protected: 31 | QTcpServer *tcpServer; 32 | QTcpSocket *tcpSocket; 33 | QString _ipAddress; 34 | 35 | QJsonDocument readJsonDocument(); 36 | int getIntFromBuffer(const QByteArray &buffer); 37 | 38 | void sendFeedBackPackage(int statusType); 39 | 40 | static NetServer *_instance; 41 | 42 | protected slots: 43 | void getConnection(); 44 | void recvMessage(); 45 | void sendBeginInfo(bool beginWithSavedGame = false); 46 | 47 | signals: 48 | void getFeedBack(); 49 | void connectBuilt(); 50 | void gameBegin(bool hostColor); 51 | 52 | 53 | }; 54 | 55 | #endif // NETSERVER_H 56 | -------------------------------------------------------------------------------- /connectdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ConnectDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 80 20 | 80 21 | 241 22 | 141 23 | 24 | 25 | 26 | 27 | 28 | 29 | <h1>请输入主机ip地址</h1> 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 取消 42 | 43 | 44 | 45 | 46 | 47 | 48 | 确认 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /ChineseChess.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-09-05T17:38:13 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui widgets 8 | QT += network 9 | QT += multimedia 10 | 11 | 12 | TARGET = ChineseChess 13 | TEMPLATE = app 14 | 15 | 16 | 17 | # The following define makes your compiler emit warnings if you use 18 | # any feature of Qt which has been marked as deprecated (the exact warnings 19 | # depend on your compiler). Please consult the documentation of the 20 | # deprecated API in order to know how to port your code away from it. 21 | DEFINES += QT_DEPRECATED_WARNINGS 22 | 23 | # You can also make your code fail to compile if you use deprecated APIs. 24 | # In order to do so, uncomment the following line. 25 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 26 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 27 | 28 | CONFIG += c++11 29 | 30 | SOURCES += \ 31 | main.cpp \ 32 | mainwindow.cpp \ 33 | chesspiece.cpp \ 34 | chessboard.cpp \ 35 | netserver.cpp \ 36 | chesspos.cpp \ 37 | gamecenter.cpp \ 38 | graphicsscene.cpp \ 39 | pieceitem.cpp \ 40 | waitdialog.cpp \ 41 | connectdialog.cpp 42 | 43 | HEADERS += \ 44 | mainwindow.h \ 45 | chesspiece.h \ 46 | chessboard.h \ 47 | netserver.h \ 48 | chesspos.h \ 49 | gamecenter.h \ 50 | graphicsscene.h \ 51 | pieceitem.h \ 52 | waitdialog.h \ 53 | connectdialog.h 54 | 55 | FORMS += \ 56 | mainwindow.ui \ 57 | waitdialog.ui \ 58 | connectdialog.ui 59 | 60 | # Default rules for deployment. 61 | qnx: target.path = /tmp/$${TARGET}/bin 62 | else: unix:!android: target.path = /opt/$${TARGET}/bin 63 | !isEmpty(target.path): INSTALLS += target 64 | 65 | RESOURCES += \ 66 | chessresource.qrc 67 | ICON = images/chessIcon.icns 68 | RC_FILE += chessApp.rc 69 | #RC_ICONS = ./images/chessIcon.ico 70 | -------------------------------------------------------------------------------- /graphicsscene.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHICSSCENE_H 2 | #define GRAPHICSSCENE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "gamecenter.h" 9 | #include "chesspiece.h" 10 | #include "pieceitem.h" 11 | #include "chesspos.h" 12 | #include "gamecenter.h" 13 | 14 | using std::list; 15 | 16 | class GraphicsScene : public QGraphicsScene 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit GraphicsScene(QObject *parent = nullptr); 21 | void setSelectable(); 22 | void movePieceItemTo(ChessPos oldPos, ChessPos newPos); 23 | 24 | signals: 25 | 26 | public slots: 27 | 28 | protected: 29 | void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); 30 | void mousePressEvent(QGraphicsSceneMouseEvent *event); 31 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); 32 | ChessPos posFromPixel(const QPointF& pos); 33 | QPointF posFromXY(const ChessPos& pos); 34 | bool inChessboard(const QPointF& pos); 35 | PieceItem *getPieceItem(ChessPiece* chesspiece); 36 | 37 | PieceItem *getExistedItem(ChessPiece* chesspiece); 38 | 39 | list pieceItems; 40 | 41 | bool pieceSelected() const { 42 | return selectedItems().size() > 0; 43 | } 44 | 45 | void removePieceItem(PieceItem* item); 46 | 47 | PieceItem *selectedPieceItem; 48 | ChessPiece *willBeEatenPiece; 49 | QGraphicsPixmapItem *backgroundItem; 50 | #ifdef LOW_DPI 51 | 52 | const double squareLen = 109.6/2; 53 | const double leftPointx = 61/2 + 1, leftPointy = 59/2; 54 | const double leftLimit = 56.2/2, topLimit = 54.2/2, bottomLimit = 1150.2/2, rightLimit = 1042.6/2; 55 | const double pieceLen = 50; 56 | #else 57 | const double squareLen = 109.6; 58 | const double leftPointx = 61 + 3, leftPointy = 59 + 3; 59 | const double leftLimit = 56.2, topLimit = 54.2, bottomLimit = 1150.2, rightLimit = 1042.6; 60 | const double pieceLen = 100; 61 | #endif 62 | 63 | protected slots: 64 | void modifySelection(); 65 | }; 66 | 67 | #endif // GRAPHICSSCENE_H 68 | -------------------------------------------------------------------------------- /gamecenter.h: -------------------------------------------------------------------------------- 1 | #ifndef GAMECENTER_H 2 | #define GAMECENTER_H 3 | 4 | #include 5 | #include 6 | #include "chessboard.h" 7 | #include "chesspiece.h" 8 | #include "netserver.h" 9 | 10 | //#define DEBUG_MODE 11 | 12 | //#ifdef __APPLE__ 13 | 14 | #define LOW_DPI 15 | 16 | //#endif 17 | 18 | #define roundTime 60 19 | 20 | class GameCenter : public QObject 21 | { 22 | Q_OBJECT 23 | public: 24 | GameCenter(bool localGamer = 0, int colorSet = 1, bool color = 0, QObject *parent = nullptr); 25 | NetServer *netServer; 26 | static GameCenter* getInstance(); 27 | QTimer *gameClock; 28 | 29 | /** 30 | * @brief gamerColor 31 | * @return 0代表自己是黑色,1代表自己是红色 32 | */ 33 | bool gamerColor() const { 34 | return this->_gamerColor; 35 | } 36 | 37 | /** 38 | * @brief whoseRound 下一回合是谁 39 | * @return 0代表主机,1代表对面 40 | */ 41 | bool whoseRound() const { 42 | return this->_whoseRound; 43 | } 44 | 45 | void newGame(bool colorSet = 0); 46 | void startGame(); 47 | 48 | 49 | void loadOldGame(const QString& filePath); 50 | 51 | 52 | 53 | /** 54 | * @brief roundEnd 调用来结束当前会和,开启下一回合 55 | */ 56 | void roundEnd(); 57 | void eatPiece(ChessPiece* eaterPiece, ChessPiece * eatenPiece); 58 | 59 | static ChessBoard* getChessBoard() { 60 | if(GameCenter::getInstance()->chessBoard == nullptr) 61 | GameCenter::getInstance()->chessBoard = new ChessBoard; 62 | return GameCenter::getInstance()->chessBoard; 63 | } 64 | 65 | static vector& getPieces() { 66 | return GameCenter::getChessBoard()->getPieces(); 67 | } 68 | 69 | ~GameCenter(); 70 | 71 | void setLocalGamer(bool gamer); 72 | 73 | void setGamerColor(bool color); 74 | 75 | bool isGameOver() { 76 | return this->_gameOver; 77 | } 78 | 79 | void simplyChangeColor(bool color) { 80 | this->_gamerColor = color; 81 | if(_gamerColor) 82 | this->_whoseRound = this->_localGamer; 83 | else this->_whoseRound = !_localGamer; 84 | } 85 | 86 | bool localGamer() const { 87 | return this->_localGamer; 88 | } 89 | 90 | bool isSavedGame() const { 91 | return this->_savedGame; 92 | } 93 | 94 | void setSavedGame(bool isSavedGame = true) { 95 | this->_savedGame = isSavedGame; 96 | } 97 | 98 | public slots: 99 | void setGameOver(bool isOver = true) { 100 | this->_gameOver = isOver; 101 | } 102 | 103 | protected: 104 | ChessBoard *chessBoard; 105 | bool _whoseRound; 106 | bool _gamerColor; 107 | int totalRound; 108 | bool _localGamer; 109 | int remainTime; 110 | bool _savedGame; 111 | bool _gameOver; 112 | static GameCenter *_instance; 113 | 114 | protected slots: 115 | void timeDecline(); 116 | 117 | signals: 118 | void gameOverSignal(bool whoseWinner, int winType); 119 | void pieceMoved(); 120 | }; 121 | 122 | 123 | 124 | #endif // GAMECENTER_H 125 | -------------------------------------------------------------------------------- /gamecenter.cpp: -------------------------------------------------------------------------------- 1 | #include "gamecenter.h" 2 | #include 3 | #include 4 | #include "mainwindow.h" 5 | 6 | GameCenter *GameCenter::_instance = nullptr; 7 | 8 | GameCenter *GameCenter::getInstance() 9 | { 10 | if(GameCenter::_instance == nullptr) 11 | GameCenter::_instance = new GameCenter; 12 | return GameCenter::_instance; 13 | } 14 | 15 | GameCenter::GameCenter(bool localGamer, int colorSet, bool color, QObject *parent): 16 | QObject(parent), chessBoard(nullptr), totalRound(0), _localGamer(localGamer), _savedGame(0), _gameOver(0) 17 | { 18 | srand((unsigned)time(0)); 19 | if(colorSet == 0) { 20 | this->_gamerColor = rand()%2; 21 | } 22 | else _gamerColor = color; 23 | if(_gamerColor) 24 | this->_whoseRound = this->_localGamer; 25 | else this->_whoseRound = !_localGamer; 26 | this->chessBoard = new ChessBoard; 27 | this->netServer = NetServer::getInstance(); 28 | this->gameClock = new QTimer(); 29 | gameClock->setTimerType(Qt::PreciseTimer); 30 | connect(this, SIGNAL(gameOverSignal(bool, int)), this, SLOT(setGameOver())); 31 | GameCenter::_instance = this; 32 | } 33 | 34 | void GameCenter::setGamerColor(bool color) 35 | { 36 | this->_gamerColor = color; 37 | if(_gamerColor) 38 | this->_whoseRound = this->_localGamer; 39 | else this->_whoseRound = !_localGamer; 40 | this->newGame(1); 41 | } 42 | 43 | void GameCenter::setLocalGamer(bool gamer) 44 | { 45 | this->_localGamer = gamer; 46 | } 47 | 48 | void GameCenter::newGame(bool colorSet) 49 | { 50 | if(chessBoard != nullptr) 51 | delete chessBoard; 52 | this->chessBoard = new ChessBoard; 53 | this->setGameOver(0); 54 | totalRound = 0; 55 | if(!colorSet) 56 | this->_gamerColor = rand()%2; 57 | if(_gamerColor) 58 | this->_whoseRound = this->_localGamer; 59 | else this->_whoseRound = !_localGamer; 60 | MainWindow::getInstance()->changeNewScene(); 61 | } 62 | 63 | void GameCenter::loadOldGame(const QString& filePath) 64 | { 65 | this->chessBoard->clearChessBoard(); 66 | QFile file(filePath); 67 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) 68 | return; 69 | QTextStream in(&file); 70 | this->chessBoard->loadSavedFile(in); 71 | MainWindow::getInstance()->changeNewScene(); 72 | } 73 | 74 | void GameCenter::startGame() 75 | { 76 | #ifndef DEBUG_MODE 77 | this->gameClock->start(1000); 78 | #endif 79 | remainTime = roundTime; 80 | disconnect(gameClock, 0, this, 0); 81 | connect(gameClock, SIGNAL(timeout()), this, SLOT(timeDecline())); 82 | connect(this, SIGNAL(gameOverSignal(bool, int)), gameClock, SLOT(stop())); 83 | MainWindow::getInstance()->displayTime(remainTime); 84 | } 85 | 86 | void GameCenter::timeDecline() 87 | { 88 | this->remainTime--; 89 | MainWindow::getInstance()->displayTime(remainTime); 90 | if(remainTime == 0 && _whoseRound == _localGamer) { 91 | GameCenter::getInstance()->netServer->sendLossMessage(3); 92 | this->gameClock->stop(); 93 | emit this->gameOverSignal(!_whoseRound, 3); 94 | } 95 | } 96 | 97 | 98 | void GameCenter::eatPiece(ChessPiece* eaterPiece, ChessPiece * eatenPiece) 99 | { 100 | if(eaterPiece->canMoveTo(eatenPiece->pos())) { 101 | ChessPos tempPos = eatenPiece->pos(); int eatenType = eatenPiece->type(); 102 | 103 | GameCenter::getChessBoard()->movePieceTo(eaterPiece, tempPos); 104 | this->chessBoard->removePiece(eatenPiece); 105 | //eaterPiece->moveTo(tempPos); 106 | if(eatenType == General) { 107 | emit gameOverSignal(eaterPiece->belong(), 1); 108 | } 109 | } 110 | } 111 | 112 | void GameCenter::roundEnd() 113 | { 114 | this->totalRound++; 115 | this->_whoseRound = !_whoseRound; 116 | this->remainTime = roundTime; 117 | MainWindow::getInstance()->displayTime(remainTime); 118 | } 119 | 120 | GameCenter::~GameCenter() 121 | { 122 | 123 | } 124 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 809 10 | 734 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Qt::Vertical 29 | 30 | 31 | 32 | 20 33 | 40 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 剩余时间 50 | 51 | 52 | 53 | 54 | 55 | 56 | QLCDNumber::Flat 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Qt::Vertical 69 | 70 | 71 | 72 | 20 73 | 40 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 认输 82 | 83 | 84 | 85 | 86 | 87 | 88 | Qt::Vertical 89 | 90 | 91 | 92 | 20 93 | 40 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 0 108 | 0 109 | 809 110 | 21 111 | 112 | 113 | 114 | 115 | 116 | TopToolBarArea 117 | 118 | 119 | false 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /chesspiece.cpp: -------------------------------------------------------------------------------- 1 | #include "chesspiece.h" 2 | #include "gamecenter.h" 3 | 4 | const QString ChessPiece::pieceNames[7] = {"general", "advisor", "elephant", "horse", "chariot", "cannon", "soldier"}; 5 | 6 | ChessPiece::ChessPiece(const ChessPos &chessPos, PieceType type, bool belong): _pos(chessPos), _type(type), _belong(belong) 7 | { 8 | 9 | } 10 | 11 | ChessPiece::ChessPiece(int x, int y, PieceType type, bool belong): _pos(ChessPos(x, y)), _type(type), _belong(belong) 12 | { 13 | 14 | } 15 | 16 | PieceType ChessPiece::type() const { 17 | return this->_type; 18 | } 19 | 20 | 21 | ChessPiece::~ChessPiece() 22 | { 23 | 24 | } 25 | 26 | ChessPos ChessPiece::pos() const 27 | { 28 | return this->_pos; 29 | } 30 | 31 | int ChessPiece::x() const 32 | { 33 | return this->_pos.x; 34 | } 35 | 36 | int ChessPiece::y() const 37 | { 38 | return this->_pos.y; 39 | } 40 | 41 | bool ChessPiece::belong() const 42 | { 43 | return this->_belong; 44 | } 45 | 46 | int ChessPiece::moveTo(ChessPos pos) 47 | { 48 | return this->moveTo(pos.x, pos.y); 49 | } 50 | 51 | int ChessPiece::moveTo(int x, int y) 52 | { 53 | //if(this->canMoveTo(x, y)) { 54 | this->_pos.x = x; this->_pos.y = y; 55 | 56 | //} 57 | } 58 | 59 | int getDis(ChessPos pos1, ChessPos pos2) 60 | { 61 | return abs(pos1.x - pos2.x) + abs(pos1.y - pos2.y); 62 | } 63 | 64 | bool inHomeArea(int x, int y, bool belong) 65 | { 66 | if(belong) { 67 | return (0 <= x && 2 >= x && 3 <= y && 5 >= y); 68 | } 69 | else { 70 | return (7 <= x && 9 >= x && 3 <=y && 5 >= y); 71 | } 72 | } 73 | 74 | bool inHomeHalf(int x, int y, int belong) 75 | { 76 | if(belong) { 77 | return (0 <= x && 4 >= x && 0 <= y && 8 >= y); 78 | } 79 | else { 80 | return (5 <= x && 9 >= x && 0 <=y && 8 >= y); 81 | } 82 | } 83 | 84 | bool inChessBoard(int x, int y) 85 | { 86 | return (0 <= x && 9 >= x && 0 <= y && 8 >= y); 87 | } 88 | 89 | bool belongToSamePlayer(ChessPos pos1, ChessPos pos2) 90 | { 91 | return GameCenter::getChessBoard()->at(pos1)->belong() == GameCenter::getChessBoard()->at(pos2)->belong(); 92 | } 93 | 94 | int ChessPiece::canMoveTo(int x, int y) const 95 | { 96 | if(inChessBoard(x, y)) { 97 | if(GameCenter::getChessBoard()->at(x, y) != nullptr) 98 | if(belongToSamePlayer(this->pos(), ChessPos(x, y))) 99 | return 0; 100 | switch (this->_type) { 101 | case General: 102 | if(getDis(this->_pos, ChessPos(x, y)) == 1) { 103 | return inHomeArea(x, y, this->_belong); 104 | } 105 | return 0; 106 | case Advisor: 107 | if(abs(x - this->x()) == 1 && abs(y - this->y()) == 1) 108 | return inHomeArea(x, y, this->_belong); 109 | return 0; 110 | case Elephant: 111 | if(abs(x - this->x()) == 2 && abs(y - this->y()) == 2) 112 | if(inHomeHalf(x, y, this->_belong)) 113 | if(GameCenter::getChessBoard()->at((x + this->x()) / 2, (y + this->y()) / 2) == nullptr) 114 | return 1; 115 | return 0; 116 | case Horse: { 117 | int xdis = abs(x - this->x()), ydis = abs(y - this->y()); 118 | if(xdis == 2 && ydis == 1) { 119 | if(GameCenter::getChessBoard()->at((x + this->x()) / 2, this->y()) == nullptr) { 120 | return 1; 121 | } 122 | } 123 | else if(xdis == 1 && ydis == 2) { 124 | if(GameCenter::getChessBoard()->at(this->x(), (y + this->y()) / 2) == nullptr) 125 | return 1; 126 | } 127 | return 0; 128 | } 129 | case Chariot: { 130 | int xdis = abs(x - this->x()), ydis = abs(y - this->y()); 131 | if(xdis == 0) { 132 | int mulRatio = -1; 133 | if(y > this->y()) 134 | mulRatio = 1; 135 | for(int i = 1; i < ydis; ++i) 136 | if(GameCenter::getChessBoard()->at(x, this->y() + i * mulRatio) != nullptr) 137 | return 0; 138 | return 1; 139 | 140 | } 141 | else if(ydis == 0) { 142 | int mulRatio = -1; 143 | if(x > this->x()) 144 | mulRatio = 1; 145 | for(int i = 1; i < xdis; ++i) 146 | if(GameCenter::getChessBoard()->at(this->x() + i * mulRatio, y) != nullptr) 147 | return 0; 148 | return 1; 149 | } 150 | return 0; 151 | } 152 | 153 | case Soldier: 154 | if(getDis(_pos, ChessPos(x, y)) == 1) { 155 | if(inHomeHalf(this->x(), this->y(), _belong)) { 156 | if(this->y() == y) { 157 | if(_belong && x > this->x()) 158 | return 1; 159 | else if((!_belong) && x < this->x()) 160 | return 1; 161 | } 162 | } 163 | else { 164 | if(_belong && x >= this->x()) 165 | return 1; 166 | else if(!_belong && x <= this->x()) 167 | return 1; 168 | } 169 | } 170 | return 0; 171 | case Cannon: { 172 | int xdis = abs(x - this->x()), ydis = abs(y - this->y()); 173 | bool beatSomeone = (GameCenter::getChessBoard()->at(x, y) != nullptr); 174 | if(xdis == 0) { 175 | int numOfPieceInLine = 0; 176 | int mulRatio = (y - this->y()) / ydis; 177 | for(int i = 1; i < ydis; ++i) { 178 | if(GameCenter::getChessBoard()->at(x, this->y() + i * mulRatio) != nullptr) 179 | numOfPieceInLine ++; 180 | } 181 | if((numOfPieceInLine == 1 && beatSomeone) || (numOfPieceInLine == 0 && !beatSomeone) ) 182 | return 1; 183 | } 184 | else if(ydis == 0) { 185 | int numOfPieceInLine = 0; 186 | int mulRatio = (x - this->x()) / xdis; 187 | for(int i = 1; i < xdis; ++i) 188 | if(GameCenter::getChessBoard()->at(this->x() + i * mulRatio, y) != nullptr) 189 | numOfPieceInLine++; 190 | if((numOfPieceInLine == 1 && beatSomeone) || (numOfPieceInLine == 0 && !beatSomeone)) 191 | return 1; 192 | } 193 | return 0; 194 | } 195 | 196 | } 197 | } 198 | else return 0; 199 | } 200 | 201 | int ChessPiece::canMoveTo(ChessPos chesspos) const 202 | { 203 | return this->canMoveTo(chesspos.x, chesspos.y); 204 | } 205 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "waitdialog.h" 12 | #include "gamecenter.h" 13 | #include "connectdialog.h" 14 | 15 | MainWindow::MainWindow(QWidget *parent) : 16 | QMainWindow(parent), 17 | ui(new Ui::MainWindow) 18 | { 19 | ui->setupUi(this); 20 | this->createMenu(); 21 | this->prepareSound(); 22 | //this->moveSound = new QSoundEffect(this); 23 | //moveSound->setSource(QUrl(":/media/give.wav")); 24 | qDebug() << this->devicePixelRatio(); 25 | 26 | //moveSound->setVolume(0.5); 27 | #ifdef LOW_DPI 28 | this->resize(800, 750); 29 | #else 30 | this->resize(1600, 1400); 31 | #endif 32 | 33 | this->graphicsScene = new GraphicsScene; 34 | ui->graphicsView->setMouseTracking(true); 35 | //ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); 36 | ui->graphicsView->setScene(this->graphicsScene); 37 | connect(ui->giveUpButton, SIGNAL(clicked()), this, SLOT(giveUpGame())); 38 | connect(GameCenter::getInstance(), SIGNAL(gameOverSignal(bool, int)), this, SLOT(gameOver(bool, int))); 39 | MainWindow::instance = this; 40 | } 41 | 42 | bool MainWindow::checkJiangjun(int type) 43 | { 44 | if(type == 1) 45 | return 1; 46 | return 0; 47 | } 48 | 49 | void MainWindow::prepareSound() 50 | { 51 | this->moveSound = new QSound(":/media/give.wav"); 52 | connect(GameCenter::getInstance(), SIGNAL(pieceMoved()), moveSound, SLOT(play())); 53 | this->gameOverSound = new QSound(":/media/check.wav"); 54 | connect(GameCenter::getInstance(), SIGNAL(gameOverSignal(bool, int)), this, SLOT(playJiangjun(bool, int))); 55 | } 56 | 57 | void MainWindow::playJiangjun(bool winner, int type) 58 | { 59 | if(checkJiangjun(type)) 60 | this->gameOverSound->play(); 61 | } 62 | 63 | void MainWindow::changeNewScene() 64 | { 65 | if(this->graphicsScene != nullptr) 66 | delete this->graphicsScene; 67 | this->graphicsScene = new GraphicsScene; 68 | ui->graphicsView->setScene(this->graphicsScene); 69 | } 70 | 71 | MainWindow* MainWindow::instance = nullptr; 72 | 73 | MainWindow* MainWindow::getInstance() 74 | { 75 | if(MainWindow::instance == nullptr) 76 | MainWindow::instance = new MainWindow(); 77 | return MainWindow::instance; 78 | } 79 | 80 | 81 | void MainWindow::createMenu() 82 | { 83 | QMenu *gameMenu = new QMenu(tr("游戏")); 84 | QAction *newGameAction = new QAction(tr("新建")); 85 | QAction *joinGameAction = new QAction(tr("加入")); 86 | QAction *saveAction = new QAction(tr("保存")); 87 | QAction *openAction = new QAction(tr("读取")); 88 | QAction *quitAction = new QAction(tr("退出")); 89 | newGameAction->setShortcut(QKeySequence::New); 90 | saveAction->setShortcut(QKeySequence::Save); 91 | openAction->setShortcut(QKeySequence::Open); 92 | quitAction->setShortcut(QKeySequence::Quit); 93 | gameMenu->addAction(newGameAction); 94 | gameMenu->addAction(joinGameAction); 95 | gameMenu->addAction(saveAction); 96 | gameMenu->addAction(openAction); 97 | gameMenu->addAction(quitAction); 98 | connect(newGameAction, SIGNAL(triggered()), this, SLOT(createNewGame())); 99 | connect(joinGameAction, SIGNAL(triggered()), this, SLOT(joinGame())); 100 | connect(saveAction, SIGNAL(triggered()), this, SLOT(saveGame())); 101 | connect(openAction, SIGNAL(triggered()), this, SLOT(readOldGame())); 102 | connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); 103 | 104 | menuBar()->addMenu(gameMenu); 105 | gameMenu->show(); 106 | 107 | } 108 | 109 | void MainWindow::displayTime(int remainTime) 110 | { 111 | ui->lcdNumber->display(QString::number(remainTime)); 112 | this->repaint(); 113 | //this->update(); 114 | } 115 | 116 | void MainWindow::createNewGame() 117 | { 118 | GameCenter::getInstance()->netServer->initServer(); 119 | GameCenter::getInstance()->newGame(); 120 | waitDialog *waitWindow = new waitDialog; 121 | connect(GameCenter::getInstance()->netServer, SIGNAL(connectBuilt()), waitWindow, SLOT(close())); 122 | connect(GameCenter::getInstance()->netServer, SIGNAL(connectBuilt()), this, SLOT(beginGame())); 123 | waitWindow->show(); 124 | } 125 | 126 | void MainWindow::beginGame() 127 | { 128 | GameCenter::getInstance()->startGame(); 129 | } 130 | 131 | void MainWindow::joinGame() 132 | { 133 | GameCenter::getInstance()->setLocalGamer(1); 134 | ConnectDialog* connectDialog = new ConnectDialog; 135 | connectDialog->show(); 136 | } 137 | 138 | void MainWindow::saveGame() 139 | { 140 | QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), 141 | QDir::homePath(), 142 | tr("存档文件 (*.txt)")); 143 | if(fileName != "") { 144 | QFile file(fileName); 145 | if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) 146 | QMessageBox::critical(this, tr("File permission denied"), tr("无写入权限")); 147 | else file.write(GameCenter::getChessBoard()->getSaveContent().toLocal8Bit().data()); 148 | } 149 | } 150 | 151 | void MainWindow::readOldGame() 152 | { 153 | 154 | QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), QDir::homePath(), tr("存档文件 (*.txt)")); 155 | if(filePath != "") 156 | GameCenter::getInstance()->loadOldGame(filePath); 157 | GameCenter::getInstance()->setSavedGame(true); 158 | waitDialog *waitWindow = new waitDialog; 159 | GameCenter::getInstance()->netServer->initServer(); 160 | connect(GameCenter::getInstance()->netServer, SIGNAL(connectBuilt()), waitWindow, SLOT(close())); 161 | connect(GameCenter::getInstance()->netServer, SIGNAL(connectBuilt()), this, SLOT(beginGame())); 162 | waitWindow->show(); 163 | } 164 | 165 | void MainWindow::gameOver(bool whoseWinner, int winType) 166 | { 167 | if(whoseWinner == GameCenter::getInstance()->localGamer()) { 168 | if(winType == 1) 169 | QMessageBox::information(this, tr("胜利"), tr("将军,you WIN")); 170 | else if(winType == 2) 171 | QMessageBox::information(this, tr("胜利"), tr("对方认输, you WIN")); 172 | else if(winType == 3) 173 | QMessageBox::information(this, tr("胜利"), tr("对方操作超时, you WIN")); 174 | else if(winType == 4) 175 | QMessageBox::information(this, tr("胜利"), tr("对方对将, you WIN")); 176 | } 177 | else { 178 | if(winType == 1) 179 | QMessageBox::information(this, tr("输了"), tr("将军,you Lose")); 180 | else if(winType == 2) 181 | QMessageBox::information(this, tr("输了"), tr("认输, you Lose")); 182 | else if(winType == 3) 183 | QMessageBox::information(this, tr("输了"), tr("操作超时, you Lose")); 184 | else if(winType == 4) 185 | QMessageBox::information(this, tr("输了"), tr("对将, you Lose")); 186 | } 187 | } 188 | 189 | void MainWindow::giveUpGame() 190 | { 191 | GameCenter::getInstance()->netServer->sendLossMessage(2); 192 | emit GameCenter::getInstance()->gameOverSignal(!GameCenter::getInstance()->localGamer(), 2); 193 | } 194 | 195 | void MainWindow::quitGame() 196 | { 197 | 198 | this->close(); 199 | } 200 | 201 | MainWindow::~MainWindow() 202 | { 203 | delete ui; 204 | } 205 | -------------------------------------------------------------------------------- /chessboard.cpp: -------------------------------------------------------------------------------- 1 | #include "chessboard.h" 2 | #include 3 | #include 4 | #include 5 | 6 | inline int abs(int x) { return x > 0 ? x : -x ;} 7 | 8 | ChessBoard::ChessBoard() 9 | { 10 | memset(this->pieces, 0, sizeof(this->pieces)); 11 | for(int i = 0; i < 2; ++i) { 12 | remainingPieces.push_back(new ChessPiece(9*i, 0, Chariot, 1-i)); 13 | //pieces[9*i][0] = new ChessPiece(9*i, 0, Chariot, 1-i); 14 | remainingPieces.push_back(new ChessPiece(9*i, 8, Chariot, 1-i)); 15 | remainingPieces.push_back(new ChessPiece(9*i, 1, Horse, 1-i)); 16 | remainingPieces.push_back(new ChessPiece(9*i, 7, Horse, 1-i)); 17 | remainingPieces.push_back(new ChessPiece(9*i, 2, Elephant, 1-i)); 18 | remainingPieces.push_back(new ChessPiece(9*i, 6, Elephant, 1-i)); 19 | remainingPieces.push_back(new ChessPiece(9*i, 3, Advisor, 1-i)); 20 | remainingPieces.push_back(new ChessPiece(9*i, 5, Advisor, 1-i)); 21 | remainingPieces.push_back(new ChessPiece(9*i, 4, General, 1-i)); 22 | remainingPieces.push_back(new ChessPiece(abs(9*i-2), 1, Cannon, 1-i)); 23 | remainingPieces.push_back(new ChessPiece(abs(9*i-2), 7, Cannon, 1-i)); 24 | remainingPieces.push_back(new ChessPiece(abs(9*i-3), 0, Soldier, 1-i)); 25 | remainingPieces.push_back(new ChessPiece(abs(9*i-3), 8, Soldier, 1-i)); 26 | remainingPieces.push_back(new ChessPiece(abs(9*i-3), 2, Soldier, 1-i)); 27 | remainingPieces.push_back(new ChessPiece(abs(9*i-3), 6, Soldier, 1-i)); 28 | remainingPieces.push_back(new ChessPiece(abs(9*i-3), 4, Soldier, 1-i)); 29 | } 30 | for(unsigned long i = 0; i < this->remainingPieces.size(); ++i) 31 | this->addPiece(this->remainingPieces[i]); 32 | //this->generalPos[0] = new ChessPos(0, 4); 33 | //this->generalPos[1] = new ChessPos(9, 4); 34 | 35 | } 36 | 37 | void ChessBoard::clearChessBoard() 38 | { 39 | for(int i = 0; i < 10; ++i) 40 | for(int j = 0; j < 9; ++j) 41 | if(this->pieces[i][j] != nullptr) { 42 | delete this->pieces[i][j]; 43 | this->pieces[i][j] = nullptr; 44 | } 45 | this->remainingPieces.clear(); 46 | } 47 | 48 | void ChessBoard::addPiece(ChessPiece *piece) 49 | { 50 | this->pieces[piece->x()][piece->y()] = piece; 51 | } 52 | 53 | bool ChessBoard::generalFaced() const 54 | { 55 | ChessPos* generalPos[2]; 56 | memset(generalPos, 0, sizeof(generalPos)); 57 | for(int i = 3; i <= 5; ++i) { 58 | if(pieces[0][i] != nullptr) 59 | if(pieces[0][i]->type() == General) 60 | generalPos[1] = new ChessPos(0, i); 61 | if(pieces[9][i] != nullptr) 62 | if(pieces[9][i]->type() == General) 63 | generalPos[0] = new ChessPos(9, i); 64 | } 65 | if(generalPos[0] != nullptr && generalPos[1] != nullptr) 66 | if(generalPos[0]->y == generalPos[1]->y) { 67 | for(int i = 1; i < 9; ++i) 68 | if(pieces[i][generalPos[0]->y] != nullptr) 69 | return false; 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | void ChessBoard::movePieceTo(ChessPiece* piece, int x, int y) 76 | { 77 | if(piece->canMoveTo(x, y)) { 78 | this->pieces[x][y] = piece; 79 | this->pieces[piece->x()][piece->y()] = nullptr; 80 | piece->moveTo(x, y); 81 | // if(piece->type() == General) 82 | // *(this->generalPos[piece->belong()]) = piece->pos(); 83 | if(this->generalFaced()) 84 | emit GameCenter::getInstance()->gameOverSignal(!piece->belong(), 4); 85 | 86 | 87 | } 88 | emit GameCenter::getInstance()->pieceMoved(); 89 | } 90 | 91 | vector& ChessBoard::getPieces() 92 | { 93 | return this->remainingPieces; 94 | } 95 | 96 | void ChessBoard::movePieceTo(ChessPiece* piece, const ChessPos &pos) 97 | { 98 | this->movePieceTo(piece, pos.x, pos.y); 99 | } 100 | 101 | void ChessBoard::removePieceAt(const ChessPos &pos) 102 | { 103 | if(this->pieces[pos.x][pos.y] != nullptr) { 104 | for(vector::iterator it = remainingPieces.begin(); it != remainingPieces.end(); ++it) 105 | if(*it == this->pieces[pos.x][pos.y]) { 106 | this->remainingPieces.erase(it); 107 | delete this->pieces[pos.x][pos.y]; 108 | this->pieces[pos.x][pos.y] = nullptr; 109 | break; 110 | } 111 | } 112 | } 113 | 114 | QString ChessBoard::getSaveContent() 115 | { 116 | QString tempStr; 117 | vector tempVector; 118 | QTextStream out(&tempStr, QIODevice::WriteOnly | QIODevice::Text); 119 | for(int k = 0; k < 2; ++k) { 120 | if(GameCenter::getInstance()->gamerColor() == 0) { 121 | if(k == 0) 122 | out << "black" << '\n'; 123 | else out << "red" << '\n'; 124 | } 125 | else { 126 | if(k == 0) 127 | out << "red" << '\n'; 128 | else out << "black" << '\n'; 129 | } 130 | for(int i = 0; i < 7; ++i) { 131 | for(vector::iterator it = remainingPieces.begin(); it != remainingPieces.end(); it++) 132 | if((*it)->type() == i + 2 && (*it)->belong() == k) 133 | tempVector.push_back(*it); 134 | out << tempVector.size() << " "; 135 | for(vector::iterator it = tempVector.begin(); it != tempVector.end(); ++it) 136 | out << "<" << (*it)->y() << "," << -(*it)->x() + 9 << "> " ; 137 | out << '\n'; 138 | tempVector.clear(); 139 | } 140 | } 141 | return tempStr; 142 | } 143 | 144 | void ChessBoard::loadSavedFile(QTextStream &in) 145 | { 146 | 147 | QString colorStr; 148 | int pieceNum = 0, x = 0, y = 0; 149 | QString xStr, yStr; 150 | QString piecePosStr; 151 | for(int k = 0; k < 2; ++k) { 152 | in >> colorStr; 153 | if(k == GameCenter::getInstance()->localGamer()) { 154 | if(colorStr == "red") 155 | GameCenter::getInstance()->simplyChangeColor(1); 156 | else if(colorStr == "black") 157 | GameCenter::getInstance()->simplyChangeColor(0); 158 | else throw "Cant not load file, can't get color"; 159 | } 160 | for(int i = 0; i < 7; ++i) { 161 | in >> pieceNum; 162 | for(int j = 0; j < pieceNum; ++j) { 163 | in >> piecePosStr; 164 | xStr = piecePosStr[1]; yStr = piecePosStr[3]; 165 | x = xStr.toInt(); y = yStr.toInt(); 166 | remainingPieces.push_back(new ChessPiece(-y+9, x, PieceType(i+2), k) ); 167 | } 168 | } 169 | 170 | } 171 | for(unsigned long i = 0; i < this->remainingPieces.size(); ++i) 172 | this->addPiece(this->remainingPieces[i]); 173 | 174 | } 175 | 176 | void ChessBoard::removePiece(ChessPiece* piece) 177 | { 178 | for(vector::iterator it = remainingPieces.begin(); it != remainingPieces.end(); ++it) 179 | if(*it == piece) { 180 | this->remainingPieces.erase(it); 181 | break; 182 | } 183 | 184 | for(int i = 0; i < 10; ++i) 185 | for(int j = 0; j < 9; ++j) 186 | if(this->pieces[i][j] == piece) 187 | this->pieces[i][j] = nullptr; 188 | delete piece; 189 | } 190 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /netserver.cpp: -------------------------------------------------------------------------------- 1 | #include "netserver.h" 2 | #include "gamecenter.h" 3 | #include 4 | #include 5 | #include 6 | #include "mainwindow.h" 7 | #include 8 | 9 | NetServer* NetServer::_instance = nullptr; 10 | 11 | NetServer::NetServer(): 12 | tcpServer(nullptr), tcpSocket(nullptr) 13 | { 14 | this->_ipAddress = "127.0.0.1"; 15 | NetServer::_instance = this; 16 | } 17 | 18 | void NetServer::connectServer() 19 | { 20 | if(this->tcpSocket != nullptr) 21 | delete this->tcpSocket; 22 | this->tcpSocket = new QTcpSocket; 23 | this->tcpSocket->connectToHost(QHostAddress(this->_ipAddress), 8731); 24 | connect(this->tcpSocket, SIGNAL(readyRead()), this, SLOT(recvMessage())); 25 | 26 | } 27 | 28 | void NetServer::initServer() 29 | { 30 | if(this->tcpServer != nullptr) 31 | delete this->tcpServer; 32 | this->tcpServer = new QTcpServer; 33 | this->tcpServer->listen(QHostAddress::Any, 8731); 34 | connect(this->tcpServer, SIGNAL(newConnection()), this, SLOT(getConnection())); 35 | } 36 | 37 | void NetServer::getConnection() 38 | { 39 | this->tcpSocket = this->tcpServer->nextPendingConnection(); 40 | this->sendBeginInfo(GameCenter::getInstance()->isSavedGame()); 41 | emit this->connectBuilt(); 42 | //connect(this->tcpSocket, SIGNAL(connected()), this, SLOT(sendBeginInfo())); 43 | connect(this->tcpSocket, SIGNAL(readyRead()), this, SLOT(recvMessage())); 44 | 45 | } 46 | 47 | void NetServer::sendBeginInfo(bool beginWithSavedGame) 48 | { 49 | 50 | QJsonObject beginObject; 51 | beginObject.insert("packageType", 3); 52 | beginObject.insert("hostColor", GameCenter::getInstance()->gamerColor()); 53 | if(beginWithSavedGame) { 54 | beginObject.insert("gameMode", 1); 55 | beginObject.insert("map", GameCenter::getChessBoard()->getSaveContent()); 56 | } 57 | else beginObject.insert("gameMode", 0); 58 | this->sendObjectMessage(beginObject); 59 | } 60 | 61 | ChessPos getPosFromJsonObject(const QJsonObject& object) 62 | { 63 | QJsonValue xValue = object.value("x"); 64 | QJsonValue yValue = object.value("y"); 65 | return ChessPos(xValue.toInt(), yValue.toInt()); 66 | } 67 | 68 | void NetServer::sendMoveMessage(ChessPos oldPos, ChessPos newPos) 69 | { 70 | QJsonObject moveMessageObject; 71 | moveMessageObject.insert("packageType", 1); 72 | QJsonObject fromObject, toObject; 73 | fromObject.insert("x", oldPos.x); fromObject.insert("y", oldPos.y); 74 | toObject.insert("x", newPos.x); toObject.insert("y",newPos.y); 75 | moveMessageObject.insert("from", fromObject); 76 | moveMessageObject.insert("to", toObject); 77 | this->sendObjectMessage(moveMessageObject); 78 | } 79 | 80 | void NetServer::sendFeedBackPackage(int statusType) 81 | { 82 | QJsonObject returnObject; 83 | returnObject.insert("packageType", 0); 84 | returnObject.insert("result", statusType); 85 | this->sendObjectMessage(returnObject); 86 | } 87 | 88 | void NetServer::sendLossMessage(int loseType) 89 | { 90 | QJsonObject lossMessageObject; 91 | lossMessageObject.insert("packageType", 2); 92 | lossMessageObject.insert("loseType", loseType); 93 | this->sendObjectMessage(lossMessageObject); 94 | } 95 | 96 | 97 | 98 | void NetServer::recvMessage() 99 | { 100 | QByteArray getbuffer; 101 | QJsonDocument getDocument = this->readJsonDocument(); 102 | QJsonObject rootObject = getDocument.object(); 103 | #ifdef DEBUG_MODE 104 | qDebug() << "recive " << rootObject; 105 | #endif 106 | QJsonValue packageType = rootObject.value("packageType"); 107 | int typeValue = packageType.toInt(); 108 | try { 109 | if(typeValue == 0) { 110 | QJsonValue resultValue = rootObject.value("result"); 111 | int resultInt = resultValue.toInt(); 112 | if(resultInt == 0) 113 | emit this->getFeedBack(); 114 | } 115 | else if(typeValue == 1) { 116 | QJsonValue fromValue = rootObject.value("from"); QJsonValue toValue = rootObject.value("to"); 117 | ChessPos fromPos = getPosFromJsonObject(fromValue.toObject()), toPos = getPosFromJsonObject(toValue.toObject()); 118 | MainWindow::getInstance()->getGraphicsScene()->movePieceItemTo(fromPos, toPos); 119 | this->sendFeedBackPackage(0); 120 | } 121 | else if(typeValue == 2) { 122 | QJsonValue winTypeValue = rootObject.value("loseType"); 123 | int winType = winTypeValue.toInt(); 124 | emit GameCenter::getInstance()->gameOverSignal(GameCenter::getInstance()->localGamer(), winType); 125 | } 126 | else if(typeValue == 3) { 127 | QJsonValue gameModeValue = rootObject.value("gameMode"); 128 | int gameMode = gameModeValue.toInt(); 129 | if(gameMode == 0) { 130 | QJsonValue hostColorValue = rootObject.value("hostColor"); 131 | bool hostColor = hostColorValue.toBool(); 132 | GameCenter::getInstance()->setGamerColor(!hostColor); 133 | GameCenter::getInstance()->startGame(); 134 | } 135 | else { 136 | QJsonValue mapValue = rootObject.value("map"); 137 | QString map = mapValue.toString(); 138 | QTextStream in(&map, QIODevice::ReadOnly | QIODevice::Text); 139 | GameCenter::getChessBoard()->clearChessBoard(); 140 | GameCenter::getChessBoard()->loadSavedFile(in); 141 | MainWindow::getInstance()->changeNewScene(); 142 | } 143 | GameCenter::getInstance()->startGame(); 144 | } 145 | } catch (const char* msg) { 146 | qDebug() << msg; 147 | } 148 | 149 | 150 | } 151 | 152 | 153 | 154 | int NetServer::readIntoBuffer(QByteArray& buffer, int len) 155 | { 156 | int leftBytes = len, tempLen; 157 | QByteArray tempBuffer, result; 158 | char *tempStr; 159 | int i = 0; 160 | while(leftBytes > 0) { 161 | tempStr = new char[leftBytes+1]; 162 | memset(tempStr, 0, leftBytes + 1); 163 | tempLen = this->tcpSocket->read(tempStr, leftBytes); 164 | leftBytes -= tempLen; 165 | result.append(tempStr); 166 | /* 167 | if(leftBytes > 0) { 168 | if(WebIO::getSocket()->waitForReadyRead(30000) == false) 169 | qDebug() << "接受超时"; 170 | } 171 | */ 172 | i++; 173 | if(i > 1000000) { 174 | qDebug() << this->tcpSocket->errorString(); 175 | return -1; 176 | 177 | } 178 | } 179 | buffer = std::move(result); 180 | #ifdef DEBUG_MODE 181 | qDebug() << buffer; 182 | #endif 183 | return buffer.length(); 184 | } 185 | 186 | int NetServer::getIntFromBuffer(const QByteArray &buffer) 187 | { 188 | QDataStream tempStream(buffer); 189 | tempStream.setByteOrder(QDataStream::BigEndian); 190 | int x; 191 | tempStream >> x; 192 | return x; 193 | } 194 | 195 | QJsonDocument NetServer::readJsonDocument() 196 | { 197 | QByteArray byteBuffer = this->tcpSocket->read(4); 198 | int len = this->getIntFromBuffer(byteBuffer); 199 | int status = this->readIntoBuffer(byteBuffer, len); 200 | QJsonDocument tempJson; 201 | if(status > 0) 202 | tempJson = QJsonDocument::fromJson(byteBuffer); 203 | return tempJson; 204 | } 205 | 206 | NetServer::~NetServer() 207 | { 208 | 209 | } 210 | 211 | void NetServer::setHostIp(const QString& ipAddress) 212 | { 213 | this->_ipAddress = ipAddress; 214 | } 215 | 216 | int NetServer::sendMessage(const QByteArray& message) 217 | { 218 | QDataStream dataStream(this->tcpSocket); 219 | dataStream.setByteOrder(QDataStream::BigEndian); 220 | dataStream << message.length(); 221 | int leftBytes = message.length(), tempLen; 222 | while(leftBytes > 0) { 223 | tempLen = this->tcpSocket->write(message); 224 | if(tempLen == -1) { 225 | qDebug() << "errorCode " << this->tcpSocket->error(); 226 | qDebug() << this->tcpSocket->errorString(); 227 | if(this->tcpSocket->error() == QTcpSocket::UnknownSocketError) { 228 | //socket->connectToHost(QHostAddress("35.194.106.246"), 8333); 229 | } 230 | } 231 | 232 | leftBytes -= tempLen; 233 | } 234 | return 0; 235 | } 236 | 237 | int NetServer::sendObjectMessage(const QJsonObject &object) 238 | { 239 | #ifdef DEBUG_MODE 240 | qDebug() << "state" << this->tcpSocket->state(); 241 | qDebug() << "send message" << object; 242 | #endif 243 | QJsonDocument jsonDocument(object); 244 | QByteArray message = jsonDocument.toJson(QJsonDocument::Compact); 245 | return this->sendMessage(message); 246 | } 247 | -------------------------------------------------------------------------------- /graphicsscene.cpp: -------------------------------------------------------------------------------- 1 | #include "graphicsscene.h" 2 | #include 3 | #include "gamecenter.h" 4 | #include "chessboard.h" 5 | #include 6 | #include 7 | 8 | 9 | GraphicsScene::GraphicsScene(QObject *parent) : 10 | QGraphicsScene(parent), selectedPieceItem(nullptr), willBeEatenPiece(nullptr), backgroundItem(nullptr) 11 | { 12 | QPixmap backgroundPixmap; 13 | //backgroundPixmap.setDevicePixelRatio(2); 14 | //qDebug() << backgroundPixmap.devicePixelRatio(); 15 | backgroundPixmap.load(":/images/chessboard.png"); 16 | 17 | //qDebug() << "size " << backgroundPixmap.size(); 18 | #ifdef LOW_DPI 19 | backgroundPixmap.setDevicePixelRatio(2); 20 | #else 21 | backgroundPixmap.setDevicePixelRatio(1); 22 | #endif 23 | //qDebug() << "size " << backgroundPixmap.size() << "\n" << backgroundPixmap.devicePixelRatio(); 24 | backgroundItem = new QGraphicsPixmapItem(backgroundPixmap); 25 | this->addItem(backgroundItem); 26 | for(auto it = GameCenter::getPieces().begin(); it != GameCenter::getPieces().end(); it++) { 27 | ChessPiece* tempPiece = *it; 28 | this->addItem(getPieceItem(tempPiece)); 29 | } 30 | connect(this, SIGNAL(selectionChanged()), this, SLOT(modifySelection())); 31 | this->setSelectable(); 32 | } 33 | 34 | 35 | ChessPos GraphicsScene::posFromPixel(const QPointF& pos) 36 | { 37 | double xDis = (pos.y() - topLimit) / squareLen, yDis = (pos.x() - leftLimit) / squareLen ; 38 | int posX = abs(9 * GameCenter::getInstance()->localGamer() - static_cast(floor(xDis)) ); 39 | int posY = abs(8 * GameCenter::getInstance()->localGamer() - static_cast(floor(yDis) ) ); 40 | return ChessPos(posX, posY); 41 | } 42 | 43 | bool GraphicsScene::inChessboard(const QPointF& pos) 44 | { 45 | return (pos.x() >= leftLimit && pos.x() <= rightLimit && pos.y() >= topLimit && pos.y() <= bottomLimit); 46 | } 47 | 48 | QPointF GraphicsScene::posFromXY(const ChessPos& pos) 49 | { 50 | return QPointF(abs(8 * GameCenter::getInstance()->localGamer() - pos.y) * squareLen + leftPointx, abs(9 * GameCenter::getInstance()->localGamer() - pos.x) * squareLen + leftPointy); 51 | } 52 | 53 | PieceItem* GraphicsScene::getPieceItem(ChessPiece* chesspiece) 54 | { 55 | QString filePath = ":/images/" + ChessPiece::pieceNames[chesspiece->type() - 2]; 56 | bool gamerColor = GameCenter::getInstance()->gamerColor(); 57 | 58 | if(chesspiece->belong() != GameCenter::getInstance()->localGamer()) 59 | gamerColor = !gamerColor; 60 | 61 | QString gamerName = QString::number(gamerColor); 62 | filePath += "_" + gamerName; 63 | 64 | 65 | QPixmap piecePixmap(filePath); 66 | #ifdef LOW_DPI 67 | piecePixmap.setDevicePixelRatio(1); 68 | #else 69 | //piecePixmap.setDevicePixelRatio(0.5); 70 | piecePixmap = piecePixmap.scaled(piecePixmap.width() * 2, piecePixmap.height() * 2); 71 | #endif 72 | PieceItem *pieceItem = new PieceItem(chesspiece, piecePixmap); 73 | //pieceItem->setFlag(QGraphicsItem::ItemIsSelectable, true); 74 | pieceItem->setPos(this->posFromXY(chesspiece->pos())); 75 | this->pieceItems.push_back(pieceItem); 76 | //this->addItem(pieceItem); 77 | return pieceItem; 78 | } 79 | 80 | PieceItem* GraphicsScene::getExistedItem(ChessPiece* chesspiece) 81 | { 82 | for(list::iterator it = this->pieceItems.begin(); it!=pieceItems.end(); ++it) 83 | if((*it)->chessPiece() == chesspiece) 84 | return (*it); 85 | return nullptr; 86 | } 87 | 88 | void GraphicsScene::modifySelection() 89 | { 90 | QList selectItems = this->selectedItems(); 91 | if(selectItems.size() > 0) { 92 | PieceItem* selectedItem = static_cast(selectItems.first()); 93 | this->selectedPieceItem = selectedItem; 94 | for(list::iterator it = this->pieceItems.begin(); it!=pieceItems.end(); ++it) { 95 | if(*it != selectedItem) { 96 | (*it)->setFlag(QGraphicsItem::ItemIsSelectable, false); 97 | } 98 | } 99 | } 100 | else { 101 | this->setSelectable(); 102 | /* 103 | for(list::iterator it = this->pieceItems.begin(); it!=pieceItems.end(); ++it) 104 | (*it)->setFlag(QGraphicsItem::ItemIsSelectable, true); 105 | */ 106 | this->selectedPieceItem = nullptr; 107 | } 108 | } 109 | 110 | void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) 111 | { 112 | //qDebug() << "pos " << mouseEvent->scenePos().x() << " " << mouseEvent->scenePos().y(); 113 | // qDebug() << "is in chessboard " << this->inChessboard(mouseEvent->scenePos()); 114 | 115 | QGraphicsScene::mouseMoveEvent(mouseEvent); 116 | } 117 | 118 | void GraphicsScene::removePieceItem(PieceItem* item) 119 | { 120 | this->removeItem(item); 121 | for(list::iterator it = pieceItems.begin(); it != pieceItems.end(); ++it) 122 | if(*it == item) { 123 | pieceItems.erase(it); 124 | break; 125 | } 126 | } 127 | 128 | void GraphicsScene::movePieceItemTo(ChessPos oldPos, ChessPos newPos) 129 | { 130 | ChessPiece *selectedPiece = GameCenter::getChessBoard()->at(oldPos); 131 | PieceItem* eaterItem = this->getExistedItem(selectedPiece); 132 | ChessPiece *chesspiece = GameCenter::getChessBoard()->at(newPos); 133 | if(chesspiece != nullptr) { 134 | PieceItem* pieceItem = this->getExistedItem(chesspiece); 135 | GameCenter::getInstance()->roundEnd(); 136 | this->removePieceItem(pieceItem); 137 | GameCenter::getInstance()->eatPiece(selectedPiece, chesspiece); 138 | eaterItem->setPos(this->posFromXY(selectedPiece->pos())); 139 | } 140 | else { 141 | GameCenter::getInstance()->roundEnd(); 142 | GameCenter::getChessBoard()->movePieceTo(selectedPiece, newPos); 143 | eaterItem->setPos(this->posFromXY(newPos)); 144 | } 145 | this->setSelectable(); 146 | } 147 | 148 | void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) 149 | { 150 | //this->setSelectable(); 151 | bool movedFlag = 0; 152 | if(event->button() == Qt::LeftButton) { 153 | if(pieceSelected()) { 154 | QGraphicsItem *tempItem = this->itemAt(event->scenePos(), QTransform()); 155 | PieceItem* eaterItem = this->selectedPieceItem; 156 | ChessPiece* selectedPiece = eaterItem->chessPiece(); 157 | if(tempItem != this->backgroundItem && tempItem != nullptr) { 158 | PieceItem* pieceItem = static_cast(tempItem); 159 | //ChessPos mousePos = this->posFromPixel(event->scenePos()); 160 | //ChessPiece* chesspiece = GameCenter::getChessBoard()->at(mousePos); 161 | ChessPiece* chesspiece = pieceItem->chessPiece(); 162 | if(chesspiece != nullptr) { 163 | if(chesspiece != eaterItem->chessPiece()) { 164 | if(selectedPiece->canMoveTo(chesspiece->pos())) { 165 | //selectedPiece->moveTo(chesspiece->pos()); 166 | GameCenter::getInstance()->roundEnd(); 167 | this->removePieceItem(pieceItem); 168 | GameCenter::getInstance()->netServer->sendMoveMessage(selectedPiece->pos(), chesspiece->pos()); 169 | GameCenter::getInstance()->eatPiece(selectedPiece, chesspiece); 170 | 171 | eaterItem->setPos(this->posFromXY(selectedPiece->pos())); 172 | eaterItem->setSelected(false); 173 | 174 | movedFlag = 1; 175 | //this->willBeEatenPiece = chesspiece; 176 | } 177 | } 178 | } 179 | } 180 | else if(this->inChessboard(event->scenePos()) ) { 181 | ChessPos emptyPos = this->posFromPixel(event->scenePos()); 182 | if(selectedPiece->canMoveTo(emptyPos)) { 183 | GameCenter::getInstance()->roundEnd(); 184 | //selectedPiece->moveTo(emptyPos); 185 | GameCenter::getInstance()->netServer->sendMoveMessage(selectedPiece->pos(), emptyPos); 186 | GameCenter::getChessBoard()->movePieceTo(selectedPiece, emptyPos); 187 | eaterItem->setPos(this->posFromXY(emptyPos)); 188 | eaterItem->setSelected(false); 189 | 190 | movedFlag = 1; 191 | } 192 | } 193 | } 194 | 195 | } 196 | if(!movedFlag) 197 | QGraphicsScene::mousePressEvent(event); 198 | 199 | } 200 | 201 | void GraphicsScene::setSelectable() 202 | { 203 | if(!GameCenter::getInstance()->isGameOver() && GameCenter::getInstance()->whoseRound() == GameCenter::getInstance()->localGamer()) { 204 | for(list::iterator it = this->pieceItems.begin(); it != pieceItems.end(); it++) 205 | (*it)->setFlag(QGraphicsItem::ItemIsSelectable, (*it)->chessPiece()->belong() == GameCenter::getInstance()->whoseRound()); 206 | } 207 | else for(list::iterator it = this->pieceItems.begin(); it != pieceItems.end(); it++) 208 | (*it)->setFlag(QGraphicsItem::ItemIsSelectable, false); 209 | } 210 | 211 | void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) 212 | { 213 | /* 214 | if(mouseEvent->button() == Qt::LeftButton) { 215 | 216 | if(this->willBeEatenPiece != nullptr) { 217 | //ChessPos mousePos = this->posFromPixel(mouseEvent->scenePos()); 218 | //ChessPiece* chesspiece = GameCenter::getChessBoard()->at(mousePos); 219 | QGraphicsItem *tempItem = this->itemAt(mouseEvent->scenePos(), QTransform()); 220 | if(tempItem != this->backgroundItem) { 221 | PieceItem* pieceItem = static_cast(tempItem); 222 | if(pieceItem != this->selectedPieceItem) { 223 | ChessPiece* chesspiece = pieceItem->chessPiece(); 224 | if(chesspiece != nullptr && chesspiece == this->willBeEatenPiece) { 225 | ChessPiece* selectedPiece = selectedPieceItem->chessPiece(); 226 | selectedPiece->moveTo(chesspiece->pos()); 227 | this->removePieceItem(pieceItem); 228 | 229 | } 230 | 231 | } 232 | } 233 | this->willBeEatenPiece = nullptr; 234 | } 235 | 236 | 237 | } 238 | */ 239 | QGraphicsScene::mouseReleaseEvent(mouseEvent); 240 | } 241 | --------------------------------------------------------------------------------