0

I'm trying to write a simple WPF C# scrabble game. What I was able to do on my own: I created a 10x10 table and randomly put letters in it

Here is the code of XAML and Randomizer

 <ItemsControl ItemsSource="{Binding Chars}">
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <ItemsControl ItemsSource="{Binding}">
                 <ItemsControl.ItemsPanel>
                     <ItemsPanelTemplate>
                         <StackPanel Orientation="Horizontal" />
                     </ItemsPanelTemplate>
                 </ItemsControl.ItemsPanel>
                 <ItemsControl.ItemTemplate>
                     <DataTemplate>
                         <Button
                             Width="30"
                             Height="30"
                             Margin="3"
                             Content="{Binding}" />
                     </DataTemplate>
                 </ItemsControl.ItemTemplate>
             </ItemsControl>
         </DataTemplate>
     </ItemsControl.ItemTemplate>
 </ItemsControl>

And randomizer

public partial class MainWindow : Window
 {
     public ObservableCollection<ObservableCollection<char>> Chars { get; set; }

     public MainWindow()
     {
         InitializeComponent();
         DataContext = this;

         Random rchar = new Random();
         Chars = new();
         for (int x = 0; x < 10; x++)
         {
             Chars.Add(new());
             for (int y = 0;  y < 10; y ++)
             {
                 Chars[x].Add((char)rchar.Next(65, 91));
             }
         }

     }
 }

The next step, which I could not do, is to create a collection of words and place them in a table. I understand that we need to create a Word List; List<string[]>words = new List<string[]>();and then split each word into letters but then how do I arrange the letters vertically or horizontally in the table?

I am a beginner and if there is a solution it should not be very complicated

string word = "House";
        char[,] arr = new char[10, 10];
    for (int x = 0; x < arr.GetLength(0); x++)
    {
        for (int y = 0; y < arr.GetLength(1); y++)
        {
            if(y <  word.Length)
            {
                arr[x,y] = word[y];
            } else
            {
                arr[x, y] = (char)(rchar.Next(65, 91));
            }
    
            Console.Write(arr[x, y] + " ");
        }
        Console.WriteLine();
    }

But I get a picture like this

How to fix that? The word needs to be displayed once and anywhere

enter image description here

Dharman
  • 30,962
  • 25
  • 85
  • 135
Dima
  • 1
  • 2
  • 1
    Don't vandalise posts, not even your own. By posting here, you've granted the company irrevocable rights under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). – Jiminy Cricket. Oct 26 '22 at 07:03
  • I wanted to add an answer to this question a few weeks ago, before realizing that the question post had been closed. If it is opened again, I would like to add my answer. In the meantime, I will simply share the [**fiddle**](https://dotnetfiddle.net/I47vPE) that I created for the answer's purpose; it uses a nested list rather than a two-dimensional array, but it can be used to play around with, and hopefully it may provide some understanding. – Astrid E. Nov 16 '22 at 09:52

2 Answers2

1

Steps:

  1. decide the direction - horizontal vs vertical
  2. decide where the word should start - as coordinates 0..9 (don't forget to perform checks if the word will fit)
  3. replace the generated characters with word characters

sample function code:

public enum WordDirection
{
    Vertical,
    Horizontal
}

public void WriteWord(ObservableCollection<ObservableCollection<char>> charTable, 
    IEnumerable<char> word, int startX, int startY, WordDirection direction)
{
    int x = startX;
    int y = startY;
    foreach(char ch in word)
    {
        charTable[x][y] = ch;
        if(direction == WordDirection.Horizontal)
        {
            x++;
        }
        else //these two maybe need to be swapped as I'm not sure which is which (as I'm writing this without testing)
        {
            y++;
        }
    }
}

Example call can look like this:

WriteWord(Chars, "test".AsEnumerable(), 0, 0, WordDirection.Vertical);

Notes:

  • if the word won't fit, this code will most likely throw an exception
  • words written later will overwrite previous ones, unless you implement additional checks
Marty
  • 412
  • 3
  • 7
0

Like Marty's answer, but this will also check if there's space for your words. Sorry if it's too complicated this is my first StackOverflow answer.

It will: 1. Create an 2d array of chars filled with char '33'. 2. Loop through the words, check if there's space and if there's space commit the word. 3. Fill the rest of the chars up with random characters.

public ObservableCollection<ObservableCollection<char>> Chars { get; set; }

public List<string> Words { get; set; }

public enum WordDirection
{
    Vertical,
    Horizontal
}

Random rnd = new Random();

public void Main(){
    FillWithEmptyChars();
    WriteWords(Words);
    FillRestOfSpace();
}

public void FillWithEmptyChars(){
     Chars = new();
     for (int x = 0; x < 10; x++)
     {
         Chars.Add(new());
         for (int y = 0;  y < 10; y ++)
         {
             Chars[x].Add((char)33); //Couldnt find a better char, chosen for ease
         }
     }
}

public void WriteWords(List<string> words){
    
    foreach(string word in words){
        var startx = rnd.Next(0, 9);
        var starty =  rnd.Next(0, 9);
        var worddir = (WordDirection) rnd.Next(0, 1);
        if WriteWord(word, startx, starty, worddir, false)
            WriteWord(word, startx, starty, worddir, true);
    }
}

public void WriteWord(IEnumerable<char> word, 
                        int startX, 
                        int startY,
                        WordDirection direction,
                        bool commit)
{
    //Start position
    int x = startX;
    int y = startY;
    
    //Clamp position
        if(direction == WordDirection.Horizontal)
            x = Math.Clamp(startX, 0, 10 - word.Count);
        if(direction == WordDirection.Vertical)
            y = Math.Clamp(startY, 0, 10 - word.Count);
    
    //Add a letter
    foreach(char ch in word)
    {
        //Only commit after checking if there's space left, to not overwrite other letters
        if (commit)
            charTable[x][y] = ch;
        
        //Check if there is space or that the letters match up
        if !(charTable[x][y] == ch || charTable[x][y] == (char)33)
            return false;
            
        if(direction == WordDirection.Horizontal)
            x++;
        if(direction == WordDirection.Vertical)
            y++;
    }
    
    return true;
}

public void FillRestOfSpace(){
     for (int x = 0; x < 10; x++)
     {
         for (int y = 0;  y < 10; y ++)
         {
             if (Chars[x][y] == (char)33)
                Chars[x][y] = (char)rnd.Next(65, 91) //Couldnt find a better char, chosen for ease
         }
     }
}
Sep Vrij
  • 36
  • 2
  • Thanks, but where should I write the word that will be inserted in the field? – Dima Oct 19 '22 at 06:35
  • Honestly, I did not understand a lot of what was written in the code. Can you give me an example of how to insert one word into a table? – Dima Oct 19 '22 at 09:13
  • I don't think there's a good reason for first filling with empty char and then rewriting the empty ones with random. You can just fill all with random at first and when writing words, it will just be rewritten. – Marty Oct 19 '22 at 15:48
  • @Dima I expanded my answer with an example – Marty Oct 19 '22 at 15:51