How to use C # to write an example code share for a complete puzzle game

Source: Internet
Author: User
Tags decrypt

Introduced

Crossword puzzles, which you may have seen in many puzzle books. It's also interesting to try to write a crossword puzzle on a computer with different categories of content and have custom words to play.

Background

I used turbo C-coded games long ago, but I lost the code. I think in C #. NET it will be a great thing to revive it. The language provides a lot of flexibility in memory, GC, graphics, which I have to handle carefully when using C language. But a clear focus in C will make us learn a lot (that's why C is called "God's Programming Language"). On the other hand, because C #. NET takes care of these, so I can focus on other areas of enhancement, such as the direction of the word, overlap, cheat codes, scoring, encryption and so on. So there needs to be a balance in appreciating the two languages.

In the title I say it is "complete" for the following reasons:

1) It has some categories of preset words.

2) It saves words and fractions in an encrypted file so that no one can tamper with the file. If you want to tamper with it, it will revert to the preset and score from the beginning.

3) It has a cheat code, but cheating will not be conducive to scoring, and obviously cheat once the application will make the score zeroed.

4) It has a scoring mechanism.

Using code

The game provides the following features, which I'll discuss in a later section:

1) Load categories and words: Load words from a hard-coded preset in the program. However, if the player provides a custom word, the game will automatically store all these (along with the Presets) in the file and read from there.

2) put it on the grid: The game randomly places all the words in the 18x18 matrix. The direction can be horizontal, vertical, lower left, and lower right, as shown in.

3) Scoring: For different categories, the scores are stored separately. The score is calculated by multiplying the length of the word by the multiplication factor (here is 10). At the same time, after all the words have been found, the remaining time (multiplied by the multiplication factor) is added to the score.

4) Show hidden words: If the time is exhausted, the player still cannot find all the words, then the game will display the words that are not found in different colors.

5) Cheat code: Game on the game board to mention cheat code (MAMBAZAMBA). Cheat codes are simply set for a full day of time (86,400 seconds). However, applying cheat codes will also apply a penalty of zero scoring for this run.

1) Load categories and words:

Load presets

We have a simple class for holding categories and words:

Class wordentity{Public    string Category {get; set;}    public string Word {get; set;}}

We have some preset categories and words as follows. Presets are pipe-delimited, where each 15th word is a category name, followed by a word in that category.

private string preset_words = "countries| bangladesh| gambia| australia| england| nepal| india| pakistan| tanzania| srilanka| china| canada| japan| brazil| argentina| "+" music| pinkfloyd| metallica| ironmaiden| nova| artcell| feedback| orthohin| defleppard| beatles| adams| jackson| parton| houston| Shakira| "+ ...

We use encryption to write these words in the file. So no one can tamper with the file. For encryption I used a class that I borrowed from here. Simple to use-you need to pass strings and encrypted passwords for encryption. For decryption, you need to pass an encrypted string and password.

If the file exists, then we read the category and the word from there, otherwise we save the preset (and the user-defined word) and read it from the preset. This is done in the following code:

if (file.exists (file_name_for_storing_words))   //If WORDS File Exists, then read it.    ReadFromFile (); else{   //Otherwise Create the file and populate from there.    String encryptedwords = Stringcipher.encrypt (Preset_words, Encryption_password);    using (StreamWriter OutputFile = new StreamWriter (file_name_for_storing_words))        Outputfile.write (encryptedwords );    ReadFromFile ();}

The ReadFromFile () method simply reads from the file where the word is stored. It first attempts to decrypt the string read from the file. If it fails (determined by the returned blank string), it will display a message about the problem and reload from the built-in preset. Otherwise it reads from the string and divides them into categories and words, and places them in the word list. Each 15th word is a category, followed by a word under that category.

String str = File.readalltext (file_name_for_storing_words); string[] decryptedwords = Stringcipher.decrypt (str, Encryption_password). Split (' | '); if (Decryptedwords[0]. Equals (""))  //This means the file is tampered.{    MessageBox.Show ("The words file was tampered. Any categories/words saved by the player would be lost. ");    File.delete (file_name_for_storing_words);    Populatecategoriesandwords ();   Circular Reference.    return;} String Category = ""; for (int i = 0; I <= decryptedwords.getupperbound (0); i++) {    if (i% (max_words + 1) = = 0)   //Every 15th word is the category name.    {        Category = decryptedwords[i];        Categories.add (Category);    }    else    {        wordentity Word = new wordentity ();        Word.category = Category;        Word.word = Decryptedwords[i];        Wordslist.add (Word);}    }

Save the player's custom words

The game can supply custom words provided by the player. The device is in the same load window. Words should be at least 3 characters in length, up to 10 characters in length, and require 14 words--no more or no less. indicated in the label. Another word cannot be a sub-part of any other word. For example: There is no two words like ' JAPAN ' and ' Japanese ' because the former is included in the latter.

I will briefly describe the validity check. There are 3 instant checks for maximum length, minimum length, and space input (no spaces allowed). This is done by adding our custom handler control_keypress to the editingcontrolshowingevent of the word entry grid.

private void Wordsdatagridview_editingcontrolshowing (object sender, Datagridvieweditingcontrolshowingeventargs e) {        e.control.keypress-= new Keypresseventhandler (control_keypress);    e.Control.KeyPress + = new Keypresseventhandler (control_keypress);}

Whenever the user enters something, the handler is called and checks for validity. Complete the following:

TextBox TB = sender as textbox;if (E.keychar = = (char) keys.enter) {    if (TB). Text.length <= min_length)   //Checking Length    {        MessageBox.Show ("Words should is at least" + Max_length + "Characters long.");        E.handled = true;        return;}    } if (TB. Text.length >= max_length)   //Checking length{    MessageBox.Show ("Word Length cannot be more than" + max_length + ".");    E.handled = true;    return;} if (E.keychar.equals ('))  //Checking space; no space allowed. Other invalid characters check can is put here instead for the final check on the Save button click. {    MessageBox.Show ("No space, please.");    E.handled = true;    return;} E.keychar = char. ToUpper (E.keychar);

Finally, a validity check exists after you enter all the words and the user chooses to save and use a custom word. First it checks if 14 words have been entered. It then iterates through all 14 words and checks if they have invalid characters. It also checks for duplicate words. The word is added to the list when the check succeeds. Finally, commit another iteration to check if the word is contained in another word (for example, there are two words like ' JAPAN ' and ' Japanese ' because the former is included in the latter). Complete with the following code:

public bool Checkuserinputvalidity (DataGridView Wordsdatagridview, list<string> wordsbytheplayer) {if ( WordsDataGridView.Rows.Count! = max_words + 1) {MessageBox.Show ("You need to has" + Max_words + "WORDS in th E list.        Add more. ");    return false;                             } char[] Noletterslist = {': ', '; ', ' @ ', ' \ ', ' ' ', ' ' {', '} ', ' [', '] ', ' | ', ' \ \ ', ' < ', ' > ', '? ', ', ', '. ', '/',                            ' ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' 0 ', '-', ' = ', ' ~ ', '! ', ' # ', ' $ ',   '% ', ' ^ ', ' & ', ' * ', ' (', ') ', ' _ ', ' + '}; ' foreach (DataGridViewRow Itm in wordsdatagridview.rows) {if (itm.cells[0].        Value = = null) continue; if (Itm.cells[0]. Value.tostring (). IndexOfAny (noletterslist) >= 0) {MessageBox.Show ("should only contain letters. The word that contains something else and than letters is: ' + itm.cells[0].            Value.tostring () + "'");        return false; } IF (Wordsbytheplayer.indexof (itm.cells[0). Value.tostring ())! =-1) {MessageBox.Show ("Can ' t has duplicate word in the list. The duplicate word is: ' "+ itm.cells[0].            Value.tostring () + "'");        return false; } wordsbytheplayer.add (Itm.cells[0].    Value.tostring ());    } for (int i = 0; i < wordsbytheplayer.count-1, i++)//For every word in the list.        {string str = wordsbytheplayer[i];  for (int j = i + 1, J < Wordsbytheplayer.count; J + +)//Check existence with every other word starting from the next Word if (str. IndexOf (wordsbytheplayer[j])! =-1) {MessageBox.Show ("Can ' t has a word as a sub-part of anothe R word.                Such words is: ' + wordsbytheplayer[i] + "' and '" + wordsbytheplayer[j] + "'");            return false; }} return true;

The list of players is saved with the existing words, and the gamepad is opened with those words in the category.

2) put on the grid:

Place words on a grid

Words are placed on the grid by means of the Initializeboard () method. We place the words first in the character matrix (the two-dimensional character array) Words_in_board. Then we map this matrix in the grid. Iterate through all the words. Each word gets a random position under the random direction (horizontal/vertical/bottom Left/right). At this point, if we visualize, the word matrix will look a bit like this.

Placement is done through the Placethewords () method, which gets 4 parameters-the word direction, the word itself, the x-coordinate, and the y-coordinate. This is a key approach, so I'm going to explain these four directions one by one.

Horizontal direction

For the whole word, run the loop character by string. First it checks whether the word falls outside the grid. If this is true, then it returns to the calling procedure to generate a new random position and direction.

It then checks to see if the current character may overlap existing characters on the grid. If this happens, check if it is the same character. If it is not the same character, return to the calling method, requesting another random position and direction.

After these two checks, if placement is possible, place the word in the matrix and store the position and direction in the list in wordpositions by means of the method Storewordposition ().

for (int i = 0, j = placementindex_x; i < word.length; i++, J + +)// First we check if the word can be placed in the array. For this it needs blanks there. {if (J >= GridSize) return false;//falling outside the grid.    Hence placement unavailable. if (WORDS_IN_BOARD[J, placementindex_y]! = ' + ') if (words_in_board[j, placementindex_y]! = Word[i])//I f there is a overlap, then we see if the characters match.        If matches, then it can still go there.            {placeavailable = false;        Break }}if (placeavailable) {//If all cells were blank, or a non-conflicting overlap is available and then this word can be P Laced there.    So place it.    for (int i = 0, j = placementindex_x; i < word.length; i++, J + +) Words_in_board[j, placementindex_y] = word[i];    Storewordposition (Word, placementindex_x, placementindex_y, orientationdecision); return true;} break; 

Vertical/Bottom-left/right-hand direction

The same logic applies to a good layout for finding words in these 3 directions. They differ in the increment/decrement of the matrix position and boundary check.

After all the words are placed in the matrix, the Fillinthegaps () method fills the remainder of the matrix with random letters. The form now opens and triggers the paint () event. In this event, we draw a line that is ultimately displayed as a 40x40 pixel rectangle. Then we map our character matrix to the board.

Pen pen = new Pen (Color.FromArgb (255, 0, 0, 0)); Colourcells (Colouredrectangles, Color.lightblue); if (Failedrectangles.count > 0) colourcells (FailedRectangles, Color.forestgreen);//Draw horizontal lines.for (int i = 0; I <= GridSize; i++)    e.graphics.drawline (pen, Max, (i + 1 * 1, GridSize * + +, (i +) * +);//Draw vertical lines.for (int i = 0; I <= GridSize; i++)    E.graphics.dra Wline (pen, (i + 1) * max, Max, (i + 1) * +, GridSize * 40 + 40); Maparraytogameboard ();

The Maparraytogameboard () method simply places our character matrix on the board. We use the drawing code from MSDN. This iterates through all the characters in the matrix, places them in the middle of the 40x40 rectangle, and adjusts the margin to 10 pixels.

Graphics formgraphics = CreateGraphics (); Font drawfont = new Font ("Arial", 16); SolidBrush Drawbrush = new SolidBrush (color.black); string charactertomap;for (int i = 0; i < GridSize; i++) for    (in T j = 0; J < GridSize; J + +) {        if (Words_in_board[i, j]! = '        + ') {            Charactertomap = "" + Words_in_board[i, j]; "is needed as a means for conversion of character to string.            Formgraphics.drawstring (Charactertomap, Drawfont, Drawbrush, (i + 1) * + ten, (j + 1) * + +);}    }

Word Discovery and Validity check

The mouse click position and release location are stored in the point list. Call the Checkvalidity () method on the mouse button release event (Gameboard_mouseup ()). At the same time, when the user drags the mouse while the left button is pressed, we draw a line from the starting position to the mouse pointer. This is done in the Gameboard_mousemove () event.

if (Points.count > 1)    points.pop (); if (Points.count > 0)    points.push (e.location);//Form top = X = Distance  From top, left = Y = Distance from left.//however mouse location X = Distance from left, Y = Distance from top.//need an Adjustment to exact the location. Point topleft = new Point (Top, left); Point drawfrom = new Point (Topleft.y + points.toarray () [0]. X + ten, Topleft.x + points.toarray () [0]. Y + 80); Point drawto = new Point (Topleft.y + Points.toarray () [1]. X + ten, Topleft.x + Points.toarray () [1]. Y + 80); Controlpaint.drawreversibleline (Drawfrom, Drawto, Color.Black); Draw New Line

The validity of the word is checked in the Checkvalidity () method. It uses all the letters to make the words, and the letters are drawn by using the mouse to view the corresponding character matrix. Then check to see if the words in the word list really match. If it matches, the cell is updated by shading the cells to light blue and making the words in the word list dimmed.

Here is the code snippet that grabs the start and end of the line. First it checks whether rows fall outside the bounds. It then formulates the words and stores the coordinates of the matrix. Similarly, it checks the vertical, lower left, and right words, and tries to match accordingly. If this really matches, then we store the temporary rectangle in our colouredrectangles point list through the Addcoordinates () method.

if (Points.count = = 1) return; This is a doble click, no dragging, hence return.int StartX = Points.toarray () [1].    X/40; Retrieve the starting position of the line.int Starty = Points.toarray () [1]. Y/40;int EndX = Points.toarray () [0].      X/40; Retrieve the ending position of the line.int EndY = Points.toarray () [0]. Y/40;if (StartX > GridSize | | EndX > GridSize | | Starty > GridSize | | EndY > GridSize | |    Boundary checks. StartX <= 0 | | EndX <= 0 | | Starty <= 0 | |    EndY <= 0) {statuslabel.text = "nope!";    Statustimer.start (); return;} StringBuilder thewordintended = new StringBuilder (); list<point> temprectangles = new list<point> ();    Thewordintended.clear (); if (starty = = EndY)//horizontal line drawn. for (int i = StartX; I <= endx; i++) {thewordintended.append (words_in_board[i-1, StartY-1].        ToString ());    Temprectangles.add (New Point (i *, Starty * 40)); }

3) Scoring:

For scoring, we have scoring documents. If missing, one is created using the current score and category. Here, again, all the scores are combined in a large pipe-delimited string, and then the string is encrypted and put into the file. We have four entities.

Class scoreentity{Public    string Category {get; set;}    public string scorer {get; set;}    public int score {get; set;}    Public DateTime scoretime {get; set;} ............................

A maximum of 14 fractions is allowed for a category. First, all the scores in the score list are loaded, and then the sorted subset of the current classification score is obtained. In this subset, check whether the current score is greater than any available score. If it is, the current score is inserted. After that, check whether the number of subsets exceeds 14, and if it is exceeded, eliminate the last one. So the final score disappears, and the list always has 14 points. This is done in the Checkandsaveiftopscore () method.

Here, again, if someone tampered with the scoring file, then it will only start a new score. Tampering is not allowed.

4) Show hidden words:

If time is running out, then the game displays the words in green. First, get the words that the player can't find. It can be like this.

list<string> failedwords = new list<string> (); foreach (String Word in Word_array)    if (words_found. IndexOf (Word) = =-1)        failedwords.add (word);

Then, iterate through the failed word positions and develop a corresponding failed matrix. Finally, it invokes the form's Paint method by invalidating it.

foreach (String Word in Failedwords) {wordposition Pos = wordpositions.find (p = = p.word.equals (Word));        if (pos.direction = = direction.horizontal)//horizontal word. for (int i = pos.placementindex_x + 1, j = pos.placementindex_y + 1, k = 0; k < Pos.Word.Length; i++, k++) F    Ailedrectangles.add (New Point (i *, J * 40));        else if (pos.direction = = direction.vertical)//Vertical word. for (int i = pos.placementindex_x + 1, j = pos.placementindex_y + 1, k = 0; k < Pos.Word.Length; j + +, k++) F    Ailedrectangles.add (New Point (i *, J * 40));        else if (pos.direction = = direction.downleft)//down left word.            for (int i = pos.placementindex_y + 1, j = pos.placementindex_x + 1, k = 0; k < Pos.Word.Length; I--, j + +, k++)    Failedrectangles.add (New Point (i *, J * 40));        else if (pos.direction = = direction.downright)//down right word. for (int i = pos.placementindex_x + 1, j = pos.placementindex_y + 1, k = 0; k < Pos.Word.Length; i++, J + +, k++) Failedrectangles.add (new Point (i *, J * 40));} Invalidate ();

5) Cheat Code:

This is a small thing. This works on the KeyUp event, which captures all keystrokes to the cheatcode variable. In fact, we merge the keystrokes entered by the player in the game window and see if the code matches our Cheat_code (Mambazamba). For example, if the player presses "M" and "a", then we keep them as ' ma ' in the Cheatcode variable (because the MA still matches the Cheatcode mode). Similarly, if it matches the cheat_code pattern, a continuous variable is added. However, once it does not match the pattern (for example, ' Mambi '), it begins again.

Finally, if matched, activate the cheat code (increase the remaining time to a full day, i.e. 86,400 seconds) and apply the penalty.

Cheatcode + = E.keycode.tostring (). ToUpper (); if (Cheat_code. IndexOf (cheatcode) = =-1)    //Cheat code didn ' t match with any part of the Cheat code.    Cheatcode = ("" + E.keycode). ToUpper ();                         Hence Erase it to start over.else if (Cheatcode.equals (cheat_code) && words_found. Count! = max_words) {    clock.timeleft = 86400;                 Cheat code applied, literally unlimited time. 86400 seconds Equal 1 day.    Scorelabel.text = "score:0";    Statuslabel.text = "cheated! Penalty applied!! ";    Statustimer.start ();    Currentscore = 0;    Invalidate ();

What's interesting here is that we have to use the Wordslistview KeyUp event instead of the form. This is because after the game window is loaded, the list box has the focus, not the form.

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.