Programming C # implementing the principle of jigsaw puzzle (II,

Source: Internet
Author: User
Tags integer division

Programming C # implementing the principle of jigsaw puzzle (II,

Preface:In the http://www.cnblogs.com/labixiaohei/p/6698887.html programming C # Implementation of the "puzzle game" (on), uploaded the code of each module, and in this article will be detailed analysis of the principle, so that readers can more easily understand and learn, the program has many problems. Please note that you can learn and grow together!

Body:

Jigsaw puzzle is a very classic game. Basically everyone knows how to play it. It starts, runs, and ends. So how do we get started when we want to make a puzzle? The answer is: from the reality, describe the requirement (as much as possible to the Document). When we have a comprehensive requirement, we can provide reliable policies to implement them in the code, eventually become a work!

(1) requirements:(This requirement is relatively sloppy and customized for the majority of white people, according to the thinking of the most common people, according to the process of participating in the game)

1. Picture: we have at least one picture for a puzzle.

2. Cutting: A puzzle is not a graph. We need to cut an integral graph into a small graph of N * N.

3. Disrupt: disrupt the order of N * N small images, but ensure that the smaller images can be restored after walking through game rules.

4. Judgment: the puzzle is judged to be successful.

5. Interaction: Which interaction mode do we use? Click here

6. display the complete thumbnail of the original image

The above are basic functions, and the following are extended functions.

7. Number of record steps: number of steps required for record completion

8. Change the image: Can we change the image for a long time? haha

9. Selection difficulty: too simple? No! 3*3 get 5*5, 5*5 get 9*9, roommates challenge the most difficult more than 3000 steps, distressed my mouse TAT

(2) Analysis:

With the demand, we can analyze how to implement it (map the actual needs to the computer), including:

1. Development Platform: Select C # Language

1. Storage: which includes what we want to save? What structure do we use for storage? On the other hand, we will find that some resources need to be stored.

Image: Using Image Object Storage

Unit (the Sub-Image set after the original Image is cut): the user-defined structure struct Node, including the Image object used to store the small Image unit, and the number stored by the integer (after cutting, each small unit is numbered to check whether the game is complete ).

Each unit (the Sub-image set after the original image is cut): two-dimensional arrays (like puzzles, wuziqi, xiaohappy, and even watching, Russian square, and other flat dot matrix games can be used for storage, why? Because it looks like it !) To store

Difficulty: Use a custom Enumeration type (simple and common and difficult) for storage

Steps: integer int Num Storage

With storage, we can think about the division of modules (the correct logical division has been extended, and communication can be made clearer), build and implement the specific algorithms involved in each module

First, the program modules are divided into four modules:

  Logical type:

1. puzzles: used to describe puzzles

2. configuration class: store configuration variables

  Character Type:

3. game menu window: Set Menu Options

4. Game running window: Main game interface

 

1. You can use the game menu to manipulate configurations, such as difficulty or images.

2. You can access and obtain game configurations in the running window, and use the corresponding structure of the puzzle object.

3. the user interacts through the running window and indirectly calls the moving method of the puzzle object to obtain the pattern method.

I think the most problematic part of code reading is to write the difficult Enumeration type in the puzzle class, which should be written in the configuration class or individually written into the class, changes made by readers

Public enum Diff // game difficulty {simple, // simple ordinary, // common difficulty // difficulty}

 

We can think that the configuration class is like data storage, while the puzzle class is used for logic processing, and the menu and running window are used for interaction. I admit that this design is not very reasonable, however, when the scale of the problem is not large enough, will the program become bloated if you think too much about the design? I think there must be a degree. I don't know how much it is, but I feel that it is good to implement this program and indulge in design (routine type). Sometimes it is not worth the candle. (Personal immature small opinion)

(3) code implementation:

Note: This module focuses on the implementation of the Puzzle (Puzzle) Class and the game running class and the entity communication:

Construction Method of the puzzle:

1. assignment:

Public Puzzle (Image Img, int Width, Diff GameDif) // the Image of the Puzzle, Width (explanation: the side length of the square, unit: pixel, name is ambiguous, sorry), difficulty in the game

 

The difficulty of the game determines the degree and degree of separation, and determines the size of the array you store. For example, it simply corresponds to three rows and three columns, and generally corresponds to five rows and five columns, difficulties correspond to 9 rows and 9 Columns

 

Switch (this. _ gameDif) {case Diff. simple: // simple, the cell array is saved as a 3*3 two-dimensional array this. N = 3; node = new Node [3, 3]; break; case Diff. ordinary: // generally 5*5 this. N = 5; node = new Node [5, 5]; break; case Diff. difficulty: // 9*9 this is difficult. N = 9; node = new Node [9, 9]; break ;}

2. Split the image

// Split the image to form each unit and save it in the array int Count = 0; for (int x = 0; x <this. n; x ++) {for (int y = 0; y <this. n; y ++) {node [x, y]. img = CaptureImage (this. _ img, this. width/this. n, this. width/this. n, x * (this. width/this. n), y * (this. width/this. n); node [x, y]. num = Count; Count ++ ;}}

In fact, the process of assigning values to the cell array uses a double for loop to traverse the two-dimensional array, and then assigns the number node [x, y]. Num in order;

 

Then, for node [x, y]. img, that is, assign a value to a small image of a Unit. The assignment method is to write a method to the image class library of C, truncate the small image corresponding to the corresponding position in the big image and save it in node [x, y]. img;

What is width/N? Is the side length divided by the number of rows, that is, the interval, that is, the side length of each unit! Then the starting coordinate (X, Y) is to say, after several units, my position,

That is: (x, y) = (Unit edge length * Number of units separated from the start x axis, unit edge length * Number of units separated from the start y axis );

We hope that readers can draw more pictures and then understand these problems;

 public  Image CaptureImage(Image fromImage, int width, int height, int spaceX, int spaceY)

Main logic: Use the DrawImage method:

// Create a new map Bitmap bitmap = new Bitmap (width, height); // create a drawing area Graphics graphic = Graphics. fromImage (bitmap); // extract the source image from the corresponding area and write it into the graph area graphic. drawImage (fromImage, 0, 0, new Rectangle (x, y, width, height), GraphicsUnit. pixel); // generate a new Image from the drawing area. Image saveImage = Image. fromHbitmap (bitmap. getHbitmap ());

After division, we need to make a special process, because we know that there is always a white location, right? We default to the last location, that is, node [N-1, N-1];

I wrote a white image and painted red borders around it. It was found that there were some notable elements. I also drew edges for other units, but it is white, and it is also to be distinguished in view of the puzzle. This code is not described.

 

3. Disrupt the image:

In fact, it is to disrupt the two-dimensional array. We can adopt some sort disrupt methods, but please note! Not every disruption can be recovered!

How can this problem be achieved? The method is easy to understand, that is, to allow our computers to walk a full set of orderly units according to the walking methods provided in the rules for a large number of times before the start! That is to say, this method can definitely go back!

First, let's take a look at the specific disruption methods, which will be explained later.

 

Move ):

The movement of squares in the puzzle game is actually the exchange of two adjacent units, and the two units, there must be a white unit (that is, the node [N-1, N-1] unit mentioned above, his number is N * N-1, I suggest you calculate it by yourself)

So our judgment condition is that if we move a square, his up and down left and right in four directions, once there is an adjacent is a white unit, that is, N * N-1 number unit, then exchange with it. This is the basic logic, but does not include constraints. When our array reaches the boundary, we cannot access cross-border data. For example, when the unit is node [0, 0, you cannot access the data above and on the right, because Node [-] Node [0,-1] will cross the border and an exception occurs.

Moved successfully. TRUE is returned.

Failed to move. FALSE is returned.

/// <Summary> // move the coordinates (x, y) tile unit // </summary> /// <param name = "x"> x coordinate of the tile Unit </param> /// <param name = "y"> unit y coordinate </param> public bool Move (int x, int y) {// MessageBox. show ("" + node [2, 2]. num); if (x + 1! = N & node [x + 1, y]. num = N * N-1) {Swap (new Point (x + 1, y), new Point (x, y); return true ;} if (y + 1! = N & node [x, y + 1]. num = N * N-1) {Swap (new Point (x, y + 1), new Point (x, y); return true ;} if (x-1! =-1 & node [x-1, y]. num = N * N-1) {Swap (new Point (x-1, y), new Point (x, y); return true ;} if (y-1! =-1 & node [x, y-1]. num = N * N-1) {Swap (new Point (x, y-1), new Point (x, y); return true;} return false ;}

Swap: Swap the positions of two elements in the array. This method should not be accessed outside the class.

// Switch two cells private void Swap (Point a, Point B) {Node temp = new Node (); temp = this. node [. x,. y]; this. node [. x,. y] = this. node [B. x, B. y]; this. node [B. x, B. y] = temp ;}

 

Disruption method:

As mentioned above, it is actually a lot of calls to the Move (int X, int y) method, that is to say, we randomly select one of the four adjacent blocks at the upper, lower, and lower spaces, and transfer the coordinates to Move the blocks to Move them. We also need to consider cross-border operations, A large number of such operations are repeated! You can check the code and use random numbers.

/// <Summary> /// disrupt the puzzle /// </summary> public void Upset () {int sum = 100000; if (this. _ gameDif = Diff. simple) sum = 10000; // if (this. _ gameDif = Diff. ordinary) sum = 100000; Random ran = new Random (); for (int I = 0, x = N-1, y = N-1; I <sum; I ++) {long tick = DateTime. now. ticks; ran = new Random (int) (tick & 0 xffffffffL) | (int) (tick> 32) | ran. next (); switch (ran. next (0, 4) {case 0: I F (x + 1! = N) {Move (x + 1, y); x = x + 1;} break; case 1: if (y + 1! = N) {Move (x, y + 1); y = y + 1;} break; case 2: if (x-1! =-1) {Move (x-1, y); x = x-1;} break; case 3: if (y-1! =-1) {Move (x, y-1); y = y-1 ;}break ;}}}

Method for returning an image:

Why did you get such a ghost name... DisPlay...

This method is just opposite to the segmentation method. This method is actually to traverse the array and combine it. The combination method is very simple, draw them one by one on a blank drawing of the same size as the source image! Finally, submit the drawing, that is, return an Image;

Public Image Display () {Bitmap bitmap = new Bitmap (this. width, this. width); // create the drawing area Graphics newGra = Graphics. fromImage (bitmap); for (int x = 0; x <this. n; x ++) for (int y = 0; y <this. n; y ++) newGra. drawImage (node [x, y]. img, new Point (x * this. width/this. n, y * this. width/this. n); return bitmap ;}

We also use the DrawImage method and know how to separate it. This should be easy to understand. We will understand how to calculate and compare it on paper;

 

Judgment Method:

This method is easy to understand, that is, in order! Traverse all cells if their results contain a cell number

Node [x, y]. Num is not equal to the serial number of the traversal. This indicates that the Unit is not in the original position. That is, if the image is not complete, false is returned.
If all the traversal results are correct, we can think that the image has been restored and the true value is returned.

public bool Judge() { int count=0; for (int x = 0; x < this.N; x++) { for (int y = 0; y < this.N; y++) { if (this.node[x, y].Num != count) return false; count++; } } return true; }

 

 

Game running window: The Window used for interaction during game play

Here is only one method: How should we handle and respond to a user's mouse click event?

To put it bluntly, this sentence is hard to understand:

Puzzle. Move (e. X/(puzzle. Width/puzzle. N), e. Y/(puzzle. Width/puzzle. N ))

The mobile method is called to move the square

X coordinate: e. X/(puzzle. Width/puzzle. N)
Y/(puzzle. Width/puzzle. N)

The integer division in our programming is different from the division in mathematics! For example, if 10/4 is math equal to 2 + 2 or 2.5, the computer directly equals 2 and only takes the integer part.


Number of rows = line coordinate/square side length

Number of columns = column coordinate/square length

Let's look at P1 and P2.

P1: 40/30*30 = 1
P2: 50/30*30 = 1

We will find that in the same cell, the algorithm can be converted
The same coordinate.

(E. x, e. y) Click coordinates for the mouse click event

Private void picturebox#mouseclick (object sender, MouseEventArgs e) {if (puzzle. move (e. x/(puzzle. width/puzzle. n), e. y/(puzzle. width/puzzle. n) {Num ++; pictureBox1.Image = puzzle. display (); if (puzzle. judge () {if (MessageBox. show ("congratulations", "Whether to play again", MessageBoxButtons. OKCancel) = DialogResult. OK) {Num = 0; puzzle. upset (); pictureBox1.Image = puzzle. display () ;}else {Num = 0; closefather (); this. close () ;}} NumLabel. text = Num. toString ();}

 

Well, the general logic is that the algorithm that needs to be considered in the program has been finished. There are still some things I don't quite understand ~ What ~

Added the music history score with a small feature.

 

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.