Making a Scrabble Game, Need Assistance.

Well, I'm trying to make Scrabble in C++. I thought it'd be a nice challenge, but it's more challenging then I expected.

-When a player enters a word, how can I make the program check to see if it's in my dictionary( A text file).
-How can I make it so that when players go to input words onto the board, that they can only build off of other words?
-How can I calculate score off the letters used in a word? (each letter gives a score, how do I make it read the letters then add the score?)

If I could just get some help with these 3 problems, I think i'd be able to finish it and do some testing. I can also share my code so far(it's mainly just the board at the moment) if that would help at all.
For the first one, you could load in the text file to a vector of strings, and use the std::find() algorithm to find the word. If the word isn't found, you know what to do.

For the second two, that would depend on how you're doing all this...is this a console app? (I hope not)
First: I'd recommend reading your file into a vector or something similar, then use a map of first letter combos(two letters probably) to use later. Then when someone uses a word go to that number in your dictionary vector, and iterate through that letter section to check for valid moves.
Or you could just put the whole thing in an stl::list... If your dictionary is too large to store on your ram, then you can use the first map method to store the iterator of that particular letter, then you can read in as needed.

Second: Mark each tile as it's put down, and check to make sure it's a valid move. When it's a valid move, check the word using some sort of store of your words (see above)
When it's a valid move, apply the individual letter scores (from a simple array of structs, or a map, or whatever the heck you want), then check for special tiles, and apply the specials.

For the existing tiles, it's a simple matter, you can just prepopulate your array for checking with the existing tiles, thereby also giving yourself a simple method of error checking if the user tries to place a tile on a predestined board tile.

Third: To calc the score. Store every letter and value in some sort of container. (be it struct, vector, map, array, or heck even individual variables if your crazy) then perhaps have a score variable and add all of the current letters (before adding your special modifiers eg: 3x letter, 3x word, etc), then add your mods. Then permanently increase the score of that person, if it's a valid move of course.

That's a rough outline of a rough course I'd roughly take on rough days... roughly.

Last edited on
oh wow, thanks for the quick responses! I'll start on working on these, thanks a lot! Hopefully i don't do something wrong.
Looking up words is pretty easy when you are using the correct data structurs.

First get a copy of the scrabble dictionary, sowpods.txt, here:

http://code.google.com/p/scrabblehelper/source/browse/trunk/ScrabbleHelper/src/dictionaries/sowpods.txt

Then load all the words into a set, something like this:

set<string> words;
ifstream file("sowpods.txt");
string word;
while ( file >> word )
words.insert( word );

When you want to see if a word is in the dictionary:

if ( words.find( "acreage" ) != words.end() )
cout << "The word 'acreage' is in the dictionary!";
Ok, can I get some quick help? I'm having a really hard time with assigning random letters to each player's tile set. I have an array for each player (2 players), and I need to assign a random letter to each value of that array, while taking away from my letter counters(cause you eventually run out of letters). I'm having a bad day, and getting really frustrated. I just can't get it to work, and i think i was doing it a really difficult way that I couldn't even get to work. If someone could just show me some example code (would be the best), or just explain in detail of what I should do I would greatly appreciate it.
1) Fill a container with the appropriate mix of letters for a scrabble game. (A vector is just fine.) You can find the letter distributions here:

http://en.wikipedia.org/wiki/Scrabble_letter_distributions

2) Initialize your random number generator by calling srand() with a seed of time().

3) For 100 times or so, swap two tiles by generating two random numbers between 1 and 100.

4) Your vector is now more or less randomized. Not perfectly, but good enough for what you need. Draw 7 letters for each player with pop_back().

- Mark
Thanks for the response Mark, but i think that's above me because I have no idea how to execute that.

I know how to do randomization with
1
2
3
srand(static_cast<unsigned int>(time(0)));
    randomnumber = rand();
    die=(randomnumber % 26) + 1;


But im not sure how to do 2 or 3, and how would I use pop_back() to assign a letter to an array?

I'm sorry if this all seems really basic, just kind of struggling...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
for(int i = 0; i < 12;i++)
    {
        letter.push_back("E");
    }
    for(int i = 0; i < 9;i++)
    {
        letter.push_back("A");
        letter.push_back("I");
    }
    for(int i = 0; i < 8;i++)
    {
        letter.push_back("O");
    }
    for(int i = 0; i < 6;i++)
    {
        letter.push_back("N");
        letter.push_back("R");
        letter.push_back("T");
    }
    for(int i = 0; i < 4;i++)
    {
        letter.push_back("L");
        letter.push_back("S");
        letter.push_back("U");
        letter.push_back("D");
    }
    for(int i = 0; i < 3;i++)
    {
        letter.push_back("G");
    }
    for(int i = 0; i < 2;i++)
    {
        letter.push_back("B");
        letter.push_back("C");
        letter.push_back("M");
        letter.push_back("P");
        letter.push_back("F");
        letter.push_back("H");
        letter.push_back("V");
        letter.push_back("W");
        letter.push_back("Y");
    }

        letter.push_back("K");
        letter.push_back("J");
        letter.push_back("X");
        letter.push_back("Q");
        letter.push_back("Z");
        random_shuffle( letter.begin(), letter.end() );
random_shuffle( letter.begin(), letter.end() );
random_shuffle( letter.begin(), letter.end() );
random_shuffle( letter.begin(), letter.end() );




So I'm now trying to use this, after seeing something similar. But now i'm now sure how to use it, like grabbing a letter and assigning it into my array.

p2tile[0]=letter.pop_back(); Nope, I feel really clueless today.

closed account (D80DSL3A)
What data type is stored in the vector? A character?
vector<char> letter; ?
If so, then use single quotes when pushing back. eg. letter.push_back('A');

Is p2tile an array of characters? If so your assignment ought to work.
1
2
3
vector<string> letter;
string p1tile[8];
string p2tile[8];



I just want to know how to assign the letters to an array, lol. Oh, and string will work right?
closed account (D80DSL3A)
The pop_back() returns void, not the value stored in the element.
This code works:
1
2
p2tile[0] = letter.back();// get the value at the back
letter.pop_back();// pop the back value 


I tested this with the following program. It is working:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <string>
#include <vector>
#include<algorithm>
#include <iostream>
using namespace std;

int main()
{
	vector<string> letter;

    for(int i = 0; i < 12;i++)
    {
        letter.push_back("E");
    }
    for(int i = 0; i < 9;i++)
    {
        letter.push_back("A");
        letter.push_back("I");
    }
    for(int i = 0; i < 8;i++)
    {
        letter.push_back("O");
    }
    for(int i = 0; i < 6;i++)
    {
        letter.push_back("N");
        letter.push_back("R");
        letter.push_back("T");
    }
    for(int i = 0; i < 4;i++)
    {
        letter.push_back("L");
        letter.push_back("S");
        letter.push_back("U");
        letter.push_back("D");
    }
    for(int i = 0; i < 3;i++)
    {
        letter.push_back("G");
    }
    for(int i = 0; i < 2;i++)
    {
        letter.push_back("B");
        letter.push_back("C");
        letter.push_back("M");
        letter.push_back("P");
        letter.push_back("F");
        letter.push_back("H");
        letter.push_back("V");
        letter.push_back("W");
        letter.push_back("Y");
    }

	letter.push_back("K");
	letter.push_back("J");
	letter.push_back("X");
	letter.push_back("Q");
	letter.push_back("Z");
	random_shuffle( letter.begin(), letter.end() );// is once not enough?

	size_t i = 0;
	// display entire tile pool
	for( i=0; i<letter.size(); ++i )
	{
		cout << letter[i] << " ";
		if( (i+1)%20 == 0 )cout << endl;// 20 to a line
	}
	string p1tile[8];// the 2 players tile hands
	string p2tile[8];
	// fill hands
	for( i=0; i<8; ++i )	
		if( !letter.empty() )
		{
			p1tile[i] = letter.back();
			letter.pop_back();
		}
	for( i=0; i<8; ++i )
		if( !letter.empty() )
		{
			p2tile[i] = letter.back();
			letter.pop_back();
		}	
	// show hands
	cout << "\n\n hand1 = ";
	for( i=0; i<8; ++i )
		cout << p1tile[i] << " ";
	cout << "\n hand2 = ";
	for( i=0; i<8; ++i )
		cout << p2tile[i] << " ";

  	cout << endl;
	return 0;
}


I would choose to use individual characters instead of strings but it should work either way.
Last edited on
oh wow, thanks! That's exactly what I needed!
Dang it, It crashes when I try to run this subroutine:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
string tileset()
{
       
    for(int i = 0; i < 12;i++)
    {
        letter.push_back('E');
    }
    for(int i = 0; i < 9;i++)
    {
        letter.push_back('A');
        letter.push_back('I');
    }
    for(int i = 0; i < 8;i++)
    {
        letter.push_back('O');
    }
    for(int i = 0; i < 6;i++)
    {
        letter.push_back('N');
        letter.push_back('R');
        letter.push_back('T');
    }
    for(int i = 0; i < 4;i++)
    {
        letter.push_back('L');
        letter.push_back('S');
        letter.push_back('U');
        letter.push_back('D');
    }
    for(int i = 0; i < 3;i++)
    {
        letter.push_back('G');
    }
    for(int i = 0; i < 2;i++)
    {
        letter.push_back('B');
        letter.push_back('C');
        letter.push_back('M');
        letter.push_back('P');
        letter.push_back('F');
        letter.push_back('H');
        letter.push_back('V');
        letter.push_back('W');
        letter.push_back('Y');
    }

        letter.push_back('K');
        letter.push_back('J');
        letter.push_back('X');
        letter.push_back('Q');
        letter.push_back('Z');
        random_shuffle( letter.begin(), letter.end() );
  
}



*DOH* I forgot to change it to char.
Last edited on
closed account (D80DSL3A)
You're going with a vector of characters then? Interesting...
I've been pushing this exercise forward myself!
I also made the players tile hands into vector<char> instead of an array.

It looks like you are trying to initialize the letter pool in a function.
This is what I have for that now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void INITtilePool( vector<char>& pool )
{
	int i = 0;// for looping
	for( i = 0; i < 12;i++)    
        pool.push_back('E');    
    for( i = 0; i < 9;i++)
    {
        pool.push_back('A');
        pool.push_back('I');
    }
    for( i = 0; i < 8;i++)    
        pool.push_back('O');    
    for( i = 0; i < 6;i++)
    {
        pool.push_back('N');
        pool.push_back('R');
        pool.push_back('T');
    }
    for( i = 0; i < 4;i++)
    {
        pool.push_back('L');
        pool.push_back('S');
        pool.push_back('U');
        pool.push_back('D');
    }
    for( i = 0; i < 3;i++)    
        pool.push_back('G');
    
    for( i = 0; i < 2;i++)
    {
        pool.push_back('B');
        pool.push_back('C');
        pool.push_back('M');
        pool.push_back('P');
        pool.push_back('F');
        pool.push_back('H');
        pool.push_back('V');
        pool.push_back('W');
        pool.push_back('Y');
    }

	pool.push_back('K');
	pool.push_back('J');
	pool.push_back('X');
	pool.push_back('Q');
	pool.push_back('Z');
	random_shuffle( pool.begin(), pool.end() );
	return;
}

Then I can just do this in main(). I'm now working on having a player make a play.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const size_t handSize = 8;// Aren't there only 7 tiles in a hand?

int main()
{
	vector<char> letter;// tile pool
	vector<char> p1tile;// players hands
	vector<char> p2tile;

	INITgame(letter, p1tile, p2tile);// this calls INITtilePool() and fills and displays both hands.

        //player 1 plays 2 tiles - then refills hand from pool. New hand is displayed.
	cout << "\n p1 plays: " << playTile( p1tile, 0 ) << " and " << playTile( p1tile, 2 ) << endl;// 1st and 3rd tiles in hand
	cout << "These tiles are left: "; showHand(p1tile);
	fillHand(letter, p1tile);
	cout << "p1 new hand is:       "; showHand(p1tile);

	return 0;
}


The other functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void fillHand(vector<char>& pool, vector<char>& hand)
{
	while( hand.size() < handSize )
	{
		if( !pool.empty() )
		{
			hand.push_back( pool.back() );
			pool.pop_back();
		}
		else
			break;// cannot finish filling hand
	}
	return;
}

void showPool( vector<char>& pool )
{
	cout << "pool:\n";
	for(size_t i=0; i<pool.size(); ++i )
	{
		cout << pool[i] << " ";
		if( (i+1)%20 == 0 )cout << endl;// 20 to a line
	}
	cout << endl;
	return;
}

void showHand( vector<char>& hand )
{
	cout << "hand = ";
	for(size_t i=0; i<hand.size(); ++i )
		cout << hand[i] << " ";
	cout << endl;
	return;
}

char playTile( vector<char>& hand, unsigned int tileIndex )
{
	char letterPlayed = '\0';// in case hand is empty
	if( tileIndex < hand.size() )// index is OK
	{
		letterPlayed = hand[ tileIndex ];
		hand.erase( hand.begin() + tileIndex );
	}
	return letterPlayed;
}

void INITgame(vector<char>& pool, vector<char>& hand1, vector<char>& hand2 )
{
	INITtilePool(pool);// fill pool
	showPool(pool);	
	fillHand(pool, hand1);// fill hands and show them
	showHand(hand1);
	fillHand(pool, hand2);
	showHand(hand2);
	return;
}

Last edited on
Jeez dude, your really good at this. I would give you my board, but it doesn't fit xD

Right now im trying to do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string player1t()
{  
       
 cout << "Use your letters and spell a word:";
 cin >> input;

 vector<string> words;
 ifstream file("dictionary.txt");
 string word;
 while ( file >> word )
 words.insert( word );
if ( words.find( "acreage" ) != words.end() )
cout << "The word 'acreage' is in the dictionary!";
       
}


Ain't working for me right now, lol.
Last edited on
closed account (D80DSL3A)
Thank you. Are you placing the entire dictionary list of words into one vector?
Shouldn't be a problem in terms of memory used. Even 50,000 words with average length 8 characters (say) requires 50,000*8 Bytes = 400KB < 0.5MB which isn't much.

For your line 11 I think you want words.push_back( word );

I made a scrabble game for windows about 10 years ago (user vs. computer - it plays a little better than me). I knew little of the language then and did it all in terms of global arrays, simple structures and global functions so I may try to "modernize" it.
Of course I would not make it a console game, though a console program is useful for working out the mechanics.

I found it worked very well to organize the dictionary by word length.
Searches are always done by word length first.
I'd use separate vectors for 2 letter words, 3 letter words and so on.
An array of vector<string> might work well since there is a maximum word length of 15 letters (due to board dimensions). Perhaps vector<string>words[13]; where words[0] would be for 2 letter words and so on.
You don't want to put the dictionary into a vector.

Use the standard set container, or better yet use unordored_set. Checking for a word match using a lookup in unordered_set<string> will run in constant time. Walking through an entire vector will be much slower.

- Mark
closed account (D80DSL3A)
Thanks. I'll look into that.
I do want to use the best container for the job.

In my old game version I actually performed each search on the text file (never loading it into program memory). I used an array of file pointers for searching by length.
Even this method is fast enough that plays appear to be processed "instantly".
Hi guys. Can you help me with the scrabble game. I dont have idea where to start. Im not that familiar in c++ codes. Please i really need your help. the game is for our finals. thanks
Last edited on
Topic archived. No new replies allowed.