Lab Assignment -- WSU Tri-Cities CptS 121 (Spring, 2017)

Lab 9: Pointers

This lab will develop your skills in creating functions that have a variety of ways to handle inputs and outputs and in working with pointers.

This page will be available as

http://www.tricity.wsu.edu/~bobl/cpts121/lab09_pointers/writeup.html

Calling it up in a browser will allow you to cut-and-paste the templates below into your editor and save editing time.

Plug your thumbdrive into your workstation. Give it a few seconds to be recognized by Windows and then create a MinGW terminal emulator. In that emulator, create a new directory for this lab and cd to it:

$ cd /e/cpts121
$ mkdir lab09
$ cd lab09

As always, keep all your work for this lab in this directory.

The Game of "Nim"

We have already discussed the "nim" game in class. As a reminder, the rules are these:

Assignment

Here is a the nim program we developed in class with some added comments:

#include <stdio.h>


int main(void)
{
    int heapCount1, heapCount2, heapCount3;
    int heap, player, take;
    int *heapCount_p;

    /* initialize heap counts */
    heapCount1 = 3;
    heapCount2 = 4;
    heapCount3 = 5;

    player = 2; // first player will be player 1 (see below)

    /* while any stones remain, */
    while (heapCount1 + heapCount2 + heapCount3 > 0)
    {
        /* select the next player */
        player = 3 - player; // player 1 -> 2 and 2 -> 1

        printf("player %d's turn\n", player);

        /* print out the counts */
        printf("heap 1: %d\n", heapCount1);
        printf("heap 2: %d\n", heapCount2);
        printf("heap 3: %d\n", heapCount3);

        /* let the player select a heap that contains at least one stone */
        for (;;)
        {
            /* let the player select a heap */
            for (;;)
            {
                printf("     heap to take stones from (1 - 3): ");
                scanf("%d", &heap);
                if (1 <= heap && heap <= 3)
                {
                    break;
                }
                printf("illegal heap value -- try again\n");
            }

            /*
             * At this point, we know that `heap` is valid, so we
             * check to make sure it's not empty.
             */

            /* make `heapCount_p` point at the relevant heap */
            switch (heap)
            {
            case 1:
                heapCount_p = &heapCount1;
                break;

            case 2:
                heapCount_p = &heapCount2;
                break;

            case 3:
                heapCount_p = &heapCount3;
                break;
            }

            /*
             * If there are stones in it, the move is legal, so break
             * out of the loop.
             */
            if ((*heapCount_p) > 0)
            {
                break;
            }
            printf("heap %d contains no stones -- try again\n", heap);
        }

        /* let the player select a "take" -- a count of stones to remove */
        for (;;)
        {
            printf("count of stones to take from heap %d (1 - %d): ",
                   heap, (*heapCount_p));
            scanf("%d", &take);
            /*
             * If the take is in the proper range, the move is legal,
             * so break out of the loop.
             */
            if (1 <= take && take <= (*heapCount_p))
            {
                break;
            }
            printf("illegal heap count -- try again\n");
        }

        /* deduct those stones */
        (*heapCount_p) -= take;

        printf("\n"); // blank line for cosmetic purposes
    }
    /* declare the last player the winner */
    printf("player %d wins\n", player);
    return 0;
}

You can download it as a single file:

http://www.tricity.wsu.edu/~bobl/cpts121/lab09_pointers/nim_baseline.c

Download it and compile it to make sure you have working code as a reference.

The objective of this lab is for you to rewrite (or "refactor") the code we developed in class to improve its readability by decomposing it into five separate, well-defined functions:

printStatus()
prints out the player (number) whose turn it is and the current contents of all heaps.
setHeapCountPointer()
returns a pointer to the appropriate heap count, given the heap number.
getHeap()
prompts the user for a (legal) heap number.
getTake()
prompts the user for a (legal) number of stones to take from a given heap.
playNim()
plays the game and returns the winner. (We have already refactored this in the template below.)

The first four functions are independent of each other, but playNim() will call the others. Do not implement the same code in more than one place. (i.e. "DRY -- Don't Repeat Yourself")

The listing marks off the sections of code that belong to each function. Replace each section with a call to that function. When you turn that code into a function and design its prototype, look at the block of code and answer these questions:

Constraints:

Here is a template to put all of these functions in. As a demonstration, we have already done this for playNim(). You are not permitted to modify main():

#include <stdio.h>


/*
 * ASSIGNMENT
 *
 * Cut, paste, and (slightly) modify `printStatus()` here.
 */


/*
 * ASSIGNMENT
 *
 * Cut, paste, and (slightly) modify `getHeap()` here.
 */


/*
 * ASSIGNMENT
 *
 * Cut, paste, and (slightly) modify `getHeapCountPointer()` here.
 */


/*
 * ASSIGNMENT
 *
 * Cut, paste, and (slightly) modify `getTake()` here.
 */


/*
 * Here is the (already-refactored) `playNim()` function as an
 * example.
 */

int playNim(void)
{
    int heapCount1, heapCount2, heapCount3;
    int heap, player, take;
    int *heapCount_p;

    /* initialize heap counts */
    heapCount1 = 3;
    heapCount2 = 4;
    heapCount3 = 5;

    player = 2; // first player will be player 1 (see below)

    /* while any stones remain, */
    while (heapCount1 + heapCount2 + heapCount3 > 0)
    {
        /* select the next player */
        player = 3 - player; // player 1 -> 2 and 2 -> 1

        // ---- beginning of `printStatus()` code
        //      (replace with `printStatus()` call)
        printf("player %d's turn\n", player);
        /* print out the counts */
        printf("heap 1: %d\n", heapCount1);
        printf("heap 2: %d\n", heapCount2);
        printf("heap 3: %d\n", heapCount3);
        // ---- end of `printStatus()` code

        /* let the player select a heap that contains at least one stone */
        for (;;)
        {
            /* let the player select a heap */
            // ---- beginning of `getHeap()` code
            //      (replace with `getHeap()` call)
            for (;;)
            {
                printf("     heap to take stones from (1 - 3): ");
                scanf("%d", &heap);
                if (1 <= heap && heap <= 3)
                {
                    break;
                }
                printf("no such heap -- try again\n");
            }
            // ---- end of `getHeap()` code
            /*
             * At this point, we know that `heap` is valid, so we
             * check to make sure it's not empty.
             */

            // ---- beginning of `getHeapCountPointer()` code
            //      (replace with `getHeapCountPointer()` call)
            /* make heapCount_p point at the relevant heap */
            switch (heap)
            {
            case 1:
                heapCount_p = &heapCount1;
                break;

            case 2:
                heapCount_p = &heapCount2;
                break;

            case 3:
                heapCount_p = &heapCount3;
                break;
            }
            // ---- end of `getHeapCountPointer()` code
            if ((*heapCount_p) > 0)
            {
                break;
            }
            printf("heap %d contains no stones -- try again\n", heap);
        }

        /* let the player select a "take" -- a count of stones to remove */
        // ---- beginning of `getTake()` code
        //      (replace with `getTake()` call)
        for (;;)
        {
            printf("count of stones to take from heap %d (1 - %d): ",
                   heap, (*heapCount_p));
            scanf("%d", &take);
            /*
             * If the take is in the proper range, the move is legal,
             * so break out of the loop.
             */
            if (1 <= take && take <= (*heapCount_p))
            {
                break;
            }
            printf("illegal stone count -- try again\n");
        }
        // ---- end of `getTake()` code

        /* deduct those stones */
        (*heapCount_p) -= take;

        printf("\n"); // blank line for cosmetic purposes
    }
    return player;
}


int main(void)
{
    int winner;

    winner = playNim();
    printf("player %d wins\n", winner);
    return 0;
}

You can download it as a single file:

http://www.tricity.wsu.edu/~bobl/cpts121/lab09_pointers/nim_tplt.c

It is recommended that you complete the functions in the above order. After creating one function, recompile nim and make sure it still works before creating the next function. This is a good way to proceed with refactoring.