6
\$\begingroup\$

I am trying to relearn the C language and thought making small projects would be a good way to do it. The code I wrote works perfectly as intended.

I am just here to see if there are any better practices to be implemented or any code optimization tips would be highly appreciated.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int random(int N){
    srand(time(NULL));
    int value = rand() % N;
    return value;
}

int play(int turns, int range){
    int num = random(range);
    while (turns > 0){
        printf("You have %d turns left\n", turns);
        printf("Guess the number (0-%d): ", range);
        int guess;
        scanf("%d", &guess);
        if (guess == num){
            printf("Congratulations! You guessed the correct number!\n");
            return 1;
        }
        else if (guess < num){
            printf("Too low. Try again.\n");
            turns--;
        }
        else {
            printf("Too high. Try again.\n");
            turns--;
        }

    }
    return 0;
}

int main(int argc, char const *argv[])
{
    printf("Welcome to the Guessing Game\n");

    while (1){
        printf("Choose your difficulty:\n For easy enter (1)\n For medium enter (2)\n For difficult enter (3)\n");
        int diff;
        scanf("%d", &diff);

        switch (diff) {
        case 1: 
        if (play(5, 30) != 1) {
            printf("Sorry you ran out of Turns\n");
        }
        break;
        case 2: 
        if (play(3, 50) != 1) {
            printf("Sorry you ran out of Turns\n");
        }
        break;
        case 3: 
        if (play(1, 100) != 1) {
            printf("Sorry you ran out of Turns\n");
        }
        break;
        default:
            printf("INVALID Difficulty Please try again!\n");
            break;
        }

        printf("Do you want to play again? (y/n): ");
        char choice;
        scanf(" %c", &choice);
        if (choice != 'y'){
            printf("Thanks for playing!\n");
            break;
        }
    }

    return 0;
}
\$\endgroup\$
0

3 Answers 3

5
\$\begingroup\$

Good re-learning effort.


Bug (kinda)

printf("Guess the number (0-%d): ", range); implies that 0 to range is a possible correct answer (or 1 to range - 1 if one views (...) as not including the endpoints.), yet rand() % range only makes for that values 0 to range - 1.

// Suggest
printf("Guess the number [0-%d]: ", range-1);

// or
// int value = rand() % N;
int value = rand() % (N + 1);

Test success of input functions

scanf("%d", &guess); returns 1 if a number was entered. But what if a non-number was entered? It returns zero. EOF is also possible.

Check the return value. Does it differ from expectations?

if (scanf("%d", &guess) != 1) {
  printf("Input is not numeric.  Quitting.\n");
  return EXIT_FAILUE;
}

Formatting

Format is OK, yet looks like it was manually done. Use an auto-formatter for efficiency and consistency.

Simplify

else if (guess < num){ is replaceable with if (guess < num){ as the previous if() block did a return.

srand() call only needed once

srand() is only needed to call once in the life of the program. Commonly this is done early via main().

Avoid naked magic numbers

// if (play(1, 100) != 1) {

#define TURNS_DIFFICULT 1
#define RANGE_DIFFICULT 100
...
if (play(TURNS_DIFFICULT, RANGE_DIFFICULT) != 1) {

Avoid very long lines

Use string literal concatenation.

// printf("Choose your difficulty:\n For easy enter (1)\n For medium enter (2)\n For difficult enter (3)\n");
printf("Choose your difficulty:\n"
    " For easy enter (1)\n"
    " For medium enter (2)\n"
    " For difficult enter (3)\n");

Avoid repeated code

Instead of if (play(x, x) != 1) { printf("Sorry you ran out of Turns\n"); 3 times, maybe something like

    switch (diff) {
      case 1: play(5, 30);
        break;
      case 2: play(3, 50);
        break;
      case 3: play(1, 100);
        break;
      default:
        printf("INVALID Difficulty Please try again!\n");
        break;
      }

.. and put the printf("Sorry you ran out of Turns\n"); in play()?


Minor: punctuation

// printf("INVALID Difficulty Please try again!\n");
printf("INVALID difficulty.  Please try again!\n");

Minor: Tolerate either case

// if (choice != 'y'){
if (choice != 'y' && choice != 'Y'){

Also research tolower().

\$\endgroup\$
1
  • \$\begingroup\$ Those are some really great suggestions. Thanks for your advice!! \$\endgroup\$ Commented Aug 20 at 13:24
2
\$\begingroup\$

In addition to the good points in the other answer, here are some other things to consider.

Displayed messages

The messages you display to the user make it clear how to play the game and make it easy to follow the progress. The following are some minor improvements.

You should show the correct number (num) when the user runs out of turns.

You should not display Try again. when the user runs out of turns.

This message is grammatically incorrect:

You have 1 turns left

You should display turn:

You have 1 turn left

Portability

There are 101 ways to compile C code. When I use gcc in my Linux operating system, I get an error message like the following:

error: conflicting types for 'random'
 int random(int N){
     ^~~~~~
In file included from ,,,
/usr/include/stdlib.h:321:17: note: previous declaration of 'random' was here
 extern long int random (void) __THROW;
                 ^~~~~~

The code compiled and ran without errors when I changed the name of the function from random to random_int.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ random() does not collide with the standard C library. It is colliding with (common) extensions employed by gcc. If OP compiled without these extensions, no conflict. Still a user random() is asking for trouble. \$\endgroup\$
    – chux
    Commented Aug 20 at 2:31
2
\$\begingroup\$

Do not use scanf() for user input:

Checking the return value alone does not suffice. If the converted input is larger than the maximum value of an int, the behavior would be undefined.

I would suggest reading the input as a string and then converting it with sscanf()/strtol() et cetera.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.