The 21 Number Game

illustration
I occasionally visit Rosetta Code to look for C language inspiration. The site offers a programming puzzle, then presents solutions in various languages. A recent challenge involved the 21 number game — but the C language had no solution!

A C language solution exists now, but back way back when, I figured I’d give a shot.

The game works like this: You play against the computer to process numbers in sequence. You can say up to three numbers, increasing a cumulative total. The computer takes its turn. The first player to reach 21 wins.

In my version of this game, I wanted the starting opponent (player or computer) to be randomized. Either way, the player is prompted for a value to add: 1, 2, or 3. The computer then guesses its random value: 1, 2, or 3. Back and forth they go, until computer or player hits 21.

This game isn’t complex! Here’s sample output:

21 Game!
Whoever reaches 21 first wins
You go first
The tally is 0
Enter 1, 2, or 3: 3
The tally is 3
 Me: +2
The tally is 5
Enter 1, 2, or 3: 3
The tally is 8
 Me: +2
The tally is 10
Enter 1, 2, or 3: 3
The tally is 13
 Me: +1
The tally is 14
Enter 1, 2, or 3: 3
The tally is 17
 Me: +1
The tally is 18
Enter 1, 2, or 3: 3
You win!

I use scanf() for player input. A test is made for out-of-range values, in which case the computer assigns a random value 1, 2, or 3 for the silly player. Other than this trick, I programmed a tiny bit of logic into my code: When the computer recognizes the running total is 18 or greater, it “guesses” the proper value to win the game. Otherwise, its guesses are random.

Here’s the code:

2020_08_15-Lesson.c

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

/* generate random value 1, 2, 3 */
int input(void)
{
    return( rand() % 3 + 1 );
}

int main()
{
    int player,tally,pguess,cguess;

    /* title info */
    puts("21 Game!");
    puts("Whoever reaches 21 first wins");

    /* determine who goes first */
    srand( (unsigned)time(NULL) );
    player = rand() % 2;        /* 0 = computer, 1 = human */

    if( player )
        puts("You go first");
    else
        puts("I go first");

    /* run the game */
    tally = 0;
    cguess = 0;
    while( tally<21 )
    {
        printf("The tally is %d\n",tally);
        if( player )
        {
            printf("Enter 1, 2, or 3: ");
            scanf("%d",&pguess);
            if( pguess < 1 || pguess>3 )
            {
                printf("Out of range value. Let me guess for you: ");
                pguess = input();
                printf("%d\n",pguess);
            }
            tally += pguess;
            player = 0;
        }
        else
        {
            if( tally>=18 )
                cguess = 21 - tally;
            else
                cguess = rand() % 3 + 1;
            printf(" I add %d\n",cguess);
            tally += cguess;
            player = 1;
        }
    }
    /* conclusion */
    if( player )
        puts("I win!");
    else
        puts("You win!");

    return(0);
}

The core of the code is the while loop at Line 31. A random draw (Line 21) determines who goes first, but also sets the value of the player variable. An if-else structure within the while loop uses the player variable to determine whose turn it is. This variable is reset at Line 55.

For the player’s turn, the code obtains input at Line 37. If the input is out of range, if( pguess < 1 || pguess>3 ), the computer guesses for the player. The tally is increased.

The computer’s only cheat is offered at Line 49: When the tally is 18 or greater, the computer uses the exact value to reach 21:

if( tally>=18 )
    cguess = 21 - tally;

My original version of this game had a more complex input scheme, but was too clunky. So I went with scanf(), which still isn’t perfect, but it works.

Leave a Reply