C ++ Qt design patterns 8 | simple implementation of 15 puzzle games. Please, don't be confused!

Source: Internet
Author: User

Chapter II: Introduction

I saw this game and it was quite interesting.

The interface is as follows:

Gameplay: In the matrix of 3x3, you can click each button. If one of the buttons is blank, clicking this button will move to this blank. The button is changed to "ABCD..." in alphabetical order ......" In this way, the Order will win, and finally the space can appear anywhere.

 

Chapter 1: Conception

The design pattern has never been touched, so I didn't follow the method in the book. I thought about how to implement it. Maybe I didn't have the way it provided, but after all, it's a cainiao. Let's do it step by step!

1. What are these buttons used?

After learning QGridLayOut and "The QGridLayout class lays out widgets in a grid", it is easy to do. It will put The Form Control in a grid, that is, similar to The matrix, ABC ...... These must be QPushButton one by one. Create one by one buttons and then install them. Finally, set QGridLayOut to the LayOut of QDialog.

This is from the display layer.

2. How to Use code to represent a 3 × 3 matrix

Although you can place a form in a QGridLayOut for layout, it has the following add functions:

void    addWidget ( QWidget * widget, int row, int column, Qt::Alignment alignment = 0 )

However, since I am not familiar with QGridLayOut, I don't know if I can use a matrix-like access method, that is, to get the content in a row or column. So I used a matrix, which is a two-dimensional array. corresponding to each button, the pointer to the button is put in the array, and a NULL pointer is put in the blank space, because several buttons are created in the memory, and they do not move, so when I swap a button and a blank one, we need to swap the two pointers and add the method of re-QGridLayOut addWidget.

3. required classes

Two classes are required: one MyButton, the public inheritance QPushButton, And the Dialog class, and the public inheritance QDialog. the main interface is displayed.

4. How can I move a button?

When you click the button, the button emits the clicked () signal, but the Dialog class does not know which button is used. Therefore, you need to re-transmit a signal and use this as a parameter to point to your own pointer, after the Dialog class is pressed, you can know who it is and you need to move it when judging it.

 

Chapter 3: Implementation of the MyButton class

Directly run the Code:

1 # ifndef MYBUTTON_H 2 # define MYBUTTON_H 3 4 # include <QPushButton> 5 6 7 struct Coord 8 {9 int x; 10 int y; 11}; 12 13 14 class MyButton: public QPushButton15 {16 Q_OBJECT17 18 private: 19 Coord m_coord; 20 21 public: 22 explicit MyButton (char c, Coord coord, QWidget * parent = 0 ); 23 void setCoord (Coord newCd); 24 Coord getCoord () const; 25 26 signals: 27 void myClick (MyButton * p); // signal, argument is poiter to myself, so someone else can identify me28 29 private slots: 30 void btClicked (); 31}; 32 33 # endif // MYBUTTON_HMybutton. h 1 # include "mybutton. h "2 3 # include <QMessageBox> 4 5 MyButton: MyButton (char c, Coord coord, QWidget * parent): QPushButton (parent) 6 {7 8 setText (QString ("% 1 "). arg (c); 9 this-> m_coord = coord; 10 connect (this, SIGNAL (clicked (), this, SLOT (btClicked ())); 11} 12 13 void MyButton: setCoord (Coord newCd) 14 {15 m_coord = newCd; 16} 17 18 Coord MyButton: getCoord () const19 {20 return m_coord; 21} 22 23 24 void MyButton: btClicked () 25 {26 emit myClick (this); 27}Mybutton. cpp

I gave each button a coordinate data, because after the button is created, it will not move to a certain location in the memory. How do I show which one of them is displayed? This coordinate is equivalent to marking a button, ABCD ...... They only display the text, which remains unchanged.

The char parameter of the constructor is what it wants to display, and Coord is a custom struct that represents coordinates.

 connect(this,SIGNAL(clicked()),this,SLOT(btClicked()));
void MyButton::btClicked(){    emit myClick(this);}

Pay attention to this, so that the Dialog class can write a slot by itself. The above this parameter can tell which button is clicked, and I have been thinking about it for a long time ......

 

Chapter 4: Implementation of the Dialog class

1. Class declaration:

1 # ifndef DIALOG_H 2 # define DIALOG_H 3 4 # include <QDialog> 5 # include "mybutton. h "6 7 class QGridLayout; 8 class QPushButton; 9 10 namespace Ui {11 class Dialog; 12} 13 14 class Dialog: public QDialog15 {16 Q_OBJECT17 18 public: 19 explicit Dialog (QWidget * parent = 0); 20 ~ Digri(); 21 22 private: 23 Ui: Dialog * ui; 24 25 static const int N = 3; 26 QGridLayout * m_lay; 27 MyButton * m_pbArr [N] [N]; 28 QString m_btnTextOrder; 29 private slots: 30 void btClicked (MyButton * p ); // one of N * N buttons has been clicked31 32 private: 33 void disorder (); // disorder the N * N buttons34 void exchangeButton (Coord a, Coord B ); // exchange two buttons based on coord35 bool isOver () const; // is it in Order ??? 36}; 37 38 # endif // DIALOG_HDialog. h

I will explain the meaning of data members one by one. The source code is not annotated because it cannot be entered in Chinese, so I don't want to be too short for comment ......

Static const int N = 3; it indicates the matrix of number multiplied

QGridLayout * m_lay; Layout

MyButton * m_pbArr [N] [N]; corresponds to the layout matrix. All the pointers in the array point to the button, to move a button, you only need to swap the corresponding pointer, change the private coordinate of the button, and get it in the layout.

QString m_btnTextOrder;

2. constructor:

1 Dialog: Dialog (QWidget * parent): 2 QDialog (parent), 3 ui (new Ui: Dialog) 4 {5 ui-> setupUi (this ); 6 setWindowTitle ("Let us have a game! "); 7 setMinimumSize (300,250); 8 setMaximumSize (300,250); 9 10 m_lay = new QGridLayout (this); 11 12 for (int I = 0; I <N; I ++) 13 {14 int colums; 15 if (I <N-1) colums = N; 16 else colums = N-1; 17 18 for (int j = 0; j <colums; j ++) 19 {20 char c = I * N + j + 'a'; 21 m_btnTextOrder.append (c); 22 23 Coord cd = {I, j }; 24 m_pbArr [I] [j] = new MyButton (c, cd); 25 26 m_lay-> addWidget (m_pbArr [I] [j], I, j ); 27 connect (m_pbArr [I] [j], SIGNAL (myClick (MyButton *), this, SLOT (btClicked (MyButton *))); 28} 29} 30 m_pbArr [N-1] [N-1] = NULL; 31 this-> setLayout (m_lay); 32 33 disorder (); // make buttons disorder34}Constructor

First, the window size is fixed.

New QGridLayout.

Then, the double-layer loop is used to create button objects, create an object, and add it to QGridLayOut. In this way, the order is reached, and then the slot of each button is connected.

Finally, assign a value without a button in the last position as a null pointer.

The buttons are unordered at the end. This will be introduced later.

3. The button is clicked.

1 void Dialog: btClicked (MyButton * p) 2 {3 Coord cd = p-> getCoord (); // get the button that been clicked 4 Coord cdTarget = cd; // target position that maybe switch 5 6 if (cd. x-1> = 0) & (m_pbArr [cd. x-1] [cd. y] = NULL) // test top 7 {8 cdTarget. x --; 9} 10 else if (cd. x + 1 <N) & (m_pbArr [cd. x + 1] [cd. y] = NULL) // test down11 {12 cdTarget. x ++; 13} 14 else if (cd. y-1> = 0) & (m_pbArr [cd. x] [cd. y-1] = NULL) // test left1 5 {16 cdTarget. y --; 17} 18 else if (cd. y + 1 <N) & (m_pbArr [cd. x] [cd. y + 1] = NULL) // test right19 {20 cdTarget. y ++; 21} 22 else23 {24 return; // can not move this button25} 26 27/* let us switch! */28 exchangeButton (cd, cdTarget); 29 30/* check whether game is over */31 if (isOver () 32 {33 QMessageBox: warning (this, "Sucess", "You made it! Congratulations! "); 34} 35}Button clicking event

After being clicked, you can get the pointer of the button through the signal sent by the button, and then get the coordinates of the button through the button. Then, check whether there is a space between the upper and lower sides of the coordinate. If there is no space, do nothing. If there is one, move the button to that position, which is essentially an exchange.

1 void Dialog: exchangeButton (Coord a, Coord B) 2 {3 if (m_pbArr [a. x] [a. y]! = NULL) & (m_pbArr [B. x] [B. y]! = NULL) // no NULL 4 {5/* remove from pre QGridLayOut */6 m_lay-> removeWidget (m_pbArr [. x] [. y]); 7 m_lay-> removeWidget (m_pbArr [B. x] [B. y]); 8 9/* add to QGridLayOut */10 m_lay-> addWidget (m_pbArr [. x] [. y], B. x, B. y); 11 m_lay-> addWidget (m_pbArr [B. x] [B. y],. x,. y); 12 13/* change two buttons's coord */14 m_pbArr [. x] [. y]-> setCoord (B); 15 m_pbArr [B. x] [B. y]-> setCoord (a); 16 17/* exchange poiter in m_pbArr [] */18 MyButton * temp = m_pbArr [. x] [. y]; 19 m_pbArr [. x] [. y] = m_pbArr [B. x] [B. y]; 20 m_pbArr [B. x] [B. y] = temp; 21} 22 else // one of two buttons 'position is NULL (in array m_pbArr []) 23 {24 if (m_pbArr [. x] [. y] = NULL) 25 {26 Coord temp = a; 27 a = B; 28 B = temp; 29} 30 31/* here, we can make sure that coord B is null */32 m_lay-> removeWidget (m_pbArr [. x] [. y]); 33 m_lay-> addWidget (m_pbArr [. x] [. y], B. x, B. y); 34 m_pbArr [. x] [. y]-> setCoord (B); 35 MyButton * temp = m_pbArr [. x] [. y]; 36 m_pbArr [. x] [. y] = m_pbArr [B. x] [B. y]; 37 m_pbArr [B. x] [B. y] = temp; 38} 39}Exchange button

The exchange is divided into two weeks. Two buttons are exchanged, which is called when the interface is disordered. The other is the exchange button and the blank. It is enough to check the previous one.

First, remove the two buttons to be switched from QGridLayOut, which means they are not displayed.

Then add the coordinates to QGridLayOut.

Then, exchange the private data of the two buttons, that is, the coordinates, because the coordinates are obtained from the position of the clicked button.

The data layer (QGridLayOut is the display layer) pointer is also exchanged, let them point to the right button memory.

4. Make it sequent

1 void Dialog: disorder () 2 {3 Coord cdA, cdB; 4 for (int I = 0; I <56; I ++) 5 {6 QTime time = QTime:: currentTime (); 7 qsrand (time. msec () * 7 + time. second () * 245); 8 cdA. x = qrand () % n; // from 0 to N-1 9 qsrand (time. second () + I * 3 + 91); 10 cdA. y = qrand () % N; 11 12 qsrand (time. msec () * 3 + I); 13 cdB. x = qrand () % N; 14 qsrand (time. msec () + I * 11); 15 cdB. y = qrand () % N; 16 17 // qDebug () <cdA. x <cdA. y <"-----" <cdB. x <cdB. y <endl; 18 if (cdA. x = cdB. x) & (cdA. y = cdB. y) 19 {20 I --; 21} 22 else // not the same coord23 {24 exchangeButton (cdA, cdB); 25} 26} 27}Disordered

The game starts out of order. This function is used to do this. With the above exchange, you only need to generate the coordinates and switch the buttons of the specified coordinates. The key here is the function that generates coordinates immediately. I did not write well. During debugging, we can see that many pairs of coordinates are the same, because the computer is too fast.

5. Check whether the detection is complete

1 bool Dialog: isOver () const 2 {3 QString res; 4 for (int I = 0; I <N; I ++) 5 {6 for (int j = 0; j <N; j ++) 7 {8 if (m_pbArr [I] [j]! = NULL) 9 {10 res. append (m_pbArr [I] [j]-> text (); 11} 12} 13} 14 15 if (res = m_btnTextOrder) 16 {17 return true; 18} 19 else20 {21 return false; 22} 23}End?

Each time you click a button, the execution is finished. What I write is to read the text one by one in the matrix order, append it to a string, and finally add it to "ABCD ......" String comparison. If it is equal, it is over.

 


Chapter 5: Last words

1. QGridLayOut

The display is separated from the data representation. This is not good.

2. La la

Will I tell you that I only succeeded once?

I wonder if the random exchange will fail? Mathematical theory!

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.