Use STL to implement DFS/BFS algorithms-push box games (1)

Source: Internet
Author: User
Use STL to implement DFS/BFS Algorithms -- Push box games (1)A box-pushing game must have been played by many friends. Simply put, in the M * n range, there are K boxes and K destinations, you can only use the push method to move the box. You cannot drag or push two or more boxes. The activity scope is usually narrow and there are some unmovable obstacles, therefore, it is difficult and playable. The following is a hard box-pushing question: You can see that the center of the figure is the "person" (Soko) responsible for pushing the box; surrounded by non-moving obstacles (Wall ), there are also some in the middle; the gray is space; the right side of Soko is a box, because it is not on the destination, so it is represented in yellow; there is a purple red dot in the open space at the bottom right of Soko, indicating that this is the destination of a parked box (DEST). There are three blue boxes in the top, top left, and top right of Soko, it indicates that the three boxes have been placed on the destination (however, to move all the boxes to the destination, these boxes can also be removed ). Therefore, the question of this push box has four boxes and four destinations. First, we need to determine how to indicate a certain state of the push box problem in the program. The simplest way to think of it is to use a m * n two-dimensional char array to represent, each char in the array represents a cell in the graph, A grid may be an obstacle, a person, a box, a destination, or a space. These statuses may overlap. For example, a person can stand on a destination, or a box can be placed on a destination. We use the following Char to indicate the possible lattice states: charwall = 'w', // wall obstacle charbox = 'B', // box, not in the destination charspace ='s, // space, nothing chardest = 'D', // DEST destination charindest = 'I ', // charsoko = 'k', // The Person Who pushes the box on the destination. The person who pushes the box not at the destination charsokoindest = 'O', // The Person Who pushes the box on Soko, this method is used to represent the preceding question in the charerror = 'E' // error status of the destination. The two-dimensional array on the right is displayed, with the number of rows and number of columns being 9. You can see that the Left graph is not a neat two-dimensional graph, and there are some gaps in its periphery. We use 'w' to represent all of them in the right graph. It is obvious that they have no effect, just to fill the image into a neat two-dimensional array. It doesn't matter if you want to use 's', it won't affect our program execution, but I think 'W' is more appropriate. The above is a text representation of the problem status of the push box, or an input and output method, so that we can view the problem status. However, for computer program processing, it is not an ideal representation, and computers are better at processing binary numbers. Therefore, we should also use binary methods to indicate the state of the problem, so as to facilitate program processing. Similarly, we still use a two-dimensional array, but the element of this array is not a char character, but a binary unsigned char. After a simple analysis, we can know that a grid can use four bits to represent all States: flagwall = 0x01, // whether the obstacle flagbox = 0x02, // whether there is a box flagdest = 0x04, // whether the destination flagsoko = 0x08 // whether there is a problem in the input or output status, the conversion between the two representations is required. That is, when the input is used, the text notation is converted to the binary notation; when the output is used, the binary notation is converted to the text notation. This is not difficult. The relevant code will be listed later. Now, let's first define the problem status class. Like the Data independence problem we have seen before and the problem of Queen N, we need to design the problem status class to use the DFS/BFS algorithm. For the box pushing problem, we name the problem status class sokostate. Its definition should be as follows: Class sokostate {public: sokostate (): rows _ (0 ), cols _ (0) {} void nextstep (vector <sokostate> &) const; bool istarget () const; bool operator <(const sokostate & Other) const; friend ostream & operator <(ostream & OS, const sokostate & S); friend istream & operator> (istream & is, sokostate & S); Private: struct sokostep; // records the moving int rows _, cols _; unsigned CHA of each step. R map _ [max_rows] [max_cols]; vector <sokostep> steps _ ;}; Needless to say, in the DFS/BFS algorithm, the problematic status class is to be put into the STL container, so it must have the default constructor. Sokostate has four member variables: number of rows _, number of columns Cols _, two-dimensional array map _, and a vector container Variable Steps _. The first three are easy to understand. They are exactly the binary notation we mentioned earlier. What is the last steps? It is precisely one of the obvious differences between the problem of pushing boxes and the problem of data independence and Queen n. Let's recall the DT independence question and the n queen question. Their problem status classes only record the current status data, and only the final answer status is found. As for how to change from the initial question status to the answer status step by step, this process is not recorded. This is because neither of these questions cares about the state evolution process, and they only care about the final answer status. But this is not the case for Box pushing. We need to know whether the box can be pushed to the destination. More importantly, we need to know how the box can be pushed to the destination step by step. Therefore, we need to record every step from the initial problem status to the answer status in the question status, which is the role of the member Variable Steps. We use a nested sokostep class to represent step movement and vector <sokostep> to represent the n-step movement. Since we do not know how many steps need to move from the initial problem status to the answer status, the vector container can help us easily save the data in each step. Since all four of our member variables have common value semantics, the copy constructors, value assignment operators, and destructor automatically generated by the compiler are fully available, saving a lot of effort. However, there are still many things to do later. The box pushing game is more difficult than the problem of data independence and Queen n. Let's start with the easy way to get the input and output operators first. As mentioned above, the process of input and output is actually the conversion of two kinds of notation. Let's first look at the input operator. Because the number of rows and columns of the Two-dimensional array also need to be input, I put them at the beginning, followed by the char array that specifies the number of rows and columns, each char in the array must be one of the seven characters ("wbsdiko"); otherwise, an exception is thrown to end the program. Each time a char is read, the corresponding elements of the map _ array (binary representation) are set based on the char (Text representation ). The following is a valid input text (for example, the previous question): 9. The code for the input operator is as follows: istream & operator> (istream & is, sokostate & S) {is> S. rows _; If (S. rows _ <min_rows | S. rows _> max_rows)
{
Throw invalid_argument ("rows of Soko game error .");
}
Is> S. Cols _;
If (S. Cols _ <min_cols | S. Cols _> max_cols)
{Throw invalid_argument ("Cols of Soko game error. ");} string STR; Getline (is, STR); // filter the line feed of the first line for (INT I = 0; I <S. rows _; I ++) {Getline (is, STR); For (Int J = 0; j <S. cols _; j ++) {S. map _ [I] [J] = 0; Switch (STR [J]) {Case sokostate: charbox: S. map _ [I] [J] | = sokostate: flagbox; break; Case sokostate: charwall: S. map _ [I] [J] | = sokostate: flagwall; break; Case sokostate: charspace: break; CA Se sokostate: chardest: S. map _ [I] [J] | = sokostate: flagdest; break; Case sokostate: charindest: S. map _ [I] [J] | = sokostate: flagdest | sokostate: flagbox; break; Case sokostate: charsoko: S. map _ [I] [J] | = sokostate: flagsoko; break; Case sokostate: charsokoindest: S. map _ [I] [J] | = sokostate: flagsoko | sokostate: flagdest; break; default: Throw invalid_argument (string ("char of Soko game error: ") + Str) ;}}s. stateeq (); return is ;}here a new member function stateeq () is introduced. What does it do? Let's put it aside and introduce it after the output operator. Now it is the turn of the output operator to convert binary notation to text notation. To simplify the code, we first provide some auxiliary member functions: Class sokostate {public :... PRIVATE: struct point {int X _, Y _; point (int x, int y): X _ (x), Y _ (y) {} Point up () {return point (X _-1, Y _);} point down () {return point (X _ + 1, Y _);} Point left () {return point (X _, Y _-1);} Point right () {return point (X _, Y _ + 1 );}}; enum mapchar {charwall = 'w', // wall obstacle charbox = 'B', // box, not in the destination charspace = 's', // space, nothing chardest = 'D', // DEST destination charindest = 'I', // already placed in the destination Charsoko = 'k', // The Person Who pushes the box on the ground, not the person who pushes the box at the destination charsokoindest = 'O', // The Person Who pushes the box on Soko, exactly in the destination charerror = 'E' // error status}; Enum mapflag {flagwall = 0x01, // whether the obstacle flagbox = 0x02, // whether there is a box flagdest = 0x04, // whether the destination flagsoko = 0x08 // whether there is anyone}; bool iswall (point P) const {return (MAP _ [p. X _] [p. Y _] & flagwall )! = 0;} bool isbox (point P) const {return (MAP _ [p. x _] [P. Y _] & flagbox )! = 0;} bool isdest (point P) const {return (MAP _ [p. x _] [P. Y _] & flagdest )! = 0;} bool issoko (point P) const {return (MAP _ [p. x _] [P. Y _] & flagsoko )! = 0;} bool isspace (point P) const {return! Iswall (p )&&! Isbox (p);} bool ispurespace (point P) const {return isspace (p )&&! Issoko (p);} unsigned char mapchar (point P) const ;...}; Inline unsigned char sokostate: mapchar (point P) const {If (iswall (p) return charwall; else if (isbox (p) return isdest (p )? Charindest: charbox; else if (issoko (p) return isdest (p )? Charsokoindest: charsoko; else if (isdest (p) return chardest; else return charspace;} Here we introduce the second nested class point to represent a cell in a two-dimensional graph, it has four member functions that return the upper, lower, and lower grids respectively. Then we have already introduced the two Enum and will not repeat them. Then there are six isxxxx functions used to determine whether there are obstacles, boxes, and people in the specified grid. It is worth noting the difference between isspace () and ispurespace (). The former can indicate someone in the grid, while the latter cannot. Finally, the mapchar () member function is used to return the text representation of the specified lattice, that is, one of "wbsdiko. With these auxiliary member functions, our output operators are very simple, as shown below: ostream & operator <(ostream & OS, const sokostate & S) {for (INT I = 0; I <S. rows _; I ++) {for (Int J = 0; j <S. cols _; j ++) {OS <S. mapchar (sokostate: Point (I, j);} OS <"/N";} OS <"----------------------" <Endl; return OS ;} now we return to the stateeq () member function, which is used to take the position that Soko (the person who pushes the box) can go without pushing the box (that is, his free range of activity) mark all flagsoko. In this way, we can make it easier to determine whether a box can be moved, as long as one side of the box is space and the other side is flagsoko, then the box can be moved to the empty side. Taking the previous problem as an example, the status of the problem after being handled by stateeq () Changes to: stateeq, the position of the Soko starts to set the flagsoko flag for the upper and lower left spaces, and then repeat this operation for all the grids with the flagsoko flag set until no new grids are set. The STL stack container is used in processing. The Code is as follows: void sokostate: stateeq () {int I, j; for (I = 1; I <rows _-1; I ++) {for (j = 1; j <Cols _-1; j ++) {If (issoko (point (I, j) break ;} if (j <Cols _-1) break;} stack <point> points; point P (I, j); points. push (p); While (! Points. empty () {P = points. top (); points. pop (); checksoko (points, P. up (); checksoko (points, P. down (); checksoko (points, P. left (); checksoko (points, P. right () ;}} void sokostate: checksoko (stack <point> & PS, point P) {If (ispurespace (p) {map _ [p. X _] [p. Y _] | = flagsoko; PS. push (p );}}

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.