My scrabble solution for Week 2 of CS50, struggles with symbols. Cant figure out why

853 Views Asked by At

So I wrote this code for the scrabble problem for the lab of week 2 of CS50. The jist of it is that, we need to write code to calculate the score of two words given by two players, and then declare the winner based on the points assigned to each letter in both the words. The points assigned to each letter is given in the array "POINTS".

Here's a link to the problem if u need more info: https://cs50.harvard.edu/x/2023/labs/2/

#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>

// Points assigned to each letter of the alphabet
int POINTS[] = { 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10 };

string convert_upper(string word);
int compute_score(string upper_word);
void print_winner(int score1, int score2);

int main(void)
{
    // Get input words from both players
    string word1 = get_string("Player 1: ");
    string word2 = get_string("Player 2: ");

    // Convert to uppercase
    string upper_word1 = convert_upper(word1);
    string upper_word2 = convert_upper(word2);

    // Calculate scores
    int score1 = compute_score(upper_word1);
    int score2 = compute_score(upper_word2);

    // TODO: Print the winner
    print_winner(score1, score2);
}

string convert_upper(string word)
{
    // Convert to uppercase
    int length = strlen(word);
    for (int i = 0; i < length; i++)
    {
        word[i] = toupper(word[i]);
    }
    printf("%s\n", word);
    return word;
}

int compute_score(string upper_word)
{
    // Add score for each letter
    int score = 0;
    for (int i = 0; i < strlen(upper_word); i++)
    {
        score = score + POINTS[upper_word[i]-65];
    }
    return score;
}

void print_winner(int score1, int score2)
{
    // Print result based on the scores
    if (score1 > score2)
    {
        printf("Player 1 wins \n");
    }
    else if (score2 > score1)
    {
        printf("Player 2 wins \n");
    }
    else
    {
        printf("Tie! \n");
    }
}

The code works fine if I just use normal words. But as soon as I use a word with a symbol at the end like question?, the score gets too high and it doesn't work as intended. It seems like there is some problem with how my code handles the symbols. I know that isupper() is a better way to implement this without any errors, but I want to know what went wrong here exactly.

2

There are 2 best solutions below

4
chqrlie On

In compute_score you access the score for a given tile as POINTS[upper_word[i] - 65];. If the character at offset i is not an uppercase letter, the index computed as upper_word[i] - 65 is outside the range of array POINTS so accessing this entry has undefined behavior. Note that you assume that uppercase letters are contiguous in the character set and that A is encoded as 65, which is specific to ASCII. The program would fail on a target that uses EBCDIC (but you are unlikely to find one).

You should reject a word that is not exclusively composed of letters and possibly some wildcard such as * or for the place holder.

Here is a modified version:

#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

// Points assigned to each letter of the alphabet
int POINTS[] = {
    1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3,
    1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10
};

string convert_upper(string word);
int compute_score(string upper_word);
void print_winner(int score1, int score2);

int main(void)
{
    // Get input words from both players
    string word1 = get_string("Player 1: ");
    string word2 = get_string("Player 2: ");

    // Convert to uppercase
    string upper_word1 = convert_upper(word1);
    string upper_word2 = convert_upper(word2);

    // Calculate scores
    int score1 = compute_score(upper_word1);
    int score2 = compute_score(upper_word2);

    // TODO: Print the winner
    print_winner(score1, score2);
}

string convert_upper(string word)
{
    // Convert to uppercase
    int length = strlen(word);
    for (int i = 0; i < length; i++) {
        unsigned char cc = word[i];
        word[i] = toupper(cc);
    }
    printf("%s\n", word);
    return word;
}

int compute_score(string upper_word)
{
    // Add score for each letter
    int length = strlen(word);
    int score = 0;
    for (int i = 0; i < length; i++) {
        unsigned char cc = upper_word[i];
        if (!isupper(cc)) {
            if (cc != ' ' && cc != '*') {
                printf("invalid word: %s\n", upper_word);
                return 0;
            }
        } else {
            score = score + POINTS[cc - 'A'];
        }
    }
    return score;
}

void print_winner(int score1, int score2)
{
    // Print result based on the scores
    if (score1 > score2) {
        printf("Player 1 wins \n");
    } else
    if (score2 > score1) {
        printf("Player 2 wins \n");
    } else {
        printf("Tie! \n");
    }
}
3
Anant On
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>

// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};

int compute_score(string word);

int main(void)
{
    // Get input words from both players
    string word1 = get_string("Player 1: ");
    string word2 = get_string("Player 2: ");

    // Score both words
    int score1 = compute_score(word1);
    int score2 = compute_score(word2);

    // TODO: Print the winner
    if(score1>score2)
    printf("Player 1 wins!\n");
    else if (score2>score1)
    printf("Player 2 wins\n");
    else printf("Tie!\n");
}

int compute_score(string word)
{
    // TODO: Compute and return score for string
    int sum=0;
    // loop to iterate across string
    for(int i=0;i<strlen(word);i++)
    {
        //reject all the characters that come before letters in ascii chart
        //make them 0 so that they dont add up the score and return garbage value
        if(word[i]>=1 &&word[i]<=64)
        {
            word[i]=0;
        }
        //convert all to uppercase so we dont have to check twice
        word[i]=toupper(word[i]);
        int a=word[i]-'A';
        // counter
        sum=sum+POINTS[a];

    }
     return sum;

}

// Code by anant