#include #include #include // picks a random number between 0 and "max" inclusive. values // returned are uniformly distributed (each possible value // is equally likely). int pick_random_int_value (int max) { // a key point - the 1.0 is a double constant. this means // that "RAND_MAX + 1.0" is double and so on. return (int) ((rand() / (RAND_MAX + 1.0)) * (max + 1)); } // displays instructions for playing the game of Nim void display_instructions (void) { cout << "\nThe game of Nim involves two players and three piles of chips.\n" << "The players move alternately. Each player, in his or her turn,\n" << "removes one or more chips from one of the piles. The player who\n" << "removes the last chip wins the game.\n"; } // puts between 10 and 20 (inclusive) chips on each of the three piles void make_initial_piles (int &pile1, int &pile2, int &pile3) { pile1 = 10 + pick_random_int_value(10); pile2 = 10 + pick_random_int_value(10); pile3 = 10 + pick_random_int_value(10); } // displays the current status of the three piles. void display_piles (int pile1, int pile2, int pile3) { cout << "Pile 1: " << pile1 << " Pile 2: " << pile2 << " Pile 3: " << pile3 << endl; } // You get to write functions "make_move", "select_computer_move", and // "get_human_move". All involve call-by-reference (of course), but not // all of the parameters involved should be call-by-reference. In some // cases, call-by-value is more appropriate. Additional functions may be // used if required. // function make_move: // removes "chips" chips from pile "pile". // it is assumed that the move is legal. // function select_computer_move: // given the current situation, selects a computer move. // it is assumed that there is at least one possible move. // function get_human_move: // obtains a valid human move by repeatedly asking for a move until valid // input is supplied. assumes that there is at least one legal move. void play_game (bool computer_to_move) { int pile1, pile2, pile3, pile_chosen, chips_removed; make_initial_piles (pile1, pile2, pile3); // display the initial situation cout << "\nInitial Situation:\n"; display_piles (pile1, pile2, pile3); for (;;) { if (computer_to_move) { select_computer_move (pile1, pile2, pile3, pile_chosen, chips_removed); make_move (pile1, pile2, pile3, pile_chosen, chips_removed); cout << "The computer has removed " << chips_removed << " chips from pile " << pile_chosen << ":\n"; if ((pile1 + pile2 + pile3) == 0) { cout << "The Computer has won!\n"; return; } } else { // human to move get_human_move (pile1, pile2, pile3, pile_chosen, chips_removed); make_move (pile1, pile2, pile3, pile_chosen, chips_removed); if ((pile1 + pile2 + pile3) == 0) { cout << "Congratulations - you have won!\n"; return; } } // display the new situation display_piles (pile1, pile2, pile3); computer_to_move = !computer_to_move; // it's now the other player's move } } void main (void) { char option; randomize (); for (;;) { // prompt user for and read option cout << "\nPlease enter option.\n" << " I = display instructions\n" << " C = play game (computer to move first)\n" << " H = play game (human to move first)\n" << " Q = quit program\n" << "Option: "; cin >> option; cin.ignore (1000, '\n'); // get rid of the rest of the input line // I've used a switch statement here just to expose you to this // C++ construct. the effect is equivalent to a multi-way "if". switch (toupper(option)) { case 'I': display_instructions (); break; // from switch statement case 'C': play_game (true); break; // from switch statement case 'H': play_game (false); break; // from switch statement case 'Q': return; default: // the equivalent of "else" cout << "\nIllegal option ignored.\n"; break; // from switch statement } } // end for (;;) }