I am writing a program to calculate the word score in a scrabble game and the code is as follows:
#include <stdio.h>
int main() {
// 1. Input at word
unsigned char word[15];
printf("Enter a word: \n");
scanf("%s", word);
printf("The word you entered is: %s\n", word);
// 2. Convert each character in the word to it's letter value
enum letterValue {a = 1, A = 1, e = 1, E = 1, i = 1, I = 1, o = 1, O = 1, u = 1, U = 1, l = 1, L = 1, n = 1, N = 1, r = 1, R = 1, s = 1, S = 1, t = 1, T = 1, d = 2, D = 2, g = 2, G = 2, b = 3, B = 3, c = 3, C = 3, m = 3, M = 3, p = 3, P = 3, f = 4, F = 4, h = 4, H = 4, v = 4, V = 4, w = 4, W = 4, y = 4, Y = 4, k = 5, K = 5, j = 8, J = 8, x = 8, X = 8, q = 10, Q = 10, z = 10, Z = 10};
unsigned short points[15];
for(int i = 0; i < 15; i ) {
points[i] = 0;
}
for(int j = 0; word[j] != '\0'; j ) {
points[j] = word[j]; // HERE IS MY PROBLEM!
}
//sum up the points
int sum = 0;
for(int k = 0; k < 15; k ) {
sum = points[k];
printf("Rolling sum is %d\n", sum);
}
//3. Output the word score
printf("Your word score is %d\n", sum);
}
In the line with comment "HERE IS MY PROBLEM", I read a character from the array word[] and try to assign its letterValue into the array points[]. What actually happens is that the ascii value of the character in word[] is assigned to points[], which makes sense. But, somewhere in the environment there exists a mapping between the ascii value of the characters in the enum and the bit values of the integers to which they have been assigned. Please confirm if this is true. If so, how do I tell the compiler that after reading said character from word[], go to the above mentioned mapping, find the matching bits and return the integer value associated with it?
I did consider using an array to store and lookup letter values, but my gut tells me that this would be cumbersome and the code would be harder to decipher, am I right about this or is there another way?
CodePudding user response:
But, somewhere in the environment there exists a mapping between the ascii value of the characters in the enum and the bit values of the integers to which they have been assigned. Please confirm if this is true.
No, this is not true. The enumeration constants (the named members of the enumeration) essentially exist only during compilation. The compiler knows their values, but it does not build their names, let alone any association between their names and their values, into the object file, except for debugging information (which is not ordinarily accessible to the program).
To create a map from character codes to Scrabble values, you can define an array:
char value[UCHAR_MAX 1] =
{
['A'] = 1, ['a'] = 1,
['B'] = 3, ['b'] = 3,
['C'] = 3, ['c'] = 3,
…
};
After which you may look up the value by converting the character code to an unsigned type and using it as an index into the array:
points[j] = value[(unsigned) word[j]];
UCHAR_MAX
is defined in <limits.h>
. [index] = value
is a syntax for initializing array elements, so ['A'] = 1
initializes the array element whose index is the code for the letter A
.
(I see word
is already defined as an array of unsigned char
, but I include (unsigned)
above to emphasize for other readers that the array index must not be allowed to be negative, as char
may be.)
CodePudding user response:
Not an enum, an array is your friend here:
unsigned char /* int? */ characterValues[256] = { ['A'] = 1, ['a'] = 1, /*...*/ };
Then you can easily sum up the value of a word via:
unsigned int wordValue = 0;
for(char* w = word; *w; w)
{
wordValue = characterValues[*w];
}
Note, too, that any value in the array not explicitly specified in the initialiser above is set to 0 anyway, thus unspecified characters behave neutral (whitespace, punctuation marks, ...).
An enum, on the other hand, cannot help you out, enums just define constants, you could have equally written
unsigned int const A = 1;
Such constants are helpers for the one writing the code, but in compiled code only their value remains visible. So all you could do with an enum would be:
if(character == 'A') { value = A; }
which would be exactly the same as directly writing
if(character == 'A') { value = 1; }
(or alternatively using a switch statement, but that wouldn't change anything about).
CodePudding user response:
Aside:
The longest word in standard Scrabble is 15 tiles. To save that word as a string requires an array of 15 1.
Do not use scanf("%s". ...
without a width.
Improved code:
// unsigned char word[15];
unsigned char word[15 1];
printf("Enter a word:\n");
// scanf("%s", word);
scanf("s", word);
CodePudding user response:
Assuming ASCII encoding, all the letters are encoded consecutively, so 'a' < 'b'
and so on for all letters of the (English) alphabet.
So you can use an array of 26 elements containing the values, and use the letter as an index into the array:
unsigned letterValues[] = { 1, 0, ... /* Etc. for all letters */ };
// ...
if (isalpha(word[j])
points[i] = letterValues[tolower(word[j]) - 'a'];
Note the use of isalpha
to make sure that the letter really is a letter. And the use of tolower
to not have to worry about upper- or lower-case.