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.