Home > database >  answers Can I make my code shorter using loops?
answers Can I make my code shorter using loops?

Time:09-16

is there a way to make this code shorter?

// Points assigned to each letter of the alphabet 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 (score1 < score2)
                {
                    printf("Player 2 wins!\n");
    
                }
                else
                {
                    printf("Tie!\n");
                }
            }

the calculator function I Haved to definition character is uppercase or lower in different loops and i think i can make that in one loop but i don't know how :)

 int compute_score(string word)
    {
            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 len = strlen(word);
 

            int i = 0;
            int total = 0;
            for (i = 0; i <= len; i  )
            {
                if (word[i] >= 65 && word[i] <= 90)
                {
                    int ascii = word[i];
                    int toasc = ascii - 65;
                    total  = (points[toasc]);
                }
            }

            int ii = 0;
            int totall = 0;

            for (ii = 0; ii <= len; ii  )
            {
                if (word[ii] >= 97 && word[ii] <= 122)
                {
                    int asciii = word[ii];
                    int toascc = asciii - 97;
                    totall  = (points[toascc]);
                }
            }
            int totalf = total   totall;
            return totalf;
        }

CodePudding user response:

you can try something like this:

int compute_score(string word) {
    int total = 0;
    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 len = strlen(word);
    for (i = 0; i < len; i  )
        if (word[i] >= 'A' && word[i] <= 'Z')
            total  = points[word[i] - 'A'];
        else if (word[i] >= 'a' && word[i] <= 'z')
            total  = points[word[i] - 'a'];
    return total;
}

CodePudding user response:

Normalizing the current letter to upper case which allows a fixed 'A' to be used to determine the offset into the points array. Consider changing the type of point from int to static const char [] for correctness.

#include "cs50.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>

#define PLAYERS 2

int compute_score(string word) {
    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 total = 0;
    for (; *word; word  )
        total  = isalpha(*word) ? points[toupper(*word) - 'A'] : 0;
    return total;
}

int main(void) {
    int scores[PLAYERS];
    for(size_t i = 0; i < PLAYERS; i  ) {
        scores[i] = compute_score(get_string("Player %d: ", i   1));
    }

    // TBD: generalize print of winners
    static_assert(PLAYERS == 2);
    if (scores[0] > scores[1]) {
        printf("Player 1 wins!\n");
    } else if (scores[0] < scores[1]) {
        printf("Player 2 wins!\n");
    } else {
        printf("Tie!\n");
    }
}

If you want to generalize the print of winners then it's more direct to just remember who the winners are as you go along. For example:

#include <string.h>

// ...

int main(void) {
    int max_score = -1;
    char winners[PLAYERS];
    for(size_t i = 0; i < PLAYERS; i  ) {
        int score = compute_score(get_string("Player %d: ", i   1));
        if(score > max_score)
            memset(winners, 0, sizeof(winners));
        if(score >= max_score)
            winners[i] = 1;
    }

    printf("Winner(s)");
    for(size_t i = 0; i < PLAYERS; i  ) {
        if(winners[i]) printf(" %d", i   1);
    }
    printf("\n");
}

CodePudding user response:

You demonstrate that you know strings are arrays of characters (with a null terminator on the end).

The following uses a "purpose-built" array that stores the points of both upper and lowercase ASCII alphabet characters.

#include <stdio.h>

int compute_score( string word ) {
    char tbl[] = { // small values fit into one byte
         0,  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, 0, 0, 0, 0, 0,
         0,  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, 0, 0, 0, 0, 0,
    };
    int points = 0;

    for( int i = 0; word[ i ]; i   ) { // each letter of the word

        int c = word[i] - '@'; // transpose down to range 0-63

        if( 0 < c && c < 4*16 ) // if still in range...
            points  = tbl[ c ]; // then retrieve point value of this letter
    }

    return points;
}

int main() { // A simple test program with a few words.

    string str;

    str = "Hello"; printf( "'%s' - pts\n", str, compute_score( str ) );
    str = "world"; printf( "'%s' - pts\n", str, compute_score( str ) );
    str = "quiz "; printf( "'%s' - pts\n", str, compute_score( str ) );

    return 0;
}

Output

'Hello'  8 pts
'world'  9 pts
'quiz ' 22 pts

EDIT: To use an even smaller "look-up table", invoke a little "modulo arithmetic"...

int compute_score( string word ) {
    // point values are arrayed correspondint to ASCII character positions
    uint8_t tbl[] = {
         0,  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, 0, 0, 0, 0, 0,
    };
    int points = 0;

    for( int i = 0; word[ i ]; i   )
        if( word[ i ] >= 'A' )
            points  = tbl[ word[ i ] % 32 ];

    return points;
}

EDIT2: Since we only want the look-up value for the upper two (alphabetic) ranges of the 7-bit ASCII table, AND C guarantees that the truth value of a condition will be either 0 (false) or 1 (true), the code could be made more contemporary using a "branchless programming" technique.

    for( int i = 0; word[ i ]; i   )
            points  = (word[i] >= 'A') * tbl[ word[ i ] % 32 ];

For other ASCII characters like digits or SP, the condition is false so no points are awarded. For characters in the right range, the points value is multiplied by 1 (the multiplication identity value).

Eventually, one's entire program can be reduced to a few lines... :-)

EDIT3: Now, turning attention to main() and its role in running the competition. Below combines (and renames) the function and its parameters.

The primary difference in this code is to recognise that each 'round' starts with zero. Subtracting the two players' scores will give a positive number, zero, or a negative number. Eliminating intermediary variables, each player gets a turn, their score computed, and the difference calculated all in one statement. Then an appropriate message displayed.

Because this is fun, a do/while() loop offers the opportunity to play again.

#include <stdio.h>
#include "cs50.h"

int score( string word ) {
    char pts = 0, tbl[] = {
         0,  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, 0, 0, 0, 0, 0,
    };

    for( int i = 0; word[ i ]; i   )
        pts  = (word[i] > 'A') * tbl[ word[ i ] % 32 ];

    word[ i-1 ] = '\0'; // trim '\n' from end before printing

    printf( "'%s' - %d points\n", word, pts );

    return pts;
}

int main() {
    do {
        int diff
        = score( get_string( "Player 1: " ) )
        - score( get_string( "Player 2: " ) );

        if( diff > 0 )
            puts( "\nPlayer 1 wins!" );
        else if( diff < 0 )
            puts( "\nPlayer 2 wins!" );
        else
            puts( "\nTie!");

    } while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );

    return 0;
}

Output

Player 1: house
'house' - 8 points
Player 2: car
'car' - 5 points

Player 1 wins!

Play again? (0-yes otherwise ending)0
Player 1:

Alternative main() using trenary "conditional operator":

int main() {
    do {
        int diff
        = score( get_string( "Player 1: " ) )
        - score( get_string( "Player 2: " ) );
        puts( diff > 0 ? "\nPlayer 1 wins!" : diff < 0 ? "\nPlayer 2 wins!" : "\nTie!" );
    } while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );

    return 0;
}
  • Related