- Home /
Scrabble game. Need help with parsing words from tiles.
So I'm learning Unity still and I'm trying to put together a Scrabble clone for fun. How I have it set up is I have a 21x21 grid (more than regular Scrabbs) and 42 strings. One for each row and column. When the player places a tile on a space, depending on the name of the space (say, "H11" or "M9") it will then insert the tile's letter into the right spot in two of the 42 strings. When the player has all of the tiles placed, the game will parse the strings, split them by spaces, and insert each string that's greater than 1 letter into a List<>.
Then it checks to see that each string in the list is valid by checking it against a dictionary text file. If it is valid, each string gets put into a separate list of "played" words so that the player can't try to play them a second time.
This all works great, but I have no idea how to prevent the player from laying down tiles with reckless abandon, leaving spaces in between, not building off other words, that sort of thing. As it is now, a player can play multiple words (within the seven tile limit per turn) all over the board, so he or she can just steal all of the triple word scores, just as long as the words are valid.
I have no idea how to mitigate this issue. I imagine it's because my current solution just isn't gonna work in the end, so I'm hoping someone can provide some insight as to how to fix this issue or point me in the right direction for a complete code rewrite.
Anyone have any experience with this?
Answer by wibble82 · Jan 31, 2014 at 01:02 PM
Hi there
So it sounds like you have a few issues in one to solve. The first problem is how to store your tiles. Your current solution suffers a little from what we often call 'redundant data', in the sense that you're storing the same information in multiple ways. When a user places a new tile, you store it in 2 seperate places, when its really just one informat. In addition, your data is more like a grid rather than a list of strings, so you want to be trying to store your data in a way that reflects that. This is a slightly 'opinion' based problem, but you will find that starting from a good foundation always makes your life easier!
class GridCell
{
public int score_multiplier=1; //this might be 1 for a normal cell, 2 for a double word scale, 3 for a triple
public char current_character = ' '; //current character in the cell. a space means empty
}
//this stores a grid of 21 by 21 characters
GridCell[] mygrid = new GridCell[21 * 21];
//get the cell at a given location
GridCell GetGridCellAt(int x, int y)
{
//note this check to ensure a valid location is passed in. we return null if its invalid
if (x >= 0 && x < 21 && y >= 0 && y < 21)
return mygrid[x + y * 21];
else
return null;
}
//this sets up a new cell at each location
void InitGrid()
{
//first instantiate a new grid cell at each square
for (int i = 0; i < mygrid.Length; i++)
mygrid[i] = new GridCell();
//...here you could setup all the special multipliers, i.e....
GetGridCellAt(20, 20).score_multiplier = '3';
}
Here we have the core bits of work - a way of storing each cell (the character it contains AND its multiplier), a function to clear it out and a function to get the cell at a given location. As a handy extra feature, the function to get the cell verifies you asked for a valid location before returning anything, and returns the special value 'null' (means theres nothing here) if you do something invalid.
Now you can begin writing some utility functions to build up the functionality of your grid. To get you started, heres one that iterates over all the neighbours of a cell and tells you if any contain a letter (which might be useful for the specific problem you had)
//check if any neighbour cells contain a letter
bool DoAnyNeighbourCellsContainALetter(int x, int y)
{
//iterate over each of the neighbours in x and y
for (int xoffset = -1; xoffset <= 1; xoffset++)
{
for (int yoffset = -1; yoffset <= 1; yoffset++)
{
//ignore the middle (thats the tile you passed in!)
if (xoffset == 0 && yoffset == 0)
continue;
//get the neighbour
GridCell neighbour = GetGridCellAt(x + xoffset, y + yoffset);
if (neighbour != null)
{
//if it contains a letter, return true
if (neighbour.current_character != ' ')
return true;
}
}
}
//if we got all the way through the neighbours without finding anything, return false
return false;
}
To replicate a bit of your existing functionality (should you need it), this one extracts all the letters in a cell and returns them as a string:
//get a column as a string
string GetColomnAsAString(int column_number)
{
string result = "";
for (int y = 0; y < 21; y++)
{
result = result + GetGridCellAt(column_number, y);
}
return result;
}
You should ultimately be able to do all of your logic using this grid cell structure.
Hope that gets you started - good luck!
Jeepers wibble, what a writeup! This is the kind of stuff I need to learn, so thank you for your insight!
Question before I go further though, When you were writing the GridCell class, did you mean to create a 2D array [21,21] or an array of literally 441 1D entries (21 * 21 = 441)?
Sorry - didn't see that comment. I intentionally created the 1D array, and inside GetGridCellAt I do the calculation to calculate the position in the 1D array of the x/y coordinate you're after. Doing it with a 2D array is a perfectly valid (and some would say better) way of doing it.
I generally prefer the 1D approach as it lets you just easily iterate over every grid cell with a simple loop (such as in my init function). But its a matter of taste, not correctness :)
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
how to hit enter through script 1 Answer
UnityEngine.Input.GetMouseButton(1)) issue 1 Answer
GameObject.name to string 2 Answers
Convert String To Class 1 Answer