Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a crossword puzzle in WPF?

Tags:

c#

wpf

I created 10 x 10 TextBoxes and the user should input the words into the relevant TextBoxes for the position of the words. And I save everything into a textfile like this:

enter image description here

Then on WPF side , I read the textfile and populate the TextBoxes in a panel but the problem is that the crossword puzzle has down and across hints that lead you to the answer and each hint will have a number to indicate which is which. However I can't think of a way to link the number's puzzle number to the hints down and across number. This is how it looks like now:

enter image description here

Notice the numbers (I edited them in paint to visualize what I want) beside the across and down, I need that numbers to be displayed.

In my database, I stored the location of the file in a table, and the hints and answer in another table like this:

enter image description here

And this is the hints (across and down) and answer:

enter image description here

I am using Entity framework lambda expressions to retrieve the across and down.

Appreciate any help on this to link the assign the numbers to Across and Down from the puzzle.

This is my code to display the puzzle :

  protected void Across()
    {
        IList<ModelSQL.puzzlecontent> lstAcross = daoPuzzleContent.GetAcross();

        foreach (ModelSQL.puzzlecontent lista in lstAcross)
        {
            Label tbA = new Label();
            tbA.Content = lista.Hint;
            tbA.Width = Double.NaN;
            tbA.BorderBrush = Brushes.CadetBlue;
            tbA.BorderThickness = new Thickness(2);
            stackPanel1.Width = Double.NaN;
            stackPanel1.Children.Add(tbA);
            words.Add(lista.Answer);

        }
    }

    protected void AddPuzzle()
    {
        // foldername of the txt file.
        //  using (StreamReader reader = File.OpenText((@daoWordPuzzle.GetfileURL())))
        string[] fileData = File.ReadAllLines(@"C:\Users\apr13mpsip\Desktop\OneOrganizer\OneOrganizer\WordPuzzle\educational.txt");

        string[] lineValues;

        int row = 0;
        int col;
        int hint = 1;

        string[][] rowcol = new string[fileData.Length][];

        foreach (string line in fileData)
        {
            lineValues = line.Split(new string[] { "," }, StringSplitOptions.None);


            rowcol[row] = new string[lineValues.Length];

            col = 0;

            foreach (string value in lineValues)
            {
                rowcol[row][col] = value;
                col++;
            }
            row++;

        }


        for (int i = 0; i < rowcol.GetLength(0) ; i++)
        {
            for (int j = 0; j < rowcol[i].GetLength(0) ; j++)
            {


                int iadd =  i+1 < rowcol.GetLength(0) ? i+1 : 100;
                int iminus = i-1 >= 0 ? i-1 : 100;
                int jadd =  j+1 < rowcol.GetLength(0) ? j+1 : 100;
                int jminus = j-1 >= 0 ? j-1 : 100;
                var self = rowcol[i][j]; // current value

                var top = iminus == 100 ? "" : rowcol[iminus][j];
                var bottom = iadd == 100 ? "" : rowcol[iadd][j];
                var left = jminus == 100 ? "" : rowcol[i][jminus];
                var right = jadd == 100 ? "" : rowcol[i][jadd];

                //ACROSS HORIZONTAL
                if (
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(right) && String.IsNullOrEmpty(bottom) && !String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(right) && String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && !String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left))
                  )
                {
                    wordAcross = "";
                    for (int k = 0; k < 10; k++)
                    {
                        wordAcross += rowcol[i][k];
                        if (k == 9)
                        {
                            puzzlewordAcross.Add(wordAcross);
                            // print hello and live
                        }
                    }

                }

                //DOWN VERTICAL
                if (
                     (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(top) && !String.IsNullOrEmpty(left)) ||
                     (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left)) ||
                     (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(left))
                    )
                {

                    wordDown = "";
                    for (int k = 0; k < 10; k++)
                    {
                        wordDown += rowcol[k][j];
                        if (k == 9)
                        {
                            puzzlewordDown.Add(wordDown);
                            // print holy and leducated 
                        }


                    }
                }

                //Check Top , Left , Bottom , Right value.                      
                if (
                    (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(top) && !String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && !String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(top) && !String.IsNullOrEmpty(right) && String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && !String.IsNullOrEmpty(top) && !String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(top) && String.IsNullOrEmpty(right) && !String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(left)) ||
                    (!String.IsNullOrEmpty(self) && String.IsNullOrEmpty(top) && !String.IsNullOrEmpty(right) && String.IsNullOrEmpty(bottom) && String.IsNullOrEmpty(left))

                   )
                {

                    TextBox tbox = new TextBox();
                    tbox.Height = 50;
                    tbox.Width = 50;
                    tbox.Text = hint.ToString();
                    wrapPanel1.Children.Add(tbox);



                    tbox.GotFocus += (source, e) =>
                    {
                        if (!string.IsNullOrEmpty(tbox.Text))
                        {
                            string Str = tbox.Text.Trim();
                            double Num;
                            bool isNum = double.TryParse(Str, out Num);
                            if (isNum)
                                tbox.Text = "";
                        }
                        else
                        {
                            tbox.Text = "";
                        }

                    };

                    hint++;
                }
                else
                {
                    TextBox tbox2 = new TextBox();
                    tbox2.Height = 50;
                    tbox2.Width = 50;
                    if (String.IsNullOrEmpty(self))
                    {
                        tbox2.Background = Brushes.Black;
                        tbox2.Focusable = false;
                    }
                    wrapPanel1.Children.Add(tbox2);
                }// end of top bottom left right.

            }


        }
    } // End of AddPuzzle()

Code to display Across and Down :

    protected void Down()
    {
        IList<ModelSQL.puzzlecontent> lstDown = daoPuzzleContent.GetDown();

        foreach (ModelSQL.puzzlecontent listd in lstDown)
        {
            Label tbD = new Label();
            tbD.Content = listd.Hint;
            tbD.Width = Double.NaN;
            tbD.BorderBrush = Brushes.CadetBlue;
            tbD.BorderThickness = new Thickness(2);
            stackPanel2.Width = Double.NaN;
            stackPanel2.Children.Add(tbD);


        }
    }

    protected void Across()
    {
        IList<ModelSQL.puzzlecontent> lstAcross = daoPuzzleContent.GetAcross();

        foreach (ModelSQL.puzzlecontent lista in lstAcross)
        {
            Label tbA = new Label();
            tbA.Content = lista.Hint;
            tbA.Width = Double.NaN;
            tbA.BorderBrush = Brushes.CadetBlue;
            tbA.BorderThickness = new Thickness(2);
            stackPanel1.Width = Double.NaN;
            stackPanel1.Children.Add(tbA);
            words.Add(lista.Answer);

        }
    }
like image 430
user2376998 Avatar asked Aug 15 '13 06:08

user2376998


1 Answers

You may need to re-define your data model here because I think you have failed at the first hurdle - systems analysis. It catches us all out when we just want to write code and always means a big refactor.

Think about your domain here. Crossword puzzles. If we are a reading a newspaper puzzle and you dont know the answer to a clue, what do you say when you you ask a friend.

6 letters, clue is 'blah blah'

...followed by any letters that you already know.

Now we know that the puzzle needs to know how many letters in each answer and that each answer needs a clue. We also know that letters are hidden until you fill them out but we need to know the right answer at some point.

How does the puzzle present itself in the back of the paper? Clues are not written as 1,2,3 etc. They are 4 down, 1 across etc. Now we know that you need some position data stored.

You can achieve this is 2 ways.

1. Have each clue as its own entry complete with text

Clue '1' Direction 'Across' Position '1,1' Answer 'Hello' Description 'Greeting'

Work out the grid size from the entries and position letters accordingly. Pros: Easy to work with. All the information in one place Cons: Possible data corruption. This method can define 2 different letters in the same position.

2. Seperate Entries but answer text in grid

This is very similar to how you have it now but your seperate the text into a CSV grid as you demonstrate in the first screenshot. You then have entries for the clues as in method 1. but omit the 'Answer' field.

Your code will have to :

  1. work out the grid size
  2. populate a grid
  3. populate the list of clues
  4. convert the users entries to a CSV text file so that you can validate the input against the answers and
  5. tell the user if

As for linking the clues to the entry text boxes. Set the Tooltip property of each textbox with descriptions of the clues that include the letter. they got it right.

Finally (and this is probably the bit you want), add the correct number to the entry text box, you have to take advantage on WPF's layout pipeline. Dont just put a textbox in your grid, put another grid in! I'll show you how it should look in XAML, but you may want to generate it in code.

<Grid>
  <TextBlock x:Name="TextBlock_NumberLabel"/>
  <TextBox x:Name="TextBox_LetterEntry"/>
<Grid>

Use that instead of a plain textbox in any square where you want a number.

like image 71
Gusdor Avatar answered Nov 08 '22 00:11

Gusdor