diff --git a/README.md b/README.md index 4f5ca0b..c0bb7f1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,206 @@ -# COMP2012H_Project -UST Landlord Game +# USTlandlord Game + +By COMP2012H 2020FALL Group21, ZHENG Hantao, SU Hong, LU Weiqi, GUO Bingcan + +### 0. Installation +Windows version of this game is in [COMP-2012H repository](https://github.com/williamlus/COMP-2012H). Download that repository and double click [start.exe](https://github.com/williamlus/COMP-2012H/blob/main/start.exe) to start the game. + +![USTlord 2022_11_5 19_42_51](https://user-images.githubusercontent.com/67042315/200118232-d7e20a93-01f5-4643-b3e9-708ccf1ea124.png) + +### 1. Introduction + +Dou dizhu is described as easy to learn but hard to master, requiring mathematical and strategic thinking as well as carefully planned execution. Suits are irrelevant in playing doudizhu. Players can easily play the game with a set of dou dizhu playing cards, without the suits printed on the cards. Less popular variations of the game do exist in China, such as four-player and five-player dou dizhu played with two packs of cards. + +Making a Qt GUIbased game has moderate difficulty and can be expanded with many other features such as multi-player, background music and even a chat box for players to communicate with their teammates and opponents, while the project is relatively s itable to apply beginner’slevel OOP to achieve. + +### 2. Overview + +Apply OOP to develop a landlord game with GUI based on QT with followingfeatures: + +1. A computer “AI” player written based on simple game logic as human + +2. Multip-player mode, which is the most important part of the game. + +3. Background music and fancy GUI. + + + +**Basic Rules and Strateges** + +1.**A player can deal with an unrelated or useless card by making it the kicker card.** + +2.**Rocket and bomb are the ultimate weapons in the game.** + +If they either is in one's hand, one should make full use of it when time comes. If players do not possess high confidence in winning, they may think twice about dealing a rocket or bomb, because once the dealt, the risk stake of the round will be doubled (players will either win or lose double) with each rocket or bomb dealt. + +3.**Peasants must co-operate to fight against the landlord.** + +For example, since the two peasants come after one another, the first peasant might play a low single card if the second peasant has a sole card left. +(Reference: https://en.wikipedia.org/wiki/Dou_dizhu#Rules) + + + + +### 3. Design + +* **Class Design** + + Console Game: + + * Board + * Cards + * CardsGroup + * CardsType + * CurrentPattern + * Deck + * Player + + Networking: + + * Datapackage + * ServerWindow + + GUI: + + * playerwindow + * mainwindow + * serverwindow + * clientwindow + + + +* **AI Player Design** + + AI Logic: + + `const CardsGroup choose_hint(const CurrentPattern& cp);` + + * AI player with some common sense strategies: + + * if the AI player is the first one to play or the CurrentPattern is played by himself + he will play cards with the following logic: + + First find the smallest card in hand, + if it is inside a bomb, then DO NOT play it, and find the second smallest one unless he only has one card left + if not, then if this card is inside any other cards_combination, then just play this combination + otherwise just play this SINGLE card + + * if the AI player is landlord, then try to beat everyone + + * if the AI player is farmer, then beat landlord all the time + + * if the CurrentPattern is played by another farmer + Only give cards in these cases: + + * the AI player can directly win the game + * the partner played a small SINGLE or PAIR + + + + `bool want_landlord() override;//choose to be landlord or not automatically` + + + * the probability of choosing lord is determined by how good the cards in hand are + + The evaluation is basically determined by the number of cards_combination + + The cards_combination considered here are: + + TRIO,BOMB, ROCKET + + +* **UI Design** + +1. Distribute cards effect. +2. Show buttons according to game process. +3. Info bar displays game process to players. +4. Play cards effect and view other players' cards. +5. Serverwindow and Clientwindow design. + + + +* **Networking Design** + +**Transfer principle:** + Using Transmission Control Protocol (TCP)\ + The one created room will simultaneously be SERVER and CLIENT, the rest two are just CLIENT\ + Before sending and after receiving the raw_data, the information is stored in user_defined object: **Datapackage**\ + For more details of the usages of DataPackage, please refer to `DataPackage.h` + + + class DataPackage + { + public: + enum Action{ + NONE=-1, + GIVE_ID, + CONFIRM_READY, + DEAL_CARDS, + CHOOSE_LANDLORD, + LANDLORD_BONUS, + PLAY_CARDS, + ANNOUNCE, + CHAT, + EXCEPTION + }; + + struct Content{ + static const QString REQUEST; + static const QString ACCEPT; + static const QString REJECT; + static const QString BE_LANDLORD; + static const QString DO_NOT_PLAY; + static const QString WIN_GAME; + static const QString LOSE_GAME; + static const QString END_GAME; + static const QString QUIT; + }; + + public: + + int sender; + int actioner; + Action action; + QString content; + + }; + + +**DataPackage** is equivalent to a formatted QString: "sender:`(int) sender_id`;actioner:`(int) actioner_id`;Action;Content" + +Before sending **DataPackage**, we will first convert it to the formatted QString, then serialize it to QByteArray + +After receiving **raw_data(QByteArray)**, we will first convert it to QString, then convert it to DataPackage + + + +### 4. UI Display + +Main window + +Single Player game: + +* Choose landlord: +* Player cards: +* View hints: +* Game over: + +Multiplayer Player game: + + + +### 5. Summary + + **This project design is a comprehensive OOP program design. The development of USTlord game involves object-oriented programming, data structure, TCP networking and GUI design. We encounted and overcame quite a lot problems due to lack of knowledge and communication problems of multi-person collaboration. The experience we gain are as follows:** + +- Deenpen the understanding of object-oriented programming + +Different from process-oriented program,object-oriented programming involves class, object, inheritance, polymorphism etc., which greatly enhance the resuability of the codes, and also provide convinience for deleveloping projects in team. + +- Modern development concept + +In a program involving multiple modules, the more modern development method is encapsulation. After determining the structure of the program, encapsulate the different modules. On the one hand, it is easy to combine and use the modules. On the other hand, the clear interfaces are also the cornerstone of efficient cooperation. + +- Development tools and multi-person collaboration + +Modern program development is not alone. Multi-person remote collaboration and project management are very important parts of program specification development. The use of Git for version control and project management in this program design has brought great convenience to the development of the program, and also allowed us to deepen our understanding of the actual software engineering process. diff --git a/USTlord_final/USTlord_final.pro b/USTlord_final/USTlord_final2.pro similarity index 82% rename from USTlord_final/USTlord_final.pro rename to USTlord_final/USTlord_final2.pro index aee39c8..e255c97 100644 --- a/USTlord_final/USTlord_final.pro +++ b/USTlord_final/USTlord_final2.pro @@ -1,4 +1,4 @@ -QT += core gui network +QT += core gui network multimedia greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -22,7 +22,8 @@ SOURCES += \ source/CurrentPattern.cpp \ source/Deck.cpp \ source/Player.cpp \ - source/DataPackage.cpp + source/datapackage.cpp\ + source/CardPicture.cpp HEADERS += \ clientwindow.h \ @@ -37,7 +38,8 @@ HEADERS += \ source/CurrentPattern.h \ source/Deck.h \ source/Player.h \ - source/DataPackage.h + source/datapackage.h\ + source/CardPicture.h FORMS += \ clientwindow.ui \ @@ -49,3 +51,7 @@ FORMS += \ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + img.qrc \ + music.qrc diff --git a/USTlord_final/clientwindow.cpp b/USTlord_final/clientwindow.cpp index 5f1119d..1995072 100644 --- a/USTlord_final/clientwindow.cpp +++ b/USTlord_final/clientwindow.cpp @@ -1,5 +1,6 @@ #include "clientwindow.h" #include "ui_clientwindow.h" +#include ClientWindow::ClientWindow(QWidget *parent) : QMainWindow(parent), @@ -8,6 +9,17 @@ ClientWindow::ClientWindow(QWidget *parent) : ui->setupUi(this); } +void ClientWindow::closeEvent(QCloseEvent *event){ + if(socket){ + socket->close(); + socket->deleteLater(); + qDebug() << "Closing socket"; + } + this->parentWidget()->show(); + emit close_window(); + event->accept(); +} + ClientWindow::~ClientWindow() { delete ui; @@ -15,29 +27,83 @@ ClientWindow::~ClientWindow() void ClientWindow::handleStateChanged(QAbstractSocket::SocketState state) { - + if(state==QAbstractSocket::SocketState::UnconnectedState){ + if(play_window){ + play_window->close(); + } + socket->close(); + ui->listWidget_dialogs->addItem("Disconnected from server"); + ui->listWidget_dialogs->addItem("Closing the socket"); + } } void ClientWindow::handle_server_message() { + ui->listWidget_dialogs->addItem("Handle server msg"); if(socket){ QByteArray arr=socket->readAll(); ui->listWidget_dialogs->addItem(QString::fromStdString(arr.toStdString())); DataPackage data=DataPackage::parse(arr); + ui->listWidget_dialogs->addItem("Received from server:"+data.to_string()); +// qDebug()<< "data.action==DataPackage::Action::GIVE_ID?";///// +// qDebug() << (data.action==DataPackage::Action::GIVE_ID);////////// if(data.action==DataPackage::Action::GIVE_ID){ + QMessageBox::information(this,"Start","Let's start!",QMessageBox::Ok,QMessageBox::Ok); id=data.content.toInt(); - } - if(play_window){ - play_window->receive_from_client(DataPackage::parse(arr)); + ui->listWidget_dialogs->addItem("data.conent="+data.content);/////// + DataPackage data_to_send(id,id,DataPackage::GIVE_ID,ui->lineEdit_name->text()+"#"+QString::number(id)); + send_to_server(data_to_send); + }//////// + else if(data.action==DataPackage::Action::CONFIRM_READY){ + QStringList names=data.content.split(QLatin1Char(','),Qt::SkipEmptyParts); + QVector names_vec{}; + for(int i=0;ilistWidget_dialogs->addItem("You exit the room"); + disconnect(play_window,&PlayWindow::send_to_client,this,&ClientWindow::received_from_playwindow); + qDebug() << "exit the room"; + }); + play_window->show();///////// +// this->hide(); + DataPackage data_to_send(id,-1,DataPackage::Action::CONFIRM_READY,DataPackage::Content::ACCEPT); + send_to_server(data_to_send); + }///////// + else if(play_window){ + ui->listWidget_dialogs->addItem("send msg to playwindow"+data.to_string());///////////// + play_window->receive_from_client(data); } } } void ClientWindow::send_to_server(DataPackage data){ - + ui->listWidget_dialogs->addItem("Send to server"+data.to_string());////// + qDebug() << "Send to server"+data.to_string(); + if(socket){ + QByteArray arr=data.serialize(); + socket->write(arr); + } } void ClientWindow::received_from_playwindow(DataPackage data){ + if(socket){ + this->send_to_server(data); + } +} +void ClientWindow::set_port(QString port) +{ + ui->lineEdit_server_port->setText(port); +} + +void ClientWindow::set_serverIP(QString ip) +{ + ui->lineEdit_serverIP->setText(ip); } void ClientWindow::on_pushButton_join_server_clicked() @@ -62,5 +128,5 @@ void ClientWindow::on_pushButton_stop_joining_clicked() void ClientWindow::on_pushButton_quit_clicked() { - + this->close(); } diff --git a/USTlord_final/clientwindow.h b/USTlord_final/clientwindow.h index 8f32c91..6efacea 100644 --- a/USTlord_final/clientwindow.h +++ b/USTlord_final/clientwindow.h @@ -3,6 +3,7 @@ #include #include +#include #include "source/datapackage.h" #include "playwindow.h" @@ -16,26 +17,55 @@ class ClientWindow : public QMainWindow public: explicit ClientWindow(QWidget *parent = nullptr); + + void closeEvent(QCloseEvent *event) override; + //Override closeEvent + //Show MainWindow when ClientWindow is closed + ~ClientWindow(); public slots: void handleStateChanged(QAbstractSocket::SocketState state); + //Close the ClientWindow whenever the QTcpSocket is disconnected from the QTcpServer + void handle_server_message(); + //Receive the QByteArray from server and translate it into DataPackage + //Perform actions according to DataPackage instructions from QTcpServer + //Send back DataPackage to QTcpServer if required + //Pass the DataPackage to PlayWindow + void send_to_server(DataPackage data); + //Transform the DataPackage into QByteArray + //Send the QByteArray to QTcpServer + void received_from_playwindow(DataPackage data); + //Receive DataPackage emitted from PlayWindow + //And call send_to_server() to send the data to QTcpServer -private slots: + void set_port(QString port); + //Set the port in ui line edit + + void set_serverIP(QString ip); + //Set the Server IP Address in ui line edit + +public slots: void on_pushButton_join_server_clicked(); + //Create the QTcpSocket and join the server void on_pushButton_stop_joining_clicked(); + //Close the QTcpSocket void on_pushButton_quit_clicked(); + //Close the ClientWindow + +signals: + void close_window(); private: Ui::ClientWindow *ui; - QTcpSocket *socket{nullptr}; - PlayWindow *play_window{nullptr}; - int id{-1}; + QTcpSocket *socket{nullptr};//Used to communicate with ServerWindow + PlayWindow *play_window{nullptr};//Create a PlayWindow when the game start + int id{-1};//This player id }; #endif // CLIENTWINDOW_H diff --git a/USTlord_final/clientwindow.ui b/USTlord_final/clientwindow.ui index 59fe1f9..ad7f86f 100644 --- a/USTlord_final/clientwindow.ui +++ b/USTlord_final/clientwindow.ui @@ -10,12 +10,6 @@ 600 - - - 0 - 0 - - MainWindow @@ -25,83 +19,101 @@ 40 20 - 711 - 501 + 704 + 481 - + - + + + + + Server IP: + + + + + + + 127.0.0.1 + + + + + + + Port: + + + + + + + 2012 + + + + + + + Name + + + + + + + Desmond + + + + - + - - - - - Server IP: - - - - - - - 127.0.0.1 - - - - - - - Port: - - - - - - - 2012 - - - - + - + - - - Join - - + + + + + Join + + + + + + + Stop + + + + + + + Quit + + + + - + - Stop + Dialog: - - - Quit - - + - - - - Dialog: - - - - - - diff --git a/resources/cards/S3.png b/USTlord_final/images/1.png similarity index 100% rename from resources/cards/S3.png rename to USTlord_final/images/1.png diff --git a/resources/cards/S12.png b/USTlord_final/images/10.png similarity index 100% rename from resources/cards/S12.png rename to USTlord_final/images/10.png diff --git a/resources/cards/S13.png b/USTlord_final/images/11.png similarity index 100% rename from resources/cards/S13.png rename to USTlord_final/images/11.png diff --git a/resources/cards/S14.png b/USTlord_final/images/12.png similarity index 100% rename from resources/cards/S14.png rename to USTlord_final/images/12.png diff --git a/resources/cards/S15.png b/USTlord_final/images/13.png similarity index 100% rename from resources/cards/S15.png rename to USTlord_final/images/13.png diff --git a/resources/cards/H3.png b/USTlord_final/images/14.png similarity index 100% rename from resources/cards/H3.png rename to USTlord_final/images/14.png diff --git a/resources/cards/H4.png b/USTlord_final/images/15.png similarity index 100% rename from resources/cards/H4.png rename to USTlord_final/images/15.png diff --git a/resources/cards/H5.png b/USTlord_final/images/16.png similarity index 100% rename from resources/cards/H5.png rename to USTlord_final/images/16.png diff --git a/resources/cards/H6.png b/USTlord_final/images/17.png similarity index 100% rename from resources/cards/H6.png rename to USTlord_final/images/17.png diff --git a/resources/cards/H7.png b/USTlord_final/images/18.png similarity index 100% rename from resources/cards/H7.png rename to USTlord_final/images/18.png diff --git a/resources/cards/H8.png b/USTlord_final/images/19.png similarity index 100% rename from resources/cards/H8.png rename to USTlord_final/images/19.png diff --git a/resources/cards/S4.png b/USTlord_final/images/2.png similarity index 100% rename from resources/cards/S4.png rename to USTlord_final/images/2.png diff --git a/resources/cards/H9.png b/USTlord_final/images/20.png similarity index 100% rename from resources/cards/H9.png rename to USTlord_final/images/20.png diff --git a/resources/cards/H10.png b/USTlord_final/images/21.png similarity index 100% rename from resources/cards/H10.png rename to USTlord_final/images/21.png diff --git a/resources/cards/H11.png b/USTlord_final/images/22.png similarity index 100% rename from resources/cards/H11.png rename to USTlord_final/images/22.png diff --git a/resources/cards/H12.png b/USTlord_final/images/23.png similarity index 100% rename from resources/cards/H12.png rename to USTlord_final/images/23.png diff --git a/resources/cards/H13.png b/USTlord_final/images/24.png similarity index 100% rename from resources/cards/H13.png rename to USTlord_final/images/24.png diff --git a/resources/cards/H14.png b/USTlord_final/images/25.png similarity index 100% rename from resources/cards/H14.png rename to USTlord_final/images/25.png diff --git a/resources/cards/H15.png b/USTlord_final/images/26.png similarity index 100% rename from resources/cards/H15.png rename to USTlord_final/images/26.png diff --git a/resources/cards/D3.png b/USTlord_final/images/27.png similarity index 100% rename from resources/cards/D3.png rename to USTlord_final/images/27.png diff --git a/resources/cards/D4.png b/USTlord_final/images/28.png similarity index 100% rename from resources/cards/D4.png rename to USTlord_final/images/28.png diff --git a/resources/cards/D5.png b/USTlord_final/images/29.png similarity index 100% rename from resources/cards/D5.png rename to USTlord_final/images/29.png diff --git a/resources/cards/S5.png b/USTlord_final/images/3.png similarity index 100% rename from resources/cards/S5.png rename to USTlord_final/images/3.png diff --git a/resources/cards/D6.png b/USTlord_final/images/30.png similarity index 100% rename from resources/cards/D6.png rename to USTlord_final/images/30.png diff --git a/resources/cards/D7.png b/USTlord_final/images/31.png similarity index 100% rename from resources/cards/D7.png rename to USTlord_final/images/31.png diff --git a/resources/cards/D8.png b/USTlord_final/images/32.png similarity index 100% rename from resources/cards/D8.png rename to USTlord_final/images/32.png diff --git a/resources/cards/D9.png b/USTlord_final/images/33.png similarity index 100% rename from resources/cards/D9.png rename to USTlord_final/images/33.png diff --git a/resources/cards/D10.png b/USTlord_final/images/34.png similarity index 100% rename from resources/cards/D10.png rename to USTlord_final/images/34.png diff --git a/resources/cards/D11.png b/USTlord_final/images/35.png similarity index 100% rename from resources/cards/D11.png rename to USTlord_final/images/35.png diff --git a/resources/cards/D12.png b/USTlord_final/images/36.png similarity index 100% rename from resources/cards/D12.png rename to USTlord_final/images/36.png diff --git a/resources/cards/D13.png b/USTlord_final/images/37.png similarity index 100% rename from resources/cards/D13.png rename to USTlord_final/images/37.png diff --git a/resources/cards/D14.png b/USTlord_final/images/38.png similarity index 100% rename from resources/cards/D14.png rename to USTlord_final/images/38.png diff --git a/resources/cards/D15.png b/USTlord_final/images/39.png similarity index 100% rename from resources/cards/D15.png rename to USTlord_final/images/39.png diff --git a/resources/cards/S6.png b/USTlord_final/images/4.png similarity index 100% rename from resources/cards/S6.png rename to USTlord_final/images/4.png diff --git a/resources/cards/C3.png b/USTlord_final/images/40.png similarity index 100% rename from resources/cards/C3.png rename to USTlord_final/images/40.png diff --git a/resources/cards/C4.png b/USTlord_final/images/41.png similarity index 100% rename from resources/cards/C4.png rename to USTlord_final/images/41.png diff --git a/resources/cards/C5.png b/USTlord_final/images/42.png similarity index 100% rename from resources/cards/C5.png rename to USTlord_final/images/42.png diff --git a/resources/cards/C6.png b/USTlord_final/images/43.png similarity index 100% rename from resources/cards/C6.png rename to USTlord_final/images/43.png diff --git a/resources/cards/C7.png b/USTlord_final/images/44.png similarity index 100% rename from resources/cards/C7.png rename to USTlord_final/images/44.png diff --git a/resources/cards/C8.png b/USTlord_final/images/45.png similarity index 100% rename from resources/cards/C8.png rename to USTlord_final/images/45.png diff --git a/resources/cards/C9.png b/USTlord_final/images/46.png similarity index 100% rename from resources/cards/C9.png rename to USTlord_final/images/46.png diff --git a/resources/cards/C10.png b/USTlord_final/images/47.png similarity index 100% rename from resources/cards/C10.png rename to USTlord_final/images/47.png diff --git a/resources/cards/C11.png b/USTlord_final/images/48.png similarity index 100% rename from resources/cards/C11.png rename to USTlord_final/images/48.png diff --git a/resources/cards/C12.png b/USTlord_final/images/49.png similarity index 100% rename from resources/cards/C12.png rename to USTlord_final/images/49.png diff --git a/resources/cards/S7.png b/USTlord_final/images/5.png similarity index 100% rename from resources/cards/S7.png rename to USTlord_final/images/5.png diff --git a/resources/cards/C13.png b/USTlord_final/images/50.png similarity index 100% rename from resources/cards/C13.png rename to USTlord_final/images/50.png diff --git a/resources/cards/C14.png b/USTlord_final/images/51.png similarity index 100% rename from resources/cards/C14.png rename to USTlord_final/images/51.png diff --git a/resources/cards/C15.png b/USTlord_final/images/52.png similarity index 100% rename from resources/cards/C15.png rename to USTlord_final/images/52.png diff --git a/resources/cards/K16.png b/USTlord_final/images/53.png similarity index 100% rename from resources/cards/K16.png rename to USTlord_final/images/53.png diff --git a/resources/cards/K17.png b/USTlord_final/images/54.png similarity index 100% rename from resources/cards/K17.png rename to USTlord_final/images/54.png diff --git a/resources/cards/S8.png b/USTlord_final/images/6.png similarity index 100% rename from resources/cards/S8.png rename to USTlord_final/images/6.png diff --git a/resources/cards/S9.png b/USTlord_final/images/7.png similarity index 100% rename from resources/cards/S9.png rename to USTlord_final/images/7.png diff --git a/resources/cards/S10.png b/USTlord_final/images/8.png similarity index 100% rename from resources/cards/S10.png rename to USTlord_final/images/8.png diff --git a/resources/cards/S11.png b/USTlord_final/images/9.png similarity index 100% rename from resources/cards/S11.png rename to USTlord_final/images/9.png diff --git a/USTlord_final/images/GamePicture1.jpeg b/USTlord_final/images/GamePicture1.jpeg new file mode 100644 index 0000000..037d8c5 Binary files /dev/null and b/USTlord_final/images/GamePicture1.jpeg differ diff --git a/USTlord_final/images/Homepage.jfif b/USTlord_final/images/Homepage.jfif new file mode 100644 index 0000000..4554f6d Binary files /dev/null and b/USTlord_final/images/Homepage.jfif differ diff --git a/USTlord_final/images/Homepage.jpg b/USTlord_final/images/Homepage.jpg new file mode 100644 index 0000000..8347b46 Binary files /dev/null and b/USTlord_final/images/Homepage.jpg differ diff --git a/USTlord_final/images/background.jpg b/USTlord_final/images/background.jpg new file mode 100644 index 0000000..0addfd0 Binary files /dev/null and b/USTlord_final/images/background.jpg differ diff --git a/USTlord_final/images/card2.png b/USTlord_final/images/card2.png new file mode 100644 index 0000000..133a7ea Binary files /dev/null and b/USTlord_final/images/card2.png differ diff --git a/USTlord_final/images/farmer.png b/USTlord_final/images/farmer.png new file mode 100644 index 0000000..c6b554f Binary files /dev/null and b/USTlord_final/images/farmer.png differ diff --git a/USTlord_final/images/icon.jpg b/USTlord_final/images/icon.jpg new file mode 100644 index 0000000..3a716a1 Binary files /dev/null and b/USTlord_final/images/icon.jpg differ diff --git a/USTlord_final/images/lord.png b/USTlord_final/images/lord.png new file mode 100644 index 0000000..f970673 Binary files /dev/null and b/USTlord_final/images/lord.png differ diff --git a/USTlord_final/images/player1.png b/USTlord_final/images/player1.png new file mode 100644 index 0000000..7f026d7 Binary files /dev/null and b/USTlord_final/images/player1.png differ diff --git a/USTlord_final/images/player2.png b/USTlord_final/images/player2.png new file mode 100644 index 0000000..39de8a6 Binary files /dev/null and b/USTlord_final/images/player2.png differ diff --git a/USTlord_final/images/player3.png b/USTlord_final/images/player3.png new file mode 100644 index 0000000..3f97996 Binary files /dev/null and b/USTlord_final/images/player3.png differ diff --git a/USTlord_final/img.qrc b/USTlord_final/img.qrc new file mode 100644 index 0000000..af16a1b --- /dev/null +++ b/USTlord_final/img.qrc @@ -0,0 +1,72 @@ + + + images/background.jpg + images/card2.png + images/Homepage.jfif + images/Homepage.jpg + + + images/icon.jpg + images/farmer.png + images/lord.png + images/player1.png + images/player2.png + images/player3.png + + + images/1.png + images/2.png + images/3.png + images/4.png + images/5.png + images/6.png + images/7.png + images/8.png + images/9.png + images/10.png + images/11.png + images/12.png + images/13.png + images/14.png + images/15.png + images/16.png + images/17.png + images/18.png + images/19.png + images/20.png + images/21.png + images/22.png + images/23.png + images/24.png + images/25.png + images/26.png + images/27.png + images/28.png + images/29.png + images/30.png + images/31.png + images/32.png + images/33.png + images/34.png + images/35.png + images/36.png + images/37.png + images/38.png + images/39.png + images/40.png + images/41.png + images/42.png + images/43.png + images/44.png + images/45.png + images/46.png + images/47.png + images/48.png + images/49.png + images/50.png + images/51.png + images/52.png + images/53.png + images/54.png + + diff --git a/USTlord_final/mainwindow.cpp b/USTlord_final/mainwindow.cpp index 087b7c3..ef370f2 100644 --- a/USTlord_final/mainwindow.cpp +++ b/USTlord_final/mainwindow.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "mainwindow.h" #include "ui_mainwindow.h" @@ -9,6 +10,15 @@ MainWindow::MainWindow(QWidget *parent) , ui(new Ui::MainWindow) { ui->setupUi(this); + initialize_window(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::initialize_window() { ui->start_offline_button->setStyleSheet( "QPushButton{" "background-color:white;"//color @@ -57,22 +67,20 @@ MainWindow::MainWindow(QWidget *parent) "padding:6px;" //padding "}"); ui->exit_button->setCursor(Qt::PointingHandCursor); + bgm = new QSound(":/sound/sound/bkMusic.wav"); + bgm->play(); + bgm->setLoops(-1); } - -MainWindow::~MainWindow() -{ - delete ui; -} - void MainWindow::paintEvent(QPaintEvent *event) { static QPixmap backpic(":/background/images/Homepage.jpg"); QPainter painter(this); painter.drawPixmap(this->rect(),backpic); } - +//Button slots void MainWindow::on_create_room_button_clicked() { + bgm->stop(); server_window=new ServerWindow(this); this->hide(); server_window->show(); @@ -80,13 +88,15 @@ void MainWindow::on_create_room_button_clicked() void MainWindow::on_start_offline_button_clicked() { + bgm->stop(); play_window=new PlayWindow(this); - this->hide(); + this->close(); play_window->show(); } void MainWindow::on_join_room_button_clicked() { + bgm->stop(); client_window=new ClientWindow(this); this->hide(); client_window->show(); @@ -94,5 +104,7 @@ void MainWindow::on_join_room_button_clicked() void MainWindow::on_exit_button_clicked() { + bgm->stop(); close(); } + diff --git a/USTlord_final/mainwindow.h b/USTlord_final/mainwindow.h index 5139ed9..de53698 100644 --- a/USTlord_final/mainwindow.h +++ b/USTlord_final/mainwindow.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "clientwindow.h" #include "playwindow.h" #include "serverwindow.h" @@ -20,6 +21,7 @@ class MainWindow : public QMainWindow MainWindow(QWidget *parent = nullptr); ~MainWindow(); void paintEvent(QPaintEvent * event) override; + void initialize_window(); private slots: void on_create_room_button_clicked(); @@ -35,5 +37,6 @@ private slots: ClientWindow* client_window{nullptr}; PlayWindow* play_window{nullptr}; ServerWindow* server_window{nullptr}; + QSound* bgm; }; #endif // MAINWINDOW_H diff --git a/USTlord_final/mainwindow.ui b/USTlord_final/mainwindow.ui index 4a91e4b..207cf1b 100644 --- a/USTlord_final/mainwindow.ui +++ b/USTlord_final/mainwindow.ui @@ -11,7 +11,11 @@ - MainWindow + USTlord - Main Menu + + + + images/icon.jpgimages/icon.jpg @@ -67,17 +71,6 @@ - - - - 0 - 0 - 800 - 26 - - - - diff --git a/USTlord_final/music.qrc b/USTlord_final/music.qrc new file mode 100644 index 0000000..32dd863 --- /dev/null +++ b/USTlord_final/music.qrc @@ -0,0 +1,10 @@ + + + sound/bkMusic.wav + sound/loseMusic.wav + sound/shuffleCardsMusic.wav + sound/win.wav + sound/zhadan.wav + sound/bgm2.wav + + diff --git a/USTlord_final/playwindow.cpp b/USTlord_final/playwindow.cpp index 53f2e78..679c49d 100644 --- a/USTlord_final/playwindow.cpp +++ b/USTlord_final/playwindow.cpp @@ -1,65 +1,1071 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "playwindow.h" #include "ui_playwindow.h" +#include "source/Card.h" +#define CARD_WIDTH 60 +#define CARD_HEIGHT 80 +#define OPPONENT_CARD_WIDTH 12 +#define OPPONENT_CARD_HEIGHT 16 +#define NUMBER_OF_PLAYERS 3 +#define CARDS_INTERVAL 60 +#define PLAYER1_X 20 +#define PLAYER1_Y 280 +#define PLAYER2_X 250 +#define PLAYER2_Y 10 +#define PLAYER3_X 880 +#define PLAYER3_Y 10 + +void PlayWindow::receive_from_client(DataPackage data) +{ + //TODO + if(data.action==DataPackage::EXCEPTION){ + if(data.content==DataPackage::Content::QUIT){ + this->close(); + } + } + else if(data.action == DataPackage::CHAT) { + ui->chat_box->addItem(QString::fromStdString(players[data.actioner]->get_name())+":"+data.content); + } + else if(data.action == DataPackage::DEAL_CARDS) { + set_of_cards = data.generate_cards(); + qDebug() << "number of cards:" << set_of_cards.size();/////// + initialize_cards(); + qDebug() << "initailize success"; + for(int i=0; i < NUMBER_OF_PLAYERS; i++) update_player_cards(i); + qDebug() << "render landlord cards"; + for(int i=51; iget_card_picture(); + landlord_card->select(false); + landlord_card->turn(true); + landlord_card->setGeometry(510+(i-51)*CARD_WIDTH, 160, CARD_WIDTH, CARD_HEIGHT); + landlord_card->show(); + } + qDebug() << "emit deal cards accept"; + emit send_to_client(DataPackage(my_id,my_id,DataPackage::Action::DEAL_CARDS,DataPackage::Content::ACCEPT)); + } + else if(data.action == DataPackage::CHOOSE_LANDLORD) { + if(data.content == DataPackage::Content::REQUEST) { + ui->call_lord_button->setVisible(true); + ui->refuse_button->setVisible(true); + } + else if(data.content==DataPackage::Content::BE_LANDLORD){//////////// + landlord_id = data.actioner; + choose_landlord(); + landlord_bonus(landlord_id); + if(my_id == landlord_id) { + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + } + } + else if(data.action == DataPackage::PLAY_CARDS && data.content!=DataPackage::Content::DO_NOT_PLAY && data.actioner != my_id) { + current_selection.clear(); + QVector generated_cards=data.generate_cards(); + for(int i=0,n=generated_cards.size();iget_string()); + break; + } + } + } + qDebug() << "All cards found"; + for(int i=0,n=generated_cards.size();iset_selected_cards(current_selection); + players[data.actioner]->set_choice('p'); + qDebug() << players[data.actioner]->play(*cp).get_cards(); + players[data.actioner]->set_selected_cards(players[data.actioner]->play(*cp).get_cards()); + hide_past_cards(); + sleep(200); + reveal_current_selection(); + cp->record(data.actioner,current_selection,data.actioner==landlord_id); + qDebug() << "current pattern:" << QString::fromStdString(cp->get_cards_type().to_string()); + qDebug() << "current pattern player index: " << cp->get_player_index(); + players[data.actioner]->clear_hint(); //clear the cards to be played in deck + hint_id=-1; + players[data.actioner]->clear_cards(current_selection); + vector empty_cards(0,nullptr); + players[my_id]->set_selected_cards(empty_cards); + ui->info_bar->setText(QString::fromStdString("Player " + to_string(data.actioner) + " play " + cp->get_cards_type().to_string())); + players[(data.actioner+1)%3]->set_turn_end(false); + update_player_cards(data.actioner); + current_selection.clear();////// + qDebug() << "My id:" << my_id; + for(int i=0; iget_num_cards()==0) game_finished(i); + } + if((my_id+2)%3 == data.actioner) { + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + } + else if(data.action == DataPackage::PLAY_CARDS && data.content == DataPackage::Content::DO_NOT_PLAY && data.actioner!=my_id) { + players[data.actioner]->set_choice('g'); + players[data.actioner]->set_selected_cards(players[data.actioner]->play(*cp).get_cards()); + players[data.actioner]->clear_hint(); //clear the cards to be played in deck + hint_id=-1; + current_selection.clear(); + update_player_cards(data.actioner); + players[(data.actioner+1)%3]->set_turn_end(false); + if((my_id+2)%3 == data.actioner) { + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + } +} + +/* + *Constructors + * Initialize foundamentals for both online and offline game + * including window setting, music and cards + */ PlayWindow::PlayWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::PlayWindow) { ui->setupUi(this); + initialize_window(); + initialize_music(); } -PlayWindow::PlayWindow(DataPackage data,QWidget *parent):QMainWindow(parent),ui(new Ui::PlayWindow) +PlayWindow::PlayWindow(int id, QVector names, QWidget *parent): //initialize online game. + QMainWindow(parent), + ui(new Ui::PlayWindow) { - data=DataPackage();//just for debugging + //TODO ui->setupUi(this); + my_id = id; + mode = ONLINE; + initialize_window(); + initialize_music(); + initialize_players(names); } -void PlayWindow::closeEvent(QCloseEvent *event) +/* + * Destructor + */ +PlayWindow::~PlayWindow() { - QMessageBox::StandardButton answer = QMessageBox::question( this, "PlayWindow", - tr("Are you sure to quit the game?\n"), - QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes); - if (answer != QMessageBox::Yes) { - //do not allow to close the second window - event->ignore(); + delete ui; + /*for(int i=0;i < static_cast(this->set_of_cards.size());i++){ + delete this->set_of_cards[i]; + } + this->set_of_cards.clear(); + for(int i = 0 ; i < NUMBER_OF_PLAYERS; i++){ + delete this->players[i]; + } + this->players.clear(); + delete this->cp;*/ +} + +void PlayWindow::initialize_window() { + setFixedSize(1200, 600); + if(mode == OFFLINE) { + ui->chat_box->setVisible(false); + ui->line_edit->setVisible(false); + ui->enter_button->setVisible(false); + } + ui->info_bar->setStyleSheet("color:white;"); + ui->start_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 25px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->start_button->setCursor(Qt::PointingHandCursor); + if(mode==ONLINE){ui->start_button->setVisible(false);} + ui->hit_button->setVisible(false); + ui->hit_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 25px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->hit_button->setCursor(Qt::PointingHandCursor); + ui->call_lord_button->setVisible(false); + ui->call_lord_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 10px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->call_lord_button->setCursor(Qt::PointingHandCursor); + ui->hint_button->setVisible(false); + ui->hint_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 25px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->hint_button->setCursor(Qt::PointingHandCursor); + ui->refuse_button->setVisible(false); + ui->refuse_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 15px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->refuse_button->setCursor(Qt::PointingHandCursor); + ui->give_up_button->setVisible(false); + ui->give_up_button->setStyleSheet( + "QPushButton{" + "background-color:white;"//color + "border-style:outset;" //inset/outset + "border-width:4px;" + "border-radius:10px;" + "border-color:black;" //border color + "font:bold 14px;" //character and size + "color:black;" //character color + "padding:6px;" //padding + "}"); + ui->give_up_button->setCursor(Qt::PointingHandCursor); +} + +void PlayWindow::initialize_music() { //initialize music + bgm = new QSound(":/sound/sound/bgm2.wav"); + win_music = new QSound(":/sound/sound/win.wav"); + lose_music = new QSound(":/sound/sound/loseMusic.wav"); + shuffle_music = new QSound(":/sound/sound/shuffleCardsMusic.wav"); + bgm->play(); + bgm->setLoops(-1); +} + +void PlayWindow::initialize_cards() { //initialize 54 cards + if(mode == OFFLINE) { + char color; + for(int i=0;i<54;++i){ + char figure; + if(i<52){ + figure = figures_to_int[i%13]; + int j = i/13; + switch(j){ + case 0: + color = 's'; + break; + case 1: + color = 'h'; + break; + case 2: + color = 'd'; + break; + case 3: + color = 'c'; + break; + } + } + else if(i==52){ + figure = figures_to_int[NUMBER_OF_FIGURES-1]; + color = 'b'; + } + else{ + figure = figures_to_int[NUMBER_OF_FIGURES-1]; + color = 'r'; + } + + string pic_name = ":/card/images/" + to_string(i+1) + ".png"; + Card* card = new Card(color, figure); + QPixmap pic; + pic.load(QString::fromStdString(pic_name)); + qDebug() << QString::fromStdString(pic_name); + CardPicture* card_picture = new CardPicture(this); + connect(card_picture, SIGNAL(selected_signal()),this,SLOT(card_selected())); + card_picture->setPic(pic); + card_picture->hide(); + card_picture->setGeometry(570, 260, CARD_WIDTH, CARD_HEIGHT); + card->set_card_picture(card_picture); + set_of_cards.push_back(card); + card_pic_map.insert(card_picture, card); + } } else { - //show the mainwindow - this->parentWidget()->show(); - //allow to close the second window - event->accept(); + for(int i=0, j=0; i < NUMBER_OF_PLAYERS; i++) { + for(int k = 0; k < 17; k++) { + Card* card = set_of_cards[j++]; + string pic_name = ":/card/images/" + to_string(card->get_index()+1) + ".png"; + QPixmap pic; + pic.load(QString::fromStdString(pic_name)); + qDebug() << QString::fromStdString(pic_name); + CardPicture* card_picture = new CardPicture(this); + connect(card_picture, SIGNAL(selected_signal()),this,SLOT(card_selected())); + card_picture->setPic(pic); + card_picture->hide(); + card_picture->setGeometry(570, 260, CARD_WIDTH, CARD_HEIGHT); + card->set_card_picture(card_picture); + card_pic_map.insert(card_picture, card); + players[i]->receive_card(card); + update_player_cards(i); + sleep(50);//////// + } + } + for(int i=51; iget_index()+1) + ".png"; + QPixmap pic; + pic.load(QString::fromStdString(pic_name)); + qDebug() << QString::fromStdString(pic_name); + CardPicture* card_picture = new CardPicture(this); + connect(card_picture, SIGNAL(selected_signal()),this,SLOT(card_selected())); + card_picture->setPic(pic); + card_picture->hide(); + card_picture->setGeometry(570, 260, CARD_WIDTH, CARD_HEIGHT); + card->set_card_picture(card_picture); + card_pic_map.insert(card_picture, card); + } } } -PlayWindow::~PlayWindow() +void PlayWindow::initialize_offline_game() { //initialize offline game + + my_id = 0; + + initialize_cards(); + ui->start_button->setVisible(false); + initialize_players(); + shuffle(); + for(int p = 0; p < NUMBER_OF_PLAYERS; p++) update_player_cards(p); + this->cp=new CurrentPattern(); + game_finish = false; + you_win = false; + landlord_win = false; + landlord_id = -1; + ui->call_lord_button->setVisible(true); + ui->refuse_button->setVisible(true); +} + +void PlayWindow::initialize_players() { // initialize players in offline mode + qDebug() << "Azhe"; + Player* player1 = new Player(0,"You"); + Player* player2 = new AIPlayer(1,"AI "+to_string(1)); + Player* player3 = new AIPlayer(2,"AI "+to_string(2)); + this->players.append(player1); + this->players.append(player2); + this->players.append(player3); + + player1_pic = new QLabel(this); + player1_pic->setGeometry(PLAYER1_X, PLAYER1_Y, 84, 120); + player2_pic = new QLabel(this); + player2_pic->setGeometry(PLAYER2_X, PLAYER2_Y, 84, 120); + player3_pic = new QLabel(this); + player3_pic->setGeometry(PLAYER3_X, PLAYER3_Y, 84, 120); + //set names displayed in ui. + ui->player0_name->setText("YOU"); + ui->player0_name->setStyleSheet("color:white;"); + ui->player1_name->setText("PLAYER 1"); + ui->player1_name->setStyleSheet("color:white;"); + ui->player2_name->setText("PLAYER 2"); + ui->player2_name->setStyleSheet("color:white;"); +} + +void PlayWindow::initialize_players(QVector names) { // initialize players in online mode + for(int i=0; iplayers.append(new_player); + new_player->set_turn_end(true); + } + player1_pic = new QLabel(this); + player1_pic->setGeometry(PLAYER1_X, PLAYER1_Y, 84, 120); + player2_pic = new QLabel(this); + player2_pic->setGeometry(PLAYER2_X, PLAYER2_Y, 84, 120); + player3_pic = new QLabel(this); + player3_pic->setGeometry(PLAYER3_X, PLAYER3_Y, 84, 120); + //set names displayed in ui. + ui->player0_name->setText("YOU #" +QString::number(my_id)); + ui->player0_name->setStyleSheet("color:white;"); + ui->player1_name->setText(QString::fromStdString(players[(my_id+1)%NUMBER_OF_PLAYERS]->get_name())); + ui->player1_name->setStyleSheet("color:white;"); + ui->player2_name->setText(QString::fromStdString(players[(my_id+2)%NUMBER_OF_PLAYERS]->get_name())); + ui->player2_name->setStyleSheet("color:white;"); +} + + /* + * Game Processing Functions + * shuffle + * card_selected + * AIplayer_action + * choose_landlord + * landlord_bonus + * restart + * game_finished + */ + +void PlayWindow::shuffle() //shuffle cards, distribute cards and sort cards { - delete ui; + for(int i = 0; i < NUMBER_OF_CARDS; i++) { + swap(set_of_cards[i], set_of_cards[rand()%NUMBER_OF_CARDS]); + } + CardPicture* card_pic; + bgm->stop(); + shuffle_music->play(); + shuffle_music->setLoops(-1); + for(int k = 0, i = 0; i < NUMBER_OF_PLAYERS; i++) { + players[i]->abandom_cards(); + for(int j = 0; j < 17; j++) { + card_pic = this->set_of_cards[k]->get_card_picture(); + card_pic->select(false); + if(i > 0) { + card_pic->turn(true); + card_pic->resize(OPPONENT_CARD_WIDTH, OPPONENT_CARD_HEIGHT); + } + else { + card_pic->turn(false); + card_pic->resize(CARD_WIDTH, CARD_HEIGHT); + } + card_pic->show(); + this->players[i]->receive_card(this->set_of_cards[k++]); + update_player_cards(i); + sleep(50); + } + } + for(int k = 51; k < NUMBER_OF_CARDS; k++) { + card_pic = this->set_of_cards[k]->get_card_picture(); + card_pic->select(false); + card_pic->turn(true); + card_pic->show(); + card_pic->setGeometry(510+CARD_WIDTH*(k-51), 160, CARD_WIDTH, CARD_HEIGHT); + } + shuffle_music->stop(); + bgm->play(); +} + +void PlayWindow::card_selected() { // handle card selection in ui + if(game_status == DEFAULT || game_status == DEALING_CARDS) return; + if(players[my_id]->turn_end()) return; + qDebug() << "Signal Received!"; + CardPicture* card_pic = (CardPicture*) sender(); + qDebug() << card_pic->is_selected(); + if(card_pic->is_selected()) + { + card_pic->select(false); + for(vector::iterator it = current_selection.begin(); it != current_selection.end(); it++) + { + if(*it == card_pic_map[card_pic]) + { + qDebug() << "Selection Removed!"; + current_selection.erase(it); + break; + } + } + } + else + { + qDebug() << "Select!"; + card_pic->select(true); + qDebug() << "Selection added!"; + current_selection.push_back(card_pic_map[card_pic]); + //m_Selected.insert(cardpic); add this card to selected set + } + + update_player_cards(my_id); +} + +void PlayWindow::AIplayer_action(int active_AIplayer){ //AI player play cards + + sleep(1000); + CardsGroup tmp = players[active_AIplayer]->play(*cp); + vector tmpcard = tmp.get_cards(); + sleep(1000); + if(!tmp.get_cards().empty()){ +// qDebug() << "here1"; + for(int i = 0; i < tmpcard.size(); i++){ + current_selection.push_back(tmpcard[i]); + } + hide_past_cards(); + sleep(300); + reveal_current_selection(); + sleep(200); + cp->record(active_AIplayer,tmp,active_AIplayer==landlord_id); + qDebug() << QString::fromStdString(" play " + cp->get_cards_type().to_string()); + ui->info_bar->setText(QString::fromStdString("Player ") +QString::number(active_AIplayer)+ QString::fromStdString(" plays " + cp->get_cards_type().to_string())); + update_player_cards(active_AIplayer); + current_selection.clear(); + qDebug() << QString::fromStdString(" play " + cp->get_cards_type().to_string()); + sleep(1000); + current_selection.clear(); + }else{ + ui->info_bar->setText(QString::fromStdString("Player ") +QString::number(active_AIplayer)+ QString::fromStdString(" gives up.")); + sleep(1000); + } +} + +void PlayWindow::choose_landlord(){ //handle choose landlord game process + players[my_id]->set_turn_end(true); + players[(my_id+1)%NUMBER_OF_PLAYERS]->set_turn_end(true); + players[(my_id+2)%NUMBER_OF_PLAYERS]->set_turn_end(true); + if(mode == OFFLINE) { + bool decision; + decision = players[1]->want_landlord(); + players[(my_id+1)%NUMBER_OF_PLAYERS]->display_cards(); + if(decision) { + ui->info_bar->setText("Player 1 calls landlord!"); + sleep(800); + call_landlord_list.push_front((my_id+1)%NUMBER_OF_PLAYERS); + } + decision = players[(my_id+2)%NUMBER_OF_PLAYERS]->want_landlord(); + players[(my_id+2)%NUMBER_OF_PLAYERS]->display_cards(); + if(decision) { + ui->info_bar->setText("Player 2 calls landlord!"); + sleep(800); + call_landlord_list.push_front((my_id+2)%NUMBER_OF_PLAYERS); + } + if(call_landlord_list.size() == 0) { + ui->info_bar->setText("No one calls landlord! Redistribute the cards now."); + sleep(800); + restart(); + return; + } + else { + landlord_id = call_landlord_list[0]; + qDebug() << landlord_id << "----1"; + landlord_bonus(landlord_id); + game_status = PLAYING; + if(landlord_id == my_id){ + ui->info_bar->setText(QString::fromStdString("You are landlord!")); + } + else{ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(landlord_id) + QString::fromStdString(" is the landlord now!")); + } + sleep(800); + set_chara_pic(); + } + for(int i = landlord_id; i != my_id;){ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(i) + QString::fromStdString("'s turn now")); + sleep(800); + AIplayer_action(i); + i = (++i)%NUMBER_OF_PLAYERS; + } + + if(cp->get_player_index()!= my_id){ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(cp->get_player_index()) + QString::fromStdString(" played. \n Now it's your turn."));} + else{ + ui->info_bar->setText("Now it's your turn."); + } + players[my_id]->set_turn_end(false); + sleep(1000); + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + else { + game_status = PLAYING; + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(landlord_id) + QString::fromStdString(" is the landlord now!")); + players[landlord_id]->set_turn_end(false); + vector empty_cards{}; + cp=new CurrentPattern(empty_cards,landlord_id); + set_chara_pic(); + } +} + +void PlayWindow::landlord_bonus(int landlord_id) // distribute 3 landlord bonus cards to the landlord +{ + for(int i = NUMBER_OF_PLAYERS * 17 ; i < NUMBER_OF_CARDS; i++){ + CardPicture* card_picture = this->set_of_cards[i]->get_card_picture(); + card_picture->turn(false); + card_picture->repaint(); + } + sleep(1000); + for(int i = NUMBER_OF_PLAYERS * 17 ; i < NUMBER_OF_CARDS; i++){ + players[landlord_id]->receive_card(set_of_cards[i]); //add cards into landlord player's cards + } + for(int i = NUMBER_OF_PLAYERS * 17 ; i < NUMBER_OF_CARDS; i++){ + CardPicture* card_picture = this->set_of_cards[i]->get_card_picture(); + card_picture->turn(true); + card_picture->repaint(); + } + qDebug()<< "Current num cards:" << players[landlord_id]->get_num_cards(); + update_player_cards(landlord_id); +}; + +void PlayWindow::restart() { //restart the game if no one calls landlord + qDebug() << "No landlord! Restart!"; + for(int k = 0; k < NUMBER_OF_CARDS; k++) { + CardPicture* card_pic = this->set_of_cards[k]->get_card_picture(); + card_pic->hide(); + } + players.clear(); + initialize_offline_game(); +} + +void PlayWindow::game_finished(int current_player){ //handle game finished process + game_finish = true; + + if(current_player == landlord_id){ + landlord_win = true; + }else{ + landlord_win = false; + } + + if((my_id != landlord_id && !landlord_win)||(my_id == landlord_id && landlord_win)){ + you_win = true; + }else{ + you_win = false; + } + + if(!you_win && landlord_win){ + bgm->stop(); + lose_music->play(); + QMessageBox::information(NULL, "", "Game End!! \n You Lose na :(! \n Landlord wins!", QMessageBox::Yes, QMessageBox::Yes); + } + else if(you_win && landlord_win){ + bgm->stop(); + win_music->play(); + QMessageBox::information(NULL, "", "Game End!! \n You Win na :)! \n Landlord win!", QMessageBox::Yes, QMessageBox::Yes); + } + else if(!you_win && !landlord_win){ + bgm->stop(); + lose_music->play(); + QMessageBox::information(NULL, "", "Game End!! \n You Lose na :(! \n Farmers win!", QMessageBox::Yes, QMessageBox::Yes); + } + else if(you_win && !landlord_win){ + bgm->stop(); + win_music->play(); + QMessageBox::information(NULL, "", "Game End!! \n You Win na :)! \n Farmers win!", QMessageBox::Yes, QMessageBox::Yes); + } + close(); +} + +/* + * Button slots + * START + * CALL LORD + * REFUSE + * HIT + * HINT + * GIVE UP +*/ +void PlayWindow::on_start_button_clicked() // handle game start when clicking start button +{ + if(mode == OFFLINE) { + ui->info_bar->setText("Game Start"); + //sleep(300); + initialize_offline_game(); + ui->info_bar->setText("Please choose landlord"); + } + else { + ui->info_bar->setText("Game Start"); + ui->info_bar->setText("Please choose landlord"); + } +} + +void PlayWindow::on_call_lord_button_clicked() // handle call_lord action if player choose to call landlord when calling landlord +{ + ui->info_bar->setText("You call landlord!"); + sleep(500); + if(mode == OFFLINE) { + call_landlord_list.push_front((my_id+0)%NUMBER_OF_PLAYERS); + ui->refuse_button->setVisible(false); + ui->call_lord_button->setVisible(false); + choose_landlord(); + } + else { + ui->call_lord_button->setVisible(false); + ui->refuse_button->setVisible(false); + emit send_to_client(DataPackage(my_id, my_id, DataPackage::CHOOSE_LANDLORD, DataPackage::Content::ACCEPT)); + } +} + +void PlayWindow::on_refuse_button_clicked() // handle refuse action if player choose to refuse when calling landlord +{ + ui->info_bar->setText("You refuse to be the landlord!"); + sleep(500); + + if(mode == OFFLINE) { + ui->refuse_button->setVisible(false); + ui->call_lord_button->setVisible(false); + choose_landlord(); + } + else { + ui->call_lord_button->setVisible(false); + ui->refuse_button->setVisible(false); + emit send_to_client(DataPackage(my_id, my_id, DataPackage::CHOOSE_LANDLORD, DataPackage::Content::REJECT)); + } } -void PlayWindow::on_pushButton_play_clicked() +void PlayWindow::on_hit_button_clicked() // handle play cards action when the player clicks hit button { + ui->info_bar->clear(); + + sleep(100); + players[my_id]->set_selected_cards(current_selection); + players[my_id]->set_choice('p'); + players[my_id]->set_selected_cards(players[my_id]->play(*cp).get_cards()); + + if(players[my_id]->get_selected_cards().get_cards().size() == 0){ + ui->info_bar->setText("Invalid cards group! \n Please choose again!"); + sleep(500); + if(cp->get_player_index()!=0){ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(cp->get_player_index()) + QString::fromStdString(" played. \n Now it's your turn."));} + else{ + ui->info_bar->setText("Now it's your turn."); + } + return; + } + else { + hide_past_cards(); + sleep(200); + cp->record(my_id,current_selection,my_id == landlord_id); + players[my_id]->clear_hint(); //clear the cards to be played in deck + hint_id=-1; + players[my_id]->clear_cards(current_selection); + vector empty_cards(0,nullptr); + players[my_id]->set_selected_cards(empty_cards); + ui->info_bar->setText(QString::fromStdString("You play " + cp->get_cards_type().to_string())); + update_player_cards(my_id); + current_selection.clear(); + + ui->hit_button->setVisible(false); + ui->hint_button->setVisible(false); + ui->give_up_button->setVisible(false); + sleep(800); + + + if(mode == OFFLINE) { + if(players[0]->is_winner()){ + ui->info_bar->setText("Game Finished!"); + sleep(800); + game_finished((my_id+0)%NUMBER_OF_PLAYERS); + } + + ui->info_bar->setText("Player 1's turn!"); + AIplayer_action((my_id+1)%NUMBER_OF_PLAYERS); + sleep(800); + if(players[1]->is_winner()){ + ui->info_bar->setText("Game Finished!"); + sleep(800); + game_finished((my_id+1)%NUMBER_OF_PLAYERS); + } + ui->info_bar->setText("Player 2's turn!"); + AIplayer_action((my_id+2)%NUMBER_OF_PLAYERS); + sleep(800); + if(players[2]->is_winner()){ + ui->info_bar->setText("Game Finished!"); + sleep(800); + game_finished((my_id+2)%NUMBER_OF_PLAYERS); + } + + players[1]->set_turn_end(false); + players[2]->set_turn_end(false); + players[0]->set_turn_end(false); + sleep(800); + + if(cp->get_player_index()!=0){ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(cp->get_player_index()) + QString::fromStdString(" played. \n Now it's your turn."));} + else{ + ui->info_bar->setText("Now it's your turn."); + } + + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + else { + vector cards = cp->get_cards(); + QVector cards_to_send{}; + for(int i=0,n=cards.size();ihit_button->setVisible(false); + ui->hint_button->setVisible(false); + ui->give_up_button->setVisible(false); + if(players[my_id]->get_num_cards()==0) game_finished(my_id); + } + } } -void PlayWindow::on_pushButton_hint_clicked() +void PlayWindow::on_hint_button_clicked() //handle hint generation and display when player clicks hint button { + for(auto card : players[my_id]->get_deck()->get_cards()) { + card->get_card_picture()->select(false); + } + players[my_id]->calc_hints(*cp); + if(players[my_id]->get_hints().size() == 0){ + ui->info_bar->setText("No hints."); + current_selection.clear(); + update_player_cards(my_id); + sleep(800); + if(cp->get_player_index()!=0){ + ui->info_bar->setText(QString::fromStdString("Player ") + QString::number(cp->get_player_index()) + QString::fromStdString(" played. \n Now it's your turn."));} + else{ + ui->info_bar->setText("Now it's your turn."); + } + + return; + }else{ + current_selection.clear(); + if(hint_id == -1){ hint_id = 0;} + else{ + hint_id = (hint_id+1)%players[my_id]->get_hints().size(); + } + for(auto card : players[my_id]->get_hints()[hint_id].get_cards()) { + card->get_card_picture()->select(true); + current_selection.push_back(card); + } + players[my_id]->set_selected_cards(players[my_id]->get_hints()[hint_id].get_cards()); + update_player_cards(my_id); //display calculated hints + } } -void PlayWindow::on_pushButton_give_up_clicked() +void PlayWindow::on_give_up_button_clicked() //handle give up action when player click give up { + ui->info_bar->setText("You give up, next player's turn."); + sleep(1000); + players[my_id]->set_choice('g'); + players[my_id]->set_selected_cards(players[my_id]->play(*cp).get_cards()); //player gives up + current_selection.clear(); + update_player_cards(my_id); + + for(int i = 0; i < players[my_id]->get_num_cards(); i++){ + players[my_id]->get_deck()->get_cards()[i]->get_card_picture()->select(false); + } + update_player_cards(my_id); + + if(mode == OFFLINE) { + if(players[my_id]->turn_end()){ // player action finished + ui->hit_button->setVisible(false); + ui->hint_button->setVisible(false); + ui->give_up_button->setVisible(false); + hint_id = -1; + if(cp->get_player_index() == my_id){//last time still me, clear the current pattern stored. + hide_past_cards(); + //recreate a new pattern. + if(!cp->get_cards().empty()){ delete cp;} + cp = new CurrentPattern(); + cp->set_player_index((my_id+1)%NUMBER_OF_PLAYERS); + hint_id=-1; + } + + if(cp->get_player_index() == (my_id+1)%NUMBER_OF_PLAYERS){ + hide_past_cards(); + } + AIplayer_action((my_id+1)%NUMBER_OF_PLAYERS); + sleep(300); + if(players[(my_id+1)%NUMBER_OF_PLAYERS]->is_winner()){//check if it is winner. + ui->info_bar->setText("Game Finished!"); + sleep(800); + game_finished((my_id+1)%NUMBER_OF_PLAYERS); + } + + if(cp->get_player_index() == (my_id+2)%NUMBER_OF_PLAYERS){ + hide_past_cards(); + } + AIplayer_action((my_id+2)%NUMBER_OF_PLAYERS); + sleep(300); + if(players[(my_id+2)%NUMBER_OF_PLAYERS]->is_winner()){ + ui->info_bar->setText("Game Finished!"); + sleep(800); + game_finished((my_id+2)%NUMBER_OF_PLAYERS); + } + + players[1]->set_turn_end(false); + players[2]->set_turn_end(false); + players[0]->set_turn_end(false); + + sleep(800); + + ui->hit_button->setVisible(true); + ui->hint_button->setVisible(true); + ui->give_up_button->setVisible(true); + } + } + else { + players[my_id]->clear_hint();///// + ui->hit_button->setVisible(false); + ui->hint_button->setVisible(false); + ui->give_up_button->setVisible(false); + emit send_to_client(DataPackage(my_id, my_id, DataPackage::PLAY_CARDS, DataPackage::Content::DO_NOT_PLAY)); + } } -void PlayWindow::on_pushButton_want_landlord_clicked() +void PlayWindow::on_enter_button_clicked() { + if(ui->line_edit->text().isEmpty()) return; + else send_to_client(DataPackage(my_id, my_id, DataPackage::CHAT, ui->line_edit->text())); + ui->line_edit->clear(); +} + +/* + * Helper Functions + * sleep + * set_chara_pic + * hide_past_cards + * update_player_cards + * reveal current selection + */ +void PlayWindow::sleep(unsigned int msec) { + QTime reach_time = QTime::currentTime().addMSecs(msec); + while(QTime::currentTime() < reach_time) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); +} + +void PlayWindow::set_chara_pic() { // set character pictures + if(landlord_id == -1) return; + QPixmap farmer_pixmap(":/icon/images/farmer.png"); + QPixmap lord_pixmap(":/icon/images/lord.png"); + if(landlord_id == my_id) { + player1_pic->setPixmap(lord_pixmap); + player1_pic->show(); + } + else { + player1_pic->setPixmap(farmer_pixmap); + player1_pic->show(); + } + if(landlord_id == (my_id+1)%3) { + player2_pic->setPixmap(lord_pixmap); + player2_pic->show(); + } + else { + player2_pic->setPixmap(farmer_pixmap); + player2_pic->show(); + } + if(landlord_id == (my_id+2)%3) { + player3_pic->setPixmap(lord_pixmap); + player3_pic->show(); + } + else { + player3_pic->setPixmap(farmer_pixmap); + player3_pic->show(); + } +} +void PlayWindow::hide_past_cards() { //hide past cards in the ui + for(auto card : cp->get_cards()) { + card->get_card_picture()->hide(); + } } -void PlayWindow::on_pushButton_want_farmer_clicked() +void PlayWindow::update_player_cards(int player_id) { + if(player_id < 0 || player_id > 2) return; + players[player_id]->get_deck()->rearrange(); + //render cards in hand + if(player_id == my_id) + { + for(int j = 0; j < players[player_id]->get_deck()->get_num_cards(); j++) + { + int top_border = 450; //upper border + int left_border = (1200-CARD_WIDTH*players[my_id]->get_num_cards())/2; //left border + CardPicture* card_picture = players[player_id]->get_deck()->get_cards()[j]->get_card_picture(); + card_picture->turn(false); + if(card_picture->is_selected()) top_border-=20; + card_picture->move(left_border+j*CARDS_INTERVAL, top_border); + card_picture->repaint(); + card_picture->show(); + players[my_id]->display_cards(); + } + } + else if(player_id == (my_id+1)%NUMBER_OF_PLAYERS) { + int left_border = 40; + int top_border = 40; + for(int j = 0; j < players[player_id]->get_deck()->get_num_cards(); j++) { + CardPicture* card_picture = players[player_id]->get_deck()->get_cards()[j]->get_card_picture(); + card_picture->setGeometry(left_border+j*12, top_border, OPPONENT_CARD_WIDTH, OPPONENT_CARD_HEIGHT); + card_picture->turn(true); + card_picture->repaint(); + card_picture->show(); + } + } + else { + int left_border = 956; + int top_border = 40; + for(int j = 0; j < players[player_id]->get_deck()->get_num_cards(); j++) { + CardPicture* card_picture = players[player_id]->get_deck()->get_cards()[j]->get_card_picture(); + card_picture->setGeometry(left_border+j*12, top_border, OPPONENT_CARD_WIDTH, OPPONENT_CARD_HEIGHT); + card_picture->turn(true); + card_picture->repaint(); + card_picture->show(); + } + } + if(game_status == DEFAULT || game_status == DEALING_CARDS) return; + if(players[player_id]->turn_end()) { + if(current_selection.size() == 0) return; + else { + int i = 0; + for(auto card : current_selection) { + card->get_card_picture()->setGeometry((1200-CARD_WIDTH*current_selection.size())/2+CARD_WIDTH*i, 160, CARD_WIDTH, CARD_HEIGHT); + i++; + } + } + } +} + +void PlayWindow::reveal_current_selection() { + for(auto card : current_selection) { + card->get_card_picture()->turn(false); + card->get_card_picture()->repaint(); + } +} +/* + * Event handler + * paintEvent + * closeEvent + */ +void PlayWindow::paintEvent(QPaintEvent * event) { + static QPixmap backpic(":/background/images/background.jpg"); + QPainter painter(this); + painter.drawPixmap(this->rect(),backpic); } -void PlayWindow::receive_datapackage(DataPackage dp){} +void PlayWindow::closeEvent(QCloseEvent *event) { +// qDebug() << "ahzeeee"; + bgm->stop(); + shuffle_music->stop(); +// this->close(); + this->parentWidget()->show(); + emit close_window(); + event->accept(); +// exit(0); +} +void PlayWindow::keyPressEvent(QKeyEvent *e) { + if(e->key() == Qt::Key_Enter) on_enter_button_clicked(); +} diff --git a/USTlord_final/playwindow.h b/USTlord_final/playwindow.h index cc2ab1e..fe41db4 100644 --- a/USTlord_final/playwindow.h +++ b/USTlord_final/playwindow.h @@ -1,43 +1,116 @@ #ifndef PLAYWINDOW_H #define PLAYWINDOW_H +#include +#include #include -#include -#include -#include "source/ToolsForNetworking.h" +#include +#include +#include "source/Card.h" +#include "source/CardsType.h" +#include "source/CardsGroup.h" +#include "source/Deck.h" +#include "source/CurrentPattern.h" +#include "source/Player.h" +#include "source/AIPlayer.h" +#include "source/datapackage.h" namespace Ui { class PlayWindow; } +enum GAME_STAGE { + DEFAULT, + DEALING_CARDS, + CALLING_LORD, + PLAYING +}; + +enum GAME_MODE { + OFFLINE, + ONLINE +}; + class PlayWindow : public QMainWindow { Q_OBJECT - public: explicit PlayWindow(QWidget *parent = nullptr); - explicit PlayWindow(DataPackage data,QWidget *parent = nullptr); - void closeEvent(QCloseEvent *event) override; + explicit PlayWindow(int id, QVector names, QWidget *parent=nullptr); ~PlayWindow(); + //Game initializer + void initialize_music(); + void initialize_window(); + void initialize_players(); + void initialize_players(QVector names); + void initialize_cards(); + void initialize_offline_game(); -private slots: - void on_pushButton_play_clicked(); - - void on_pushButton_hint_clicked(); + //Game Process Functions + void landlord_bonus(int landlord_id); //Add 3 bonus cards to landlord + void shuffle(); //shuffle cards, distribute cards, call Deck::rearrange() to sort cards + void choose_landlord(); + void game_finished(int current_player); + void restart(); + //Helper Functions + void set_chara_pic(); + void update_player_cards(int player_id); + void sleep(unsigned int msec); + void hide_past_cards(); + void reveal_current_selection(); + void AIplayer_action(int active_AIplayer); + void clear_cp(int player_id); + //Events + void closeEvent(QCloseEvent *event) override; + void paintEvent(QPaintEvent * event) override; + void keyPressEvent(QKeyEvent *) override; - void on_pushButton_give_up_clicked(); +private slots: + void on_start_button_clicked(); + void card_selected(); + void on_call_lord_button_clicked(); + void on_refuse_button_clicked(); + void on_hit_button_clicked(); + void on_hint_button_clicked(); + void on_give_up_button_clicked(); - void on_pushButton_want_landlord_clicked(); + void on_enter_button_clicked(); - void on_pushButton_want_farmer_clicked(); +public slots: + void receive_from_client(DataPackage data); signals: - void send_datapackage(DataPackage dp); -public slots: - void receive_datapackage(DataPackage dp); + void send_to_client(DataPackage data); + void close_window(); private: Ui::PlayWindow *ui; + //game control + GAME_STAGE game_status{DEFAULT}; + GAME_MODE mode{OFFLINE}; + //game process + QVector players; + QVector set_of_cards;//A complete set of 54 card + QMap card_pic_map; + QVector call_landlord_list; + vector current_selection; + CurrentPattern* cp; + bool game_finish = false, you_win= false, landlord_win = false; + int landlord_id{-1}; + int hint_id{-1}; + int active_player_id{-1}; + int my_id{-1}; + + //sound + QSound* bgm; + QSound* win_music; + QSound* lose_music; + QSound* shuffle_music; + //player picture + QLabel* player1_pic; + QLabel* player2_pic; + QLabel* player3_pic; }; #endif // PLAYWINDOW_H + diff --git a/USTlord_final/playwindow.ui b/USTlord_final/playwindow.ui index 4e92037..3b4b27f 100644 --- a/USTlord_final/playwindow.ui +++ b/USTlord_final/playwindow.ui @@ -6,87 +6,245 @@ 0 0 - 800 + 1200 600 - MainWindow + USTlord + + + + images/icon.jpgimages/icon.jpg - + - 20 + 550 + 200 + 100 + 50 + + + + START + + + + + + 360 + 300 + 80 + 40 + + + + PLAY + + + + + + 460 + 300 + 80 + 40 + + + + CALL LORD + + + + + + 560 + 300 + 80 + 40 + + + + HINT + + + + + + 660 + 300 + 80 + 40 + + + + REFUSE + + + + + + 760 + 300 + 80 + 40 + + + + GIVE UP + + + + + + 400 20 - 751 - 501 + 400 + 75 + + + + + Comic Sans MS + 16 + 50 + false + + + + + + + + + + Qt::AlignCenter + + + + + + 20 + 10 + 150 + 30 - - - - - - - - - - - - - - - - - - - - - - - - - - - Play - - - - - - - Hint - - - - - - - Give Up - - - - - - - Want Landlord - - - - - - - Want Farmer - - - - - - - - - + + + Comic Sans MS + 16 + 75 + true + + + + false + + + + + + + + + Qt::AlignCenter + + + + + + 1030 + 10 + 150 + 30 + + + + + Comic Sans MS + 16 + 75 + true + + + + false + + + + + + + + + Qt::AlignCenter + + + + + + 20 + 400 + 150 + 30 + + + + + Comic Sans MS + 16 + 75 + true + + + + false + + + + + + + + + Qt::AlignCenter + + + + + + 900 + 170 + 300 + 200 + + + + + + + 900 + 370 + 270 + 25 + + + + + + + 1170 + 370 + 30 + 25 + + + + GO + @@ -94,12 +252,11 @@ 0 0 - 800 + 1200 26 - diff --git a/USTlord_final/serverwindow.cpp b/USTlord_final/serverwindow.cpp index 2cbf8f6..9664f08 100644 --- a/USTlord_final/serverwindow.cpp +++ b/USTlord_final/serverwindow.cpp @@ -14,6 +14,7 @@ void ServerWindow::closeEvent(QCloseEvent *event) { on_pushButton_stop_clicked(); qDebug() << "Closing server window"; + if(client_window){this->client_window->close();} //show the mainwindow this->parentWidget()->show(); //allow to close the second window @@ -47,8 +48,12 @@ void ServerWindow::on_pushButton_stop_clicked() ui->listWidget_dialogs->addItem("Closing server"); this->server->close(); } + if(client_window){ + client_window->close(); + } ui->listWidget_dialogs->addItem("Disconnect all "+QString::number(clients.size())+" clients"); for(int i=0;ilistWidget_clients->addItem("Removed " + clients[i]->peerAddress().toString() + ":" + QString::number(clients[i]->peerPort())); //disconnect signal and slot disconnect(clients[i],&QTcpSocket::stateChanged,this,&ServerWindow::handleStateChanged); disconnect(clients[i],&QTcpSocket::readyRead,this,&ServerWindow::handle_clients_message); @@ -74,6 +79,23 @@ void ServerWindow::on_pushButton_create_clicked() ui->listWidget_serverIP->addItem(ip); } } + + //////////////////////// + //create a client window + if(client_window==nullptr){ + client_window=new ClientWindow(this); + connect(client_window,&ClientWindow::close_window,[=](){ + client_window=nullptr; + qDebug() << "Closing client"; + on_pushButton_stop_clicked(); + }); + } + client_window->move(this->pos()+QPoint(-50,100));/// + client_window->show(); + client_window->set_port(ui->lineEdit_port->text()); + client_window->set_serverIP("127.0.0.1"); + client_window->on_pushButton_join_server_clicked(); + server->listen(QHostAddress::Any,ui->lineEdit_port->text().toInt()); if(server->isListening()){ ui->listWidget_dialogs->addItem("Server is listening to port: "+ui->lineEdit_port->text()); @@ -83,9 +105,16 @@ void ServerWindow::on_pushButton_create_clicked() ui->listWidget_dialogs->addItem("Server fails to listen"); } + /////////////// //debugging - DataPackage dp(1,2,DataPackage::Action::CHAT,DataPackage::Content::WIN_GAME); - ui->listWidget_dialogs->addItem(dp.to_string());//// +// DataPackage dp(1,2,DataPackage::Action::CHAT,DataPackage::Content::WIN_GAME); +// ui->listWidget_dialogs->addItem(dp.to_string());//// +// ui->listWidget_dialogs->addItem("After parsing"); +// ui->listWidget_dialogs->addItem(DataPackage::parse(dp.serialize()).to_string()); +// DataPackage dd(1,2,DataPackage::Action::PLAY_CARDS,"s3,h4,d5,d6,rW,bW,s2,cA"); +// ui->listWidget_dialogs->addItem(dd.to_string());//// +// ui->listWidget_dialogs->addItem("After parsing"); +// ui->listWidget_dialogs->addItem(DataPackage::parse(dd.serialize()).to_string()); } void ServerWindow::on_pushButton_start_game_clicked() @@ -96,7 +125,7 @@ void ServerWindow::on_pushButton_start_game_clicked() if(reply==QMessageBox::Yes){ qDebug()<<"Three players are ready!"; give_id(); - this->hide(); + //this->hide(); } else{ qDebug()<<"Players refuse to start game >.<"; @@ -104,16 +133,28 @@ void ServerWindow::on_pushButton_start_game_clicked() } } + else{ + ui->listWidget_dialogs->addItem("Need 3 players to start the game!"); + } } void ServerWindow::handleConnection() { QTcpSocket* client=server->nextPendingConnection(); + if(clients.size()==3){ + ui->listWidget_clients->addItem("New connection"+client->peerAddress().toString() + ":" + QString::number(client->peerPort())+ " rejected"); + ui->listWidget_dialogs->addItem("Clients remained: " + QString::number(clients.size())); + client->close(); + return; + } connect(client,&QTcpSocket::stateChanged,this,&ServerWindow::handleStateChanged); connect(client,&QTcpSocket::readyRead,this,&ServerWindow::handle_clients_message); this->clients.push_back(client); - ui->listWidget_dialogs->addItem("New connection"+client->peerAddress().toString() + ":" + QString::number(client->peerPort())+ " accepted"); - ui->listWidget_dialogs->addItem("Clients left: " + QString::number(clients.size())); + ui->listWidget_clients->addItem("New connection"+client->peerAddress().toString() + ":" + QString::number(client->peerPort())+ " accepted"); + ui->listWidget_dialogs->addItem("Clients remained: " + QString::number(clients.size())); +// //debugging +// DataPackage dd(-2,-2,DataPackage::Action::PLAY_CARDS,"s3,h4,d5,d6,rW,bW,s2,cA"); +// client->write(dd.serialize()); } void ServerWindow::handleStateChanged(QAbstractSocket::SocketState state) @@ -122,11 +163,11 @@ void ServerWindow::handleStateChanged(QAbstractSocket::SocketState state) if(clients[i]->state()!=state){continue;} if(state==QAbstractSocket::SocketState::ConnectedState){ qDebug() << clients[i]->peerAddress().toString() << ":" << QString(clients[i]->peerPort()) << " connected"; - ui->listWidget_dialogs->addItem(clients[i]->peerAddress().toString() + ":" + QString::number(clients[i]->peerPort()) + " connected"); + ui->listWidget_clients->addItem(clients[i]->peerAddress().toString() + ":" + QString::number(clients[i]->peerPort()) + " connected"); } else if(state==QAbstractSocket::SocketState::UnconnectedState){ qDebug() << "Removed " << clients[i]->peerAddress().toString() << ":" << clients[i]->peerPort(); - ui->listWidget_dialogs->addItem("Removed " + clients[i]->peerAddress().toString() + ":" + QString::number(clients[i]->peerPort())); + ui->listWidget_clients->addItem("Removed " + clients[i]->peerAddress().toString() + ":" + QString::number(clients[i]->peerPort())); //disconnect signal and slot disconnect(clients[i],&QTcpSocket::stateChanged,this,&ServerWindow::handleStateChanged); disconnect(clients[i],&QTcpSocket::readyRead,this,&ServerWindow::handle_clients_message); @@ -162,13 +203,13 @@ void ServerWindow::sendData(QTcpSocket* socket, DataPackage data) socket->write(arr); ui->listWidget_dialogs->addItem("Send text to client: " + socket->peerAddress().toString() + ":" + QString::number(socket->peerPort())); - + ui->listWidget_dialogs->addItem(data.to_string());////////////////// } void ServerWindow::give_id() { - for(int i=0;i<3;++i){ - DataPackage confirm_data(-1,-1,DataPackage::Action::GIVE_ID,QString(i)); + for(int i=0;ibounded(3); DataPackage data(-1,-1,DataPackage::Action::CHOOSE_LANDLORD,DataPackage::Content::REQUEST); sendData(clients[random_index],data); + received_message=0; } } else if(data.action==DataPackage::Action::CHOOSE_LANDLORD){ choose_landlord(data); } - else if(data.action==DataPackage::Action::PLAY_CARDS){ + else if(data.action==DataPackage::Action::PLAY_CARDS || data.action==DataPackage::Action::CHAT){ DataPackage data_play(-1,data.actioner,data.action,data.content); - for(int i=0;i<3;++i){ + for(int i=0;ilistWidget_dialogs->addItem("Someone leaves the room"); + ui->listWidget_dialogs->addItem("Exit the game"); + DataPackage data_end(-1,data.actioner,DataPackage::Action::EXCEPTION,DataPackage::Content::QUIT); + for(int i=0;i get_local_IP() const; + //Find all the local IPv4/IPv6 addresses and store them in a QVector + ~ServerWindow(); signals: @@ -30,18 +36,32 @@ class ServerWindow : public QMainWindow private slots: void on_pushButton_stop_clicked(); + //Close the QTcpServer and close all QTcpSocket(s) void on_pushButton_create_clicked(); + //Create a QTcpServer and a local QTcpSocket + //Create a ClientWindow for the host to connect to ServerWindow void on_pushButton_start_game_clicked(); + //Start the game if there are 3 clients connected to the ServerWindow void handleConnection(); + //Add new client to server void handleStateChanged(QAbstractSocket::SocketState state); + //Remove the disconnected sockets + void handle_clients_message(); + //Receive clients' messages if there are bytes avaible to read + void sendData(QTcpSocket* socket,DataPackage data); + //Send the data to the corresponding socket (client) + void receiveData(DataPackage data); + //Receive the data from clients and perform corresponding actions + //Send feedback DataPackage to clients if required + //Game logic controlled by server void give_id(); void confirm_ready(); void deal_cards(); @@ -58,6 +78,7 @@ private slots: QVector data_received{}; QString cards; QString bonus_cards; + QVector names={"","",""};//players' names }; #endif // SERVERWINDOW_H diff --git a/USTlord_final/sound/bgm2.wav b/USTlord_final/sound/bgm2.wav new file mode 100644 index 0000000..7921e96 Binary files /dev/null and b/USTlord_final/sound/bgm2.wav differ diff --git a/USTlord_final/sound/bkMusic.wav b/USTlord_final/sound/bkMusic.wav new file mode 100644 index 0000000..5889e50 Binary files /dev/null and b/USTlord_final/sound/bkMusic.wav differ diff --git a/USTlord_final/sound/loseMusic.wav b/USTlord_final/sound/loseMusic.wav new file mode 100644 index 0000000..87c3433 Binary files /dev/null and b/USTlord_final/sound/loseMusic.wav differ diff --git a/USTlord_final/sound/shuffleCardsMusic.wav b/USTlord_final/sound/shuffleCardsMusic.wav new file mode 100644 index 0000000..01df861 Binary files /dev/null and b/USTlord_final/sound/shuffleCardsMusic.wav differ diff --git a/USTlord_final/sound/win.wav b/USTlord_final/sound/win.wav new file mode 100644 index 0000000..1599fc4 Binary files /dev/null and b/USTlord_final/sound/win.wav differ diff --git a/USTlord_final/sound/zhadan.wav b/USTlord_final/sound/zhadan.wav new file mode 100644 index 0000000..44c951a Binary files /dev/null and b/USTlord_final/sound/zhadan.wav differ diff --git a/USTlord_final/source/AIPlayer.cpp b/USTlord_final/source/AIPlayer.cpp index 6c66ad6..1141386 100644 --- a/USTlord_final/source/AIPlayer.cpp +++ b/USTlord_final/source/AIPlayer.cpp @@ -93,7 +93,7 @@ const CardsGroup AIPlayer::choose_hint(const CurrentPattern& cp){ vector card_to_add {to_add}; return CardsGroup(card_to_add); } - + } //if current AIPlayer is landlord, then try to beat everyone if(is_landlord){ @@ -104,7 +104,7 @@ const CardsGroup AIPlayer::choose_hint(const CurrentPattern& cp){ if(cp.current_is_landlord()){ if(hints.empty()){return CardsGroup();} return this->hints[0]; - + } else{ //if current AIPlayer is farmer, then avoid to beat its partner but always beat the landlord @@ -134,7 +134,7 @@ const CardsGroup AIPlayer::choose_hint(const CurrentPattern& cp){ } } else{ - //partner plays some combination, never beat him unless itself can win + //partner plays some combination, never beat him unless itself can win if(deck->get_num_cards()==cp.get_cards_type().get_num_cards()){ if(hints.empty()){return CardsGroup();} return this->hints[0]; @@ -143,18 +143,19 @@ const CardsGroup AIPlayer::choose_hint(const CurrentPattern& cp){ return CardsGroup(); } } - + } } - - - + + + }//choose cardsgroup according to the situation of board (e.g. num of cards of other players, current_pattern) CardsGroup AIPlayer::play(const CurrentPattern& cp){ CardsGroup cg=CardsGroup(); - if(!deck->split_important_combination){ + + if(!deck->split_important_combination||cp.get_player_index()==id){ this->calc_hints(cp); cg=this->choose_hint(cp); } @@ -173,15 +174,15 @@ CardsGroup AIPlayer::play(const CurrentPattern& cp){ //use cin or hint (with loops) to Play cards according to current pattern, clear_cards, and reset data members bool AIPlayer::want_landlord(){ - //if num_of_important_combination >=3, the probability of want_lanlord is 0.75 + //if num_of_important_combination >=3, the probability of want_lanlord is 0.85 //if num_of_important_combination==2, the probability of want_landload is 0.5 - //if num_of_important_combination<2, the probability of want_landlord is 0.3 + //if num_of_important_combination<2, the probability of want_landlord is 0.1 float prob = QRandomGenerator::global()->bounded(1.0); qDebug() << "probability:" << prob; int num_of_important_combination = deck->get_num_important_combination(); qDebug() << "important combinations:" << num_of_important_combination; if(num_of_important_combination>=3){ - return (prob<0.75)? true : false; + return (prob<0.85)? true : false; } else if(num_of_important_combination==2){ return (prob<0.5)? true : false; @@ -189,6 +190,5 @@ bool AIPlayer::want_landlord(){ else{ return (prob<0.1)? true : false; } - -}//choose to be landlord or not +}//choose to be landlord or not diff --git a/USTlord_final/source/AIPlayer.h b/USTlord_final/source/AIPlayer.h index 5589282..4167f9f 100644 --- a/USTlord_final/source/AIPlayer.h +++ b/USTlord_final/source/AIPlayer.h @@ -45,7 +45,7 @@ class AIPlayer : public Player { * the probability of choosing lord is determined by how good the cards in hand are The evaluation is basically determined by the number of cards_combination The cards_combination considered here are: - TRIO,BOMB, ROCKET + TRIO, BOMB, ROCKET */ }; diff --git a/USTlord_final/source/Board.cpp b/USTlord_final/source/Board.cpp index 35582dc..c562d07 100644 --- a/USTlord_final/source/Board.cpp +++ b/USTlord_final/source/Board.cpp @@ -123,33 +123,33 @@ void Board::init_offline_game(){ } //Perform the main process of the game -void Board::start_game(){ - string action_name; - CardsGroup action_cards; - - for(int turn = landlord_id; !game_finish; turn++){ - - if(turn >= NUMBER_OF_PLAYER){ - turn = 0; - } - cout << endl; - vector players_num_cards{players[0]->get_num_cards(),players[1]->get_num_cards(),players[2]->get_num_cards()}; - this->cp->record(players[turn]->get_id(),players[turn]->play(*this->get_current_pattern(),players_num_cards),players[turn]->get_id()==landlord_id); - this->cp->display(); - - //check game state - if(players[turn]->get_deck()->get_num_cards() == 0){ - game_finish = true; - landlord_win = (turn == landlord_id); - you_win = (turn == CURRENT_PLAYER); - //output message - if(landlord_win){ cout << "LANDLORD WIN!" << endl; } - if(you_win){ cout << "YOU WIN!" << endl;} - else{ cout << "YOU LOSE!" << endl; } - } - } - cout << "Start game success!" << endl; -}; +//void Board::start_game(){ +// string action_name; +// CardsGroup action_cards; + +// for(int turn = landlord_id; !game_finish; turn++){ + +// if(turn >= NUMBER_OF_PLAYER){ +// turn = 0; +// } +// cout << endl; +// vector players_num_cards{players[0]->get_num_cards(),players[1]->get_num_cards(),players[2]->get_num_cards()}; +// this->cp->record(players[turn]->get_id(),players[turn]->play(*this->get_current_pattern(),players_num_cards),players[turn]->get_id()==landlord_id); +// this->cp->display(); + +// //check game state +// if(players[turn]->get_deck()->get_num_cards() == 0){ +// game_finish = true; +// landlord_win = (turn == landlord_id); +// you_win = (turn == CURRENT_PLAYER); +// //output message +// if(landlord_win){ cout << "LANDLORD WIN!" << endl; } +// if(you_win){ cout << "YOU WIN!" << endl;} +// else{ cout << "YOU LOSE!" << endl; } +// } +// } +// cout << "Start game success!" << endl; +//}; //Choose landlord according to the rule int Board::choose_landlord(){ diff --git a/USTlord_final/source/Card.cpp b/USTlord_final/source/Card.cpp index 15eab57..4a85909 100644 --- a/USTlord_final/source/Card.cpp +++ b/USTlord_final/source/Card.cpp @@ -25,6 +25,19 @@ Card::Color Card::get_color() const{ return this->color; }//get the color of the card +CardPicture* Card::get_card_picture() const { + return card_picture; +} + +int Card::get_index() const { + if(color == EMPTY) return -1; + else if(color == SPADE) return value; + else if(color == HEART) return 13+value; + else if(color == DIAMOND) return 26+value; + else if(color == CLUB) return 39+value; + else if(color == BLACK_JOKER) return 52; + else return 53; +} bool Card::is_valid() const{ if(this->color==EMPTY || this->value==ERROR){ return false; @@ -55,6 +68,9 @@ void Card::set_color(Color color){ this->color=color; } +void Card::set_card_picture(CardPicture *card_pic) { + this->card_picture = card_pic; +} /*Binary Operations*/ bool Card::operator<(const Card& a) const{ return Card::compare_value(this,&a); @@ -137,4 +153,4 @@ bool Card::strictly_compare(const Card* a, const Card* b){ bool Card::strictly_equal(const Card* a, const Card* b){ if(a->value==b->value && a->color==b->color){return true;} return false; -} \ No newline at end of file +} diff --git a/USTlord_final/source/Card.h b/USTlord_final/source/Card.h index e3ddb63..b834317 100644 --- a/USTlord_final/source/Card.h +++ b/USTlord_final/source/Card.h @@ -7,6 +7,7 @@ #include #include +#include "source/CardPicture.h" using namespace std; @@ -28,7 +29,7 @@ class Card { Color color; QString str_color{"E"}; int value; - + CardPicture* card_picture{nullptr}; public: //Constructors and Destructor @@ -43,12 +44,15 @@ class Card { int get_value() const;//get the value of the card Color get_color() const;//get the color of the card bool is_valid() const;//check if the card is valid + CardPicture* get_card_picture() const;//get card picture + int get_index() const; //Mutators void reset(char color, char figure); void reset(Color color, int value); void set_value(int value); void set_color(Color color); + void set_card_picture(CardPicture* card_pic); //Binary Operations bool operator<(const Card& a) const;//Compare the value of two cards diff --git a/USTlord_final/source/CardPicture.cpp b/USTlord_final/source/CardPicture.cpp new file mode 100644 index 0000000..a1579d1 --- /dev/null +++ b/USTlord_final/source/CardPicture.cpp @@ -0,0 +1,48 @@ +#include "CardPicture.h" +#include + +CardPicture::CardPicture(QWidget *parent) : QWidget(parent) +{ + turned = true; + selected = false; + resize(60, 80); + //setFixedSize(60, 80); + QPixmap pic(":/background/images/card2.png"); + card_back = pic.copy(2*80,4*105,80,105); +} + +void CardPicture::paintEvent(QPaintEvent* event) +{ + + QPainter painter(this); + if(turned) + painter.drawPixmap(this->rect(), card_back); + else + painter.drawPixmap(this->rect(), card_pic); +} + +void CardPicture::mousePressEvent(QMouseEvent *event) +{ + if(event->button()==Qt::LeftButton) { + emit selected_signal(); + qDebug() << "Signal emitted!"; + } +} + +void CardPicture::setPic(QPixmap& pic) { + card_pic = pic.copy(0, 0, 110, 154); +} + +void CardPicture::turn(bool t) { + if(turned != t) turned = t; + return; +} + +bool CardPicture::is_turned() { return turned; } + +bool CardPicture::is_selected() { return selected; } + +void CardPicture::select(bool s) { + if(selected != s) { selected = s; } + return; +} diff --git a/USTlord_final/source/CardPicture.h b/USTlord_final/source/CardPicture.h new file mode 100644 index 0000000..9031d62 --- /dev/null +++ b/USTlord_final/source/CardPicture.h @@ -0,0 +1,36 @@ +#ifndef CARDPICTURE_H +#define CARDPICTURE_H + +#include +#include +#include + +class CardPicture : public QWidget +{ + Q_OBJECT +private: + QPixmap card_pic; + QPixmap card_back; + bool turned{true}; + bool selected{false}; +// Card* card{nullptr}; + +public: + CardPicture(QWidget *parent = 0); + void setPic(QPixmap& pic); + void turn(bool t); + bool is_turned(); + void select(bool s); + bool is_selected(); +// void set_card(); +// Card get_matched_card(); + + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent* event); + + QPixmap &getPic(); +signals: + void selected_signal(); +}; + +#endif // CARDPICTURE_H diff --git a/USTlord_final/source/CardsGroup.cpp b/USTlord_final/source/CardsGroup.cpp index 0793dfa..2b37fbe 100644 --- a/USTlord_final/source/CardsGroup.cpp +++ b/USTlord_final/source/CardsGroup.cpp @@ -195,10 +195,10 @@ int CardsGroup::compare(const CardsGroup& a) const{ if(!CardsType::is_comparable(this->cards_type,a.cards_type)){return -2;} //if both are the same type, compare the reference card if(this->cards_type==a.cards_type){ - if(this->reference_card->get_value()get_value()){ + if(*this->reference_card<*a.reference_card){ return -1; } - else if(this->reference_card->get_value()==a.reference_card->get_value()){ + else if(*this->reference_card==*a.reference_card){ return 0; } else{ diff --git a/USTlord_final/source/CardsGroup.h b/USTlord_final/source/CardsGroup.h index 7cd6a25..f0d15a9 100644 --- a/USTlord_final/source/CardsGroup.h +++ b/USTlord_final/source/CardsGroup.h @@ -35,6 +35,7 @@ class CardsGroup { //it means that you can reuse the same object //Accessors + const Card* operator[](int i) const; //get the i+1-th pointer to Card, return nullptr if index out of range diff --git a/USTlord_final/source/CurrentPattern.cpp b/USTlord_final/source/CurrentPattern.cpp index 7ccbecd..4fd9793 100644 --- a/USTlord_final/source/CurrentPattern.cpp +++ b/USTlord_final/source/CurrentPattern.cpp @@ -20,30 +20,31 @@ void CurrentPattern::set_player_index(int id){ this->player_index=id; } bool CurrentPattern::can_be_beaten_by(int id,const CardsGroup& cg) const{ + if(cg.is_valid() && this->get_cards().size()==0){return true;} if(this->player_index==id){ if(cg.is_valid()){ - //cout << "Next round!\n"; + cout << "Next round!\n"; return true; } - //cout << "Your play is invalid.\n"; + cout << "Your play is invalid.\n"; return false; } else{ int compare_value=this->compare(cg); if(compare_value==-1){ - //cout << "Current Pattern can be beaten.\n"; + cout << "Current Pattern can be beaten.\n"; return true; } else if(compare_value==-2){ - //cout << "Not comparable.\n"; + cout << "Not comparable.\n"; return false; } else if(compare_value==0){ - //cout << "They are the same.\n"; + cout << "They are the same.\n"; return false; } else if(compare_value==1){ - //cout << "Current Pattern is greater.\n"; + cout << "Current Pattern is greater.\n"; return false; } return false; @@ -53,11 +54,15 @@ bool CurrentPattern::can_be_beaten_by(int id,const CardsGroup& cg) const{ void CurrentPattern::record(int id,const CardsGroup& cg,bool is_landlord){ if(cg.get_cards_type().get_num_cards()==0){ - return; + this-> reset({}); + this->player_index=id; + this->is_landlord=is_landlord; } + else{ this->reset(cg.get_cards()); this->player_index=id; this->is_landlord = is_landlord; + } }//record the cardsgroup played by the player with the id bool CurrentPattern::current_is_landlord() const{ diff --git a/USTlord_final/source/CurrentPattern.h b/USTlord_final/source/CurrentPattern.h index a72ee47..37ece3f 100644 --- a/USTlord_final/source/CurrentPattern.h +++ b/USTlord_final/source/CurrentPattern.h @@ -13,8 +13,12 @@ class CurrentPattern : public CardsGroup{ int player_index;//index of last player who played these cards bool is_landlord; public: - CurrentPattern():CardsGroup(),player_index(-1){}; + CurrentPattern():CardsGroup(),player_index(0){}; + CurrentPattern(vectorselected_cards,int active_player_id):CardsGroup(selected_cards),player_index(active_player_id){} + CurrentPattern(CardsGroup last_player,int active_player_id):CardsGroup(last_player),player_index(active_player_id){} + void display(); + void set_cardsgroup(); int get_player_index() const; void set_player_index(int id); bool can_be_beaten_by(int id,const CardsGroup& cg) const;//check whether current_pattern can be beaten by cardsgroup played by the player with the id diff --git a/USTlord_final/source/DataPackage.h b/USTlord_final/source/DataPackage.h deleted file mode 100644 index 52cc7e2..0000000 --- a/USTlord_final/source/DataPackage.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef DATAPACKAGE_H -#define DATAPACKAGE_H - -#include -#include -#include "source/Card.h" - -class DataPackage -{ -public: - enum Action{NONE=-1, - GIVE_ID,//0,1,2 - CONFIRM_READY,//request, accept, reject - DEAL_CARDS,//s3 h3... - CHOOSE_LANDLORD,//request, accept, reject, be_lanlord - LANDLORD_BONUS,//s3 h3... - PLAY_CARDS,//do_not_play, s3 h3... - ANNOUNCE,//win_game, lose_game, end_game - CHAT,//any QString - EXCEPTION//quit - }; - struct Content{ - static const QString REQUEST; - static const QString ACCEPT; - static const QString REJECT; - static const QString BE_LANDLORD; - static const QString DO_NOT_PLAY; - static const QString WIN_GAME; - static const QString LOSE_GAME; - static const QString END_GAME; - static const QString QUIT; - }; - -public: - //server id=-1, player id=0,1,2 - int sender{-2}; - int actioner{-2}; - Action action{NONE}; - QString content{}; - -public: - DataPackage(); - DataPackage(int,int,Action,QString); - DataPackage(QString); - void reset(int,int,Action,QString); - QString to_string() const; - QByteArray serialize() const; - static QString cards_to_string(QVector cards); - static DataPackage parse(QByteArray arr); - static void read(DataPackage,QString);//reading raw data to DataPackage - QVector generate_cards();//generate cards if the content consists of cards -}; - -//QString DataPackage::Content::REQUEST = "request"; -//QString DataPackage::Content::ACCEPT="accept"; -//QString DataPackage::Content::REJECT="reject"; -//QString DataPackage::Content::BE_LANDLORD="be"; -//QString DataPackage::Content::DO_NOT_PLAY="noplay"; -//QString DataPackage::Content::WIN_GAME="win"; -//QString DataPackage::Content::LOSE_GAME="lose"; -//QString DataPackage::Content::END_GAME="end"; -//QString DataPackage::Content::QUIT="quit"; - -#endif // DATAPACKAGE_H diff --git a/USTlord_final/source/Player.cpp b/USTlord_final/source/Player.cpp index 230752d..8af090b 100644 --- a/USTlord_final/source/Player.cpp +++ b/USTlord_final/source/Player.cpp @@ -1,4 +1,5 @@ #include "Player.h" +#include Player::Player():id(-1),name("default name"),deck(new Deck()){} Player::Player(int id,string name) : id(id), name(name), deck(new Deck()) {} @@ -11,21 +12,59 @@ void Player::set_id(int id){ void Player::set_name(string name){ this->name=name; } + +void Player::set_choice(char _choice){ + choice = _choice; +} + void Player::set_is_landlord(bool is_landlord){ this->is_landlord=is_landlord; } + +void Player::set_selected_cards(vector current_selected){ + selected_cards_group = CardsGroup(current_selected); +} + int Player::get_id() const{ return this->id; } string Player::get_name() const{ return this->name; } -Deck const* Player::get_deck() const{ +Deck* Player::get_deck() const{ return this->deck; } + int Player::get_num_cards() const{ return this->deck->get_num_cards(); } + +vector Player::get_hints(){ + return this->hints; +} + +CardsGroup Player::get_selected_cards() const { + return selected_cards_group; +} +bool Player::turn_end() const{ + return end_turn; +} + +void Player::clear_hint(){ + this->hints.clear(); + this->current_hint = 0; +} + +bool Player::is_winner() const{ + if(deck->get_num_cards() == 0){ + return true; + }else return false; +} + +void Player::set_turn_end(bool status){ + this->end_turn = status; +} + void Player::receive_card(Card const* c){ this->deck->add_card(c); this->deck->rearrange(); @@ -54,7 +93,7 @@ void Player::display_cards() const{ bool Player::want_landlord(){ char ans='\0'; while (ans!='Y' && ans!='y' && ans!='N' && ans!='n'){ - cout << "Player"<id<<" : "<name<< endl; + cout << "Player"<id<<" : "<name<< endl; cout << "Do you want to be the lanlord? (Y/N) : "; cin >> ans; cin.ignore(999,'\n'); @@ -99,13 +138,12 @@ void Player::select_card(Card const * c){ } }//select one card from deck and push its pointer to selected_cards_group, if card exists in selected_cards_group, then unselect it - -CardsGroup Player::get_hint(){ - if(this->hints.size()==0){return CardsGroup();} - int temp=this->current_hint; - this->current_hint=(this->current_hint+1)%this->hints.size(); - return this->hints[temp]; -}//get one hint according to hints and current_hint, update the selected_cards_group, and display_cards() +//CardsGroup Player::get_hint(){ +// if(this->hints.size()==0){return CardsGroup();} +// int temp=this->current_hint; +// this->current_hint=(this->current_hint+1)%this->hints.size(); +// return this->hints[temp]; +//}//get one hint according to hints and current_hint, update the selected_cards_group, and display_cards() bool Player::selected_can_beat(const CurrentPattern& cp){ if(cp.can_be_beaten_by(this->id,this->selected_cards_group)){ @@ -174,65 +212,35 @@ vector Player::request_cards_string(){ return cards; } -CardsGroup Player::play(const CurrentPattern& cp, vector players_num_cards){ - this->calc_hints(cp); - char choice; - while (true){ - this->display_cards(); - cout << "Enter 'h' to get one hint, enter 's' to select cards, enter 'p' to play cards, enter 'q' to give up: "; - cin >> choice; - cout << endl; - if (choice=='h'){ - this->selected_cards_group=this->get_hint(); - //this->display_cards(); - } - else if (choice=='s'){ - vector cards_string(0,nullptr); - cout << "Please enter a set of cards, e.g. s3 h3 : "; - cards_string=this->request_cards_string(); - vector cards=this->deck->get_cards(); - for(int i=0;iget_string()==*(cards_string[i])){ - this->select_card(cards[j]); - break; - } - } - } - } - else if (choice=='p'){ - if(this->selected_cards_group.is_valid()){ - if(cp.can_be_beaten_by(this->id,this->selected_cards_group)){ - break; - } - else{ - cout << "Cannot beat, please enter again." << endl; - } - } - else{ - cout << "Invalid CardsGroup, please enter again." << endl; - } +CardsGroup Player::play(const CurrentPattern& cp){ + + if (choice=='p'){ + if(this->selected_cards_group.is_valid()){ + if(cp.can_be_beaten_by(this->id,this->selected_cards_group)){ + qDebug() << "here1"; + end_turn = true; + return selected_cards_group; + } + else{ + qDebug() << "here2"; + return CardsGroup(); } } - else if (choice=='q'){ + else{ + qDebug() << "here3"; + return CardsGroup(); } + } + + else if (choice=='g'){ //unselect all selected_cards_group vector empty_cards(0,nullptr); this->selected_cards_group.reset(empty_cards); - break; + end_turn = true; } else{ - cout << "Invalid choice, please enter again." << endl; - } + return CardsGroup(); + //display message : please choose again; } - //clear all the hints - this->hints.clear(); - this->current_hint=0; - //clear the cards to be played in deck - this->clear_cards(this->selected_cards_group); - CardsGroup temp=this->selected_cards_group; - //clear selected_cards_group - vector empty_cards(0,nullptr); - this->selected_cards_group.reset(empty_cards); - return temp; + return this->selected_cards_group; }//use cin or hint (with loops) to Play cards according to current pattern, clear_cards, and reset data members void Player::clear_cards(const CardsGroup& cg){ @@ -266,7 +274,7 @@ void Player::calc_hints(const CurrentPattern& cp) { Card const* second = deck->get_certain_card(Card::Color::HEART,i); Card const* third = deck->get_certain_card(Card::Color::CLUB,i); Card const* fourth = deck->get_certain_card(Card::Color::DIAMOND,i); - + vector temp_cards_combination {first,second,third,fourth}; CardsGroup group_to_add(temp_cards_combination); bombs.push_back(group_to_add); @@ -297,7 +305,7 @@ void Player::calc_hints(const CurrentPattern& cp) { } //then get all possible BOMB if(bombs.size()>0){ - + for(int j=0;j0){ - + for(int j=0;j0){ - + for(int j=0;j0){ - + for(int j=0;j0){ - + for(int j=0;j0){ - + for(int j=0;j=num_input){ + int num_continuous = cp.get_cards_type().get_num_cards(); int value_of_ref = cp.get_reference_card()->get_value(); //find the starting point of such consecutive terms - for(int i=value_of_ref;iget_certain_card(i,{}); - vector card_to_add{first}; - for(int k =1,p=i+1;k card_to_add; + for(int p = i;pget_certain_card(p,card_to_add); card_to_add.push_back(to_add); } @@ -479,13 +486,13 @@ void Player::calc_hints(const CurrentPattern& cp) { hints.push_back(temp); } } - - } - } + + } + //then get all possible BOMB if(bombs.size()>0){ - + for(int j=0;j=num_input/2){ + int num_continuous = num_input/2; int value_of_ref = cp.get_reference_card()->get_value(); - for(int i = value_of_ref;i0){ - + for(int j=0;jget_value(); - - if(CardsGroup::count_max_continuous_times(count,3)>=num_continuous){ - - for(int i = value_of_ref;i0){ - + for(int j=0;j request_cards_string();//only check the format during the request + char choice;///***** + bool end_turn = false;///***** public: //constructor @@ -30,23 +32,35 @@ class Player { //Mutator void set_id(int id); void set_name(string name); + void set_choice(char _choice);///***** void set_is_landlord(bool is_landlord); void receive_card(Card const* c);//receive a card given by board void abandom_cards();//clear all cards in hand + void set_selected_cards(vector current_selected);///***** + void clear_hint(); + void set_turn_end(bool status); + //Accessors + vector get_hints(); int get_id() const; string get_name() const; - Deck const* get_deck() const; + Deck* get_deck() const; int get_num_cards() const; - void display_cards() const;//display cards in hand (deck) and the selected cards to the player + void display_cards() const;//display cards in hand (deck) and the selected cards to the player ///OLD Function?? + bool turn_end() const; + bool is_winner() const; + CardsGroup get_selected_cards() const; + //Member functions virtual bool want_landlord();//choose to be landlord or not virtual void calc_hints(const CurrentPattern& cp);//find all possible hints according to current pattern, and stored them in hints. CardsGroup get_hint();//get one hint according to hints and current_hint, update the selected_cards_group, and display_cards() void select_card(Card const * c);//select one card from deck and push its pointer to selected_cards_group, if card exists in selected_cards_group, then unselect it bool selected_can_beat(const CurrentPattern& cp);//check whether the player's selected cards can beat the last player's CardsGroup - virtual CardsGroup play(const CurrentPattern& cp, vector players_num_cards);//use cin or hint (with loops) to play cards according to current pattern, clear_cards, and reset data members + virtual CardsGroup play(const CurrentPattern& cp);//use cin or hint (with loops) to play cards according to current pattern, clear_cards, and reset data members void clear_cards(const CardsGroup& cg);//clear the played cards' pointers(don't delete) + void set_is_landlord(); + }; #endif /* PLAYER_H_ */ diff --git a/USTlord_final/source/DataPackage.cpp b/USTlord_final/source/datapackage.cpp similarity index 58% rename from USTlord_final/source/DataPackage.cpp rename to USTlord_final/source/datapackage.cpp index e4d8d8f..5219b02 100644 --- a/USTlord_final/source/DataPackage.cpp +++ b/USTlord_final/source/datapackage.cpp @@ -1,120 +1,151 @@ -#include "source/DataPackage.h" -#include -#include - -DataPackage::DataPackage() -{ - -} - -DataPackage::DataPackage(int sender, int actioner, DataPackage::Action action, QString content): - sender(sender),actioner(actioner),action(action),content(content) -{ - -} - -DataPackage::DataPackage(QString raw_data){ - read(*this,raw_data); -} - -void DataPackage::reset(int sender, int actioner, DataPackage::Action action, QString content) -{ - this->sender=sender; - this->actioner=actioner; - this->action=action; - this->content=content; -} - -QString DataPackage::to_string() const -{ - //TODO - QString whole_msg{}; - QString sender_msg="sender:"+QString::number(sender)+";"; - QString actioner_msg="actioner:"+QString::number(actioner)+";"; - QString action_msg="action:"+QString::number(static_cast(action))+";"; - QString content_msg="content:"+content+";"; - whole_msg=sender_msg+actioner_msg+action_msg+content_msg; - return whole_msg; -} - -QByteArray DataPackage::serialize() const -{ - //TODO - QByteArray arr=this->to_string().toUtf8(); - return arr; -} - -QString DataPackage::cards_to_string(QVector cards) -{ - //TODO - QString str_cards; - for(auto it = cards.begin();it!=cards.end();it++){ - Card::Color enum_color = (*it).get_color(); - int value = (*it).get_value(); - string str = Card::to_string(enum_color,value); - QString qstr = QString::fromStdString(str); - if((it+1)!=cards.end()) - str_cards = str_cards+qstr+","; - else - str_cards += qstr; - } - return str_cards; -} - -DataPackage DataPackage::parse(QByteArray arr) -{ - //TODO - qDebug() << "Parsing QByteArray"; - QString whole_msg=QString::fromStdString(arr.toStdString()); - return DataPackage(whole_msg); -} - -void DataPackage::read(DataPackage data, QString raw_data){ - //the format of raw_data should be: - //(int sender_id);(int actioner_id);(Action action);(QString content) - //each seperated by ; - //for the content part, if the content is cards - //then it is seperated one COMMA - - //first split the raw_data into four parts - QStringList derived_data = raw_data.split(QLatin1Char(';')); - data.sender = derived_data[0].toInt(); - data.actioner = derived_data[1].toInt(); - data.action = static_cast(derived_data[2].toInt()); - - derived_data[3] = derived_data[3].simplified(); - data.content = derived_data[3]; - -} - -QVector DataPackage::generate_cards(){ - // ensure the content consists of cards - if(!content.contains(',')){ - qDebug() << "Invalid content!"; - return {}; - - } - QVector cards_vector; - QStringList cards = content.split(','); - for(QStringList::iterator it = cards.begin();it!=cards.end();++it){ - if((*it).size()==2){ - char color = (*it)[0].toLatin1(); - int value = (int)(*it)[1].toLatin1(); - Card card_to_add (color,value); - cards_vector.push_back(card_to_add); - } - else if((*it).size()==3){ - char color = (*it)[0].toLatin1(); - QStringRef str_value(&(*it),1,2); - int value = str_value.toInt(); - Card card_to_add (color,value); - cards_vector.push_back(card_to_add); - } - else{ - qDebug()<<"Invalid card format in content!"; - return {}; - } - - } - return cards_vector; -} +#include "source/datapackage.h" +#include +#include +#include + +DataPackage::DataPackage() +{ + +} + +DataPackage::DataPackage(int sender, int actioner, DataPackage::Action action, QString content): + sender(sender),actioner(actioner),action(action),content(content) +{ + +} + +DataPackage::DataPackage(QString raw_data){ + read(*this,raw_data); +} + +void DataPackage::reset(int sender, int actioner, DataPackage::Action action, QString content) +{ + this->sender=sender; + this->actioner=actioner; + this->action=action; + this->content=content; +} + +QString DataPackage::to_string() const +{ + //TODO + QString whole_msg{}; + QString sender_msg="sender:"+QString::number(sender)+";"; + QString actioner_msg="actioner:"+QString::number(actioner)+";"; + QString action_msg="action:"+QString::number(static_cast(action))+";"; + QString content_msg="content:"+content+";"; + whole_msg=sender_msg+actioner_msg+action_msg+content_msg; + //debugging + qDebug() << "datapackage to string"; + qDebug() << whole_msg; + return whole_msg; +} + +QByteArray DataPackage::serialize() const +{ + //TODO + QByteArray arr=this->to_string().toUtf8(); + //debugging + qDebug() << "serializing"; + qDebug() << QString::fromStdString(arr.toStdString()); + return arr; +} + +QString DataPackage::cards_to_string(QVector cards) +{ + //TODO + QString str_cards; + for(auto it = cards.begin();it!=cards.end();it++){ + Card::Color enum_color = (*it).get_color(); + int value = (*it).get_value(); + string str = Card::to_string(enum_color,value); + QString qstr = QString::fromStdString(str); + if((it+1)!=cards.end()) + str_cards = str_cards+qstr+","; + else + str_cards += qstr; + } + //debugging + qDebug() << "cards to string"; + qDebug() << str_cards; + return str_cards; +} + +DataPackage DataPackage::parse(QByteArray arr) +{ + //TODO + qDebug() << "Parsing QByteArray"; + QString whole_msg=QString::fromStdString(arr.toStdString()); + return DataPackage(whole_msg); +} + +void DataPackage::read(DataPackage& data, QString raw_data){///////////// + //the format of raw_data should be: + //(int sender_id);(int actioner_id);(Action action);(QString content) + //each seperated by ; + //for the content part, if the content is cards + //then it is seperated one COMMA + + //first split the raw_data into four parts + QStringList derived_data = raw_data.split(QLatin1Char(';'),Qt::SkipEmptyParts); + for(int i=0;i=2){ + switch (i) { + case 0: + data.sender = sub_data[1].toInt(); + break; + case 1: + data.actioner = sub_data[1].toInt(); + break; + case 2: + data.action = static_cast(sub_data[1].toInt()); + break; + case 3: + if(data.action==DataPackage::CHAT){ + int index=derived_data[i].indexOf(':'); + data.content=derived_data[i].mid(index+1); + } + else{ + data.content=sub_data[1]; + } + break; + } + } + else if(sub_data.size()==1 && data.action==DataPackage::CHAT){ + if(sub_data[0].size()+1 DataPackage::generate_cards(){ + + QVector cards_vector; + QStringList cards = content.split(','); + for(QStringList::iterator it = cards.begin();it!=cards.end();++it){ + if((*it).size()==2){ + char color = (*it)[0].toLatin1(); + int value = (int)(*it)[1].toLatin1(); + Card* card_to_add = new Card(color, value); + cards_vector.push_back(card_to_add); + } + else if((*it).size()==3){ + char color = (*it)[0].toLatin1(); + QStringRef str_value(&(*it),1,2); + int value = str_value.toInt(); + Card* card_to_add = new Card(color, value); + cards_vector.push_back(card_to_add); + } + else{ + qDebug()<<"Invalid card format in content!"; + return {}; + } + + } + return cards_vector; +} diff --git a/USTlord_final/source/datapackage.h b/USTlord_final/source/datapackage.h new file mode 100644 index 0000000..2e2c85d --- /dev/null +++ b/USTlord_final/source/datapackage.h @@ -0,0 +1,90 @@ +#ifndef DATAPACKAGE_H +#define DATAPACKAGE_H + +#include +#include +#include "source/Card.h" + +class DataPackage +{ +public: + enum Action{ + NONE=-1, + GIVE_ID, + CONFIRM_READY, + DEAL_CARDS, + CHOOSE_LANDLORD, + LANDLORD_BONUS, + PLAY_CARDS, + ANNOUNCE, + CHAT, + EXCEPTION + }; + /*For each Action, defined the related content as following: + * NONE: "" + * GIVE_ID: 0,1,2 + * CONFIRM_READY: Content::REQUEST, Content::ACCEPT, Content:: REJECT + * DEAL_CARDS: Content::DO_NOT_PLAY, + "s3,h5" + rules for formatting a set of cards: + (char)color+(int)value or (char)color + (char)figure + Remark: only JOKER and A are in the form (char)color + (char)figure + color is defined as: + * s: SPADE + * h: HEART + * c: CLUB + * d: DIAMOND + * bW: BLACK_JOKER + * rW: RED_JOKER + + * CHOOSE_LANDLORD: Content::REQUEST, Content::ACCEPT, Content:: REJECT, Content:: BE_LANDLORD + * LANDLORD_BONUS: bonus cards in formatted card form + * PLAY_CARDS: cards_to_play in formatted card form + * ANNOUNCE: Content:WIN_GAME, Content:: LOSE_GAME, Content:: END_GAME + * EXCEPTION::Content.quit + */ + struct Content{ + static const QString REQUEST; + static const QString ACCEPT; + static const QString REJECT; + static const QString BE_LANDLORD; + static const QString DO_NOT_PLAY; + static const QString WIN_GAME; + static const QString LOSE_GAME; + static const QString END_GAME; + static const QString QUIT; + }; + +public: + //server id=-1, player id=0,1,2 + int sender{-2}; + int actioner{-2}; + Action action{NONE}; + QString content{}; + +public: + DataPackage(); + DataPackage(int,int,Action,QString); + DataPackage(QString); + void reset(int,int,Action,QString); + QString to_string() const; + QByteArray serialize() const; + static QString cards_to_string(QVector cards); + static DataPackage parse(QByteArray arr); + static void read(DataPackage&,QString);//reading raw data to DataPackage + QVector generate_cards();//generate cards if the content consists of cards +}; + +/* + * REQUEST = "request"; + * ACCEPT= "accept"; + * REJECT="reject"; + * BE_LANDLORD="be"; + * DO_NOT_PLAY="noplay"; + * WIN_GAME="win"; + * LOSE_GAME="lose"; + * END_GAME="end"; + * QUIT="quit"; +*/ + +#endif // DATAPACKAGE_H diff --git a/resources/images/bg.png b/resources/images/bg.png deleted file mode 100644 index 7eb1684..0000000 Binary files a/resources/images/bg.png and /dev/null differ diff --git a/resources/images/no.png b/resources/images/no.png deleted file mode 100644 index 6639a75..0000000 Binary files a/resources/images/no.png and /dev/null differ diff --git a/resources/images/yes.png b/resources/images/yes.png deleted file mode 100644 index fdde612..0000000 Binary files a/resources/images/yes.png and /dev/null differ diff --git a/resources/media/electronic.mp3 b/resources/media/electronic.mp3 deleted file mode 100644 index 20eebdf..0000000 Binary files a/resources/media/electronic.mp3 and /dev/null differ diff --git a/resources/media/normal.mp3 b/resources/media/normal.mp3 deleted file mode 100644 index 3bb6c2f..0000000 Binary files a/resources/media/normal.mp3 and /dev/null differ diff --git a/resources/old_cards/C10.png b/resources/old_cards/C10.png deleted file mode 100644 index 2b8fb57..0000000 Binary files a/resources/old_cards/C10.png and /dev/null differ diff --git a/resources/old_cards/C11.png b/resources/old_cards/C11.png deleted file mode 100644 index b9ac348..0000000 Binary files a/resources/old_cards/C11.png and /dev/null differ diff --git a/resources/old_cards/C12.png b/resources/old_cards/C12.png deleted file mode 100644 index b3f4808..0000000 Binary files a/resources/old_cards/C12.png and /dev/null differ diff --git a/resources/old_cards/C13.png b/resources/old_cards/C13.png deleted file mode 100644 index 0502e22..0000000 Binary files a/resources/old_cards/C13.png and /dev/null differ diff --git a/resources/old_cards/C14.png b/resources/old_cards/C14.png deleted file mode 100644 index 7e6571c..0000000 Binary files a/resources/old_cards/C14.png and /dev/null differ diff --git a/resources/old_cards/C15.png b/resources/old_cards/C15.png deleted file mode 100644 index adf5c44..0000000 Binary files a/resources/old_cards/C15.png and /dev/null differ diff --git a/resources/old_cards/C3.png b/resources/old_cards/C3.png deleted file mode 100644 index 97ef168..0000000 Binary files a/resources/old_cards/C3.png and /dev/null differ diff --git a/resources/old_cards/C4.png b/resources/old_cards/C4.png deleted file mode 100644 index b3953ff..0000000 Binary files a/resources/old_cards/C4.png and /dev/null differ diff --git a/resources/old_cards/C5.png b/resources/old_cards/C5.png deleted file mode 100644 index ecde561..0000000 Binary files a/resources/old_cards/C5.png and /dev/null differ diff --git a/resources/old_cards/C6.png b/resources/old_cards/C6.png deleted file mode 100644 index 1c6f917..0000000 Binary files a/resources/old_cards/C6.png and /dev/null differ diff --git a/resources/old_cards/C7.png b/resources/old_cards/C7.png deleted file mode 100644 index 4d4a2f1..0000000 Binary files a/resources/old_cards/C7.png and /dev/null differ diff --git a/resources/old_cards/C8.png b/resources/old_cards/C8.png deleted file mode 100644 index bdc679d..0000000 Binary files a/resources/old_cards/C8.png and /dev/null differ diff --git a/resources/old_cards/C9.png b/resources/old_cards/C9.png deleted file mode 100644 index 71b448c..0000000 Binary files a/resources/old_cards/C9.png and /dev/null differ diff --git a/resources/old_cards/D10.png b/resources/old_cards/D10.png deleted file mode 100644 index 23cce30..0000000 Binary files a/resources/old_cards/D10.png and /dev/null differ diff --git a/resources/old_cards/D11.png b/resources/old_cards/D11.png deleted file mode 100644 index 0b45272..0000000 Binary files a/resources/old_cards/D11.png and /dev/null differ diff --git a/resources/old_cards/D12.png b/resources/old_cards/D12.png deleted file mode 100644 index 014b316..0000000 Binary files a/resources/old_cards/D12.png and /dev/null differ diff --git a/resources/old_cards/D13.png b/resources/old_cards/D13.png deleted file mode 100644 index 6a37c42..0000000 Binary files a/resources/old_cards/D13.png and /dev/null differ diff --git a/resources/old_cards/D14.png b/resources/old_cards/D14.png deleted file mode 100644 index 12d5323..0000000 Binary files a/resources/old_cards/D14.png and /dev/null differ diff --git a/resources/old_cards/D15.png b/resources/old_cards/D15.png deleted file mode 100644 index d43e5bf..0000000 Binary files a/resources/old_cards/D15.png and /dev/null differ diff --git a/resources/old_cards/D3.png b/resources/old_cards/D3.png deleted file mode 100644 index e86cc11..0000000 Binary files a/resources/old_cards/D3.png and /dev/null differ diff --git a/resources/old_cards/D4.png b/resources/old_cards/D4.png deleted file mode 100644 index 5399d2b..0000000 Binary files a/resources/old_cards/D4.png and /dev/null differ diff --git a/resources/old_cards/D5.png b/resources/old_cards/D5.png deleted file mode 100644 index e3768e4..0000000 Binary files a/resources/old_cards/D5.png and /dev/null differ diff --git a/resources/old_cards/D6.png b/resources/old_cards/D6.png deleted file mode 100644 index 628c66d..0000000 Binary files a/resources/old_cards/D6.png and /dev/null differ diff --git a/resources/old_cards/D7.png b/resources/old_cards/D7.png deleted file mode 100644 index e9628b0..0000000 Binary files a/resources/old_cards/D7.png and /dev/null differ diff --git a/resources/old_cards/D8.png b/resources/old_cards/D8.png deleted file mode 100644 index b4127c1..0000000 Binary files a/resources/old_cards/D8.png and /dev/null differ diff --git a/resources/old_cards/D9.png b/resources/old_cards/D9.png deleted file mode 100644 index ed73fb8..0000000 Binary files a/resources/old_cards/D9.png and /dev/null differ diff --git a/resources/old_cards/H10.png b/resources/old_cards/H10.png deleted file mode 100644 index dd1ba8e..0000000 Binary files a/resources/old_cards/H10.png and /dev/null differ diff --git a/resources/old_cards/H11.png b/resources/old_cards/H11.png deleted file mode 100644 index b417070..0000000 Binary files a/resources/old_cards/H11.png and /dev/null differ diff --git a/resources/old_cards/H12.png b/resources/old_cards/H12.png deleted file mode 100644 index 5a8aab8..0000000 Binary files a/resources/old_cards/H12.png and /dev/null differ diff --git a/resources/old_cards/H13.png b/resources/old_cards/H13.png deleted file mode 100644 index 1028d0e..0000000 Binary files a/resources/old_cards/H13.png and /dev/null differ diff --git a/resources/old_cards/H14.png b/resources/old_cards/H14.png deleted file mode 100644 index d4ca593..0000000 Binary files a/resources/old_cards/H14.png and /dev/null differ diff --git a/resources/old_cards/H15.png b/resources/old_cards/H15.png deleted file mode 100644 index 7860aae..0000000 Binary files a/resources/old_cards/H15.png and /dev/null differ diff --git a/resources/old_cards/H3.png b/resources/old_cards/H3.png deleted file mode 100644 index eecb3af..0000000 Binary files a/resources/old_cards/H3.png and /dev/null differ diff --git a/resources/old_cards/H4.png b/resources/old_cards/H4.png deleted file mode 100644 index b026b8a..0000000 Binary files a/resources/old_cards/H4.png and /dev/null differ diff --git a/resources/old_cards/H5.png b/resources/old_cards/H5.png deleted file mode 100644 index 9002f72..0000000 Binary files a/resources/old_cards/H5.png and /dev/null differ diff --git a/resources/old_cards/H6.png b/resources/old_cards/H6.png deleted file mode 100644 index 5a1750c..0000000 Binary files a/resources/old_cards/H6.png and /dev/null differ diff --git a/resources/old_cards/H7.png b/resources/old_cards/H7.png deleted file mode 100644 index 9d5d704..0000000 Binary files a/resources/old_cards/H7.png and /dev/null differ diff --git a/resources/old_cards/H8.png b/resources/old_cards/H8.png deleted file mode 100644 index 15a2c8d..0000000 Binary files a/resources/old_cards/H8.png and /dev/null differ diff --git a/resources/old_cards/H9.png b/resources/old_cards/H9.png deleted file mode 100644 index b1138cb..0000000 Binary files a/resources/old_cards/H9.png and /dev/null differ diff --git a/resources/old_cards/K16.png b/resources/old_cards/K16.png deleted file mode 100644 index 69386a3..0000000 Binary files a/resources/old_cards/K16.png and /dev/null differ diff --git a/resources/old_cards/K17.png b/resources/old_cards/K17.png deleted file mode 100644 index e923924..0000000 Binary files a/resources/old_cards/K17.png and /dev/null differ diff --git a/resources/old_cards/S10.png b/resources/old_cards/S10.png deleted file mode 100644 index 0ec52f1..0000000 Binary files a/resources/old_cards/S10.png and /dev/null differ diff --git a/resources/old_cards/S11.png b/resources/old_cards/S11.png deleted file mode 100644 index 08b1e77..0000000 Binary files a/resources/old_cards/S11.png and /dev/null differ diff --git a/resources/old_cards/S12.png b/resources/old_cards/S12.png deleted file mode 100644 index f37cc36..0000000 Binary files a/resources/old_cards/S12.png and /dev/null differ diff --git a/resources/old_cards/S13.png b/resources/old_cards/S13.png deleted file mode 100644 index d65f379..0000000 Binary files a/resources/old_cards/S13.png and /dev/null differ diff --git a/resources/old_cards/S14.png b/resources/old_cards/S14.png deleted file mode 100644 index 22a3e5b..0000000 Binary files a/resources/old_cards/S14.png and /dev/null differ diff --git a/resources/old_cards/S15.png b/resources/old_cards/S15.png deleted file mode 100644 index 78182b8..0000000 Binary files a/resources/old_cards/S15.png and /dev/null differ diff --git a/resources/old_cards/S3.png b/resources/old_cards/S3.png deleted file mode 100644 index 05018be..0000000 Binary files a/resources/old_cards/S3.png and /dev/null differ diff --git a/resources/old_cards/S4.png b/resources/old_cards/S4.png deleted file mode 100644 index 1e90378..0000000 Binary files a/resources/old_cards/S4.png and /dev/null differ diff --git a/resources/old_cards/S5.png b/resources/old_cards/S5.png deleted file mode 100644 index 959e440..0000000 Binary files a/resources/old_cards/S5.png and /dev/null differ diff --git a/resources/old_cards/S6.png b/resources/old_cards/S6.png deleted file mode 100644 index 8a98853..0000000 Binary files a/resources/old_cards/S6.png and /dev/null differ diff --git a/resources/old_cards/S7.png b/resources/old_cards/S7.png deleted file mode 100644 index 67cae45..0000000 Binary files a/resources/old_cards/S7.png and /dev/null differ diff --git a/resources/old_cards/S8.png b/resources/old_cards/S8.png deleted file mode 100644 index 448a735..0000000 Binary files a/resources/old_cards/S8.png and /dev/null differ diff --git a/resources/old_cards/S9.png b/resources/old_cards/S9.png deleted file mode 100644 index da68980..0000000 Binary files a/resources/old_cards/S9.png and /dev/null differ