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.
We have already discussed the "nim" game in class. As a reminder, the rules are these:
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:
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.