//========================================================================= #define PROGRAMMER "SOLUTIONS, Nofrills" #define PROG_CODE "soln" #define COURSE "ECE-1021" #define YEAR (2004) #define TERM "Spring" #define SECTION (0) #define ASSIGNMENT "HW #6B" #define REVISION (0) #define TITLE "Mancala Enginer" #define SUBTITLE "Two-Player Version" #define EMAIL "ece1021@eas.uccs.edu" #define FILENAME "06b0soln.c" //========================================================================= //========================================================================= // PROBLEM //========================================================================= // // // Write a Mancala Engine to allow two-player human play. // // ================================================================= // | | 1 | 2 | 3 | 4 | 5 | 6 | | // ================================================================= // | | | | | | | | | // | | 4 | 4 | 4 | 4 | 4 | 4 | | // | | | | | | | | | // | 0 |=======|=======|=======|=======|=======|=======| 0 | // | | | | | | | | | // | | 4 | 4 | 4 | 4 | 4 | 4 | | // | | | | | | | | | // ================================================================= // | | 6 | 5 | 4 | 3 | 2 | 1 | | // ================================================================= // // Player[2][7] // Player[n][0] => Player n's Kalaha // Player[n][b] => Plyaer n's bin b ( 1 <= b <= 6 ) // // PLAYER A is player 0 and is on top // PLAYER B is player 1 and is on top //========================================================================= // PSEUDOCODE //========================================================================= // // 1) TASK: Initial Setup Actions // 1.1) TASK: Initialize the Board. // 1.2) TASK: Select which player will start. // 1.3) TASK: Display the Game Board // 2) TASK: Play a Game of Mancala // 2.1) WHILE: (Game is not over) // 2.1.1) TASK: Get move from present player. // 2.1.2) TASK: Check if move is legal and forfeit if not // 2.1.2.1) IF: (move is not legal) // 2.1.2.1.1) TASK: Make present player forfeit game. // 2.1.3) TASK: Execute the move // 2.1.4) TASK: Update present player // 2.1.5) TASK: Display the Game Board // 3) TASK: Display the results //========================================================================= // DEVIATIONS FROM SUBMITTED PSEUDOCODE //========================================================================= // // 1) Selection of starting player now takes an argument to determine // how the starting player is chosen (for testing purposes). // // 2) The board display was modified to include the player identifiers // and an indication of whose turn it was. // // 3) Error in gameover check. Was if kalahas total < 48 and should be // if kalahas total is 48. // // 4) Top level tasks of checking for forfeit and updating player moved // to the ExecuteMove() function. //========================================================================= // WAIVED COMPILER WARNINGS //========================================================================= // // Linker Warning: No module definition file specified: using defaults // Reason for Waiver: Can't suppress. Does not have adverse impact. //========================================================================= // CODE SECTION //========================================================================= //== INCLUDE FILES ======================================================== #include // printf() #include // rand(), randomize() #include // randomize() //== MACRO DEFINITIONS ==================================================== #define FALSE (0) #define TRUE (!FALSE) #define BLANKLINE printf("\n") #define PLAYERA (0) #define PLAYERB (1) #define KALAHA (0) #define PLAYERPICKMODE (2) //== FUNCTION PROTOTYPES (for Primary Functions) ========================== void PrintHeader(void); void InitializeBoard(char board[2][7]); int SelectStartingPlayer(int how); void PrintBoard(char board[][7], int player); int IsGameOver(char board[2][7]); int GetPlayerMove(int player); int ExecuteMove(char board[][7], int player, int bin); void DisplayResults(char board[2][7]); //== MAIN FUNCTION ======================================================== int main(void) { char board[2][7]; int player; int bin; PrintHeader(); BLANKLINE; // 1) TASK: Initial Setup Actions InitializeBoard(board); player = SelectStartingPlayer(PLAYERPICKMODE); PrintBoard(board, player); // 2) TASK: Play a Game of Mancala while(!IsGameOver(board) ) { bin = GetPlayerMove(player); player = ExecuteMove(board, player, bin); PrintBoard(board, player); } // 3) TASK: Display the results DisplayResults(board); return(0); } //========================================================================= // PRIMARY FUNCTIONS (functions called directly by main() ) //========================================================================= //== FUNCTION PROTOTYPES (for Support Functions) ========================== int printc(char c, int n); int MakeMove(char board[2][7], int player, int bin); int SeedsLeft(char board[2][7], int player); int ForfeitGame(char board[2][7], int player); void SweepBoard(char board[2][7]); //== PRIMARY FUNCTIONS ==================================================== void PrintHeader(void) { printc('=', 79); printf("\n"); printf("Course....... %s-%i (%s %i)\n", COURSE, SECTION, TERM, YEAR); printf("Programmer... %s (%s)\n", PROGRAMMER, PROG_CODE); printf("Assignment... %s (Rev %i) (Source Code in %s)\n", ASSIGNMENT, REVISION, FILENAME); printf("Description.. %s\n", TITLE); printf(" %s\n", SUBTITLE); printc('=', 79); printf("\n"); return; } //========================================================================= // SUPPORT FUNCTIONS (functions not called directly by main() ) //========================================================================= int printc(char c, int n) { while(0 < n--) printf("%c", c); return(n); } //------------------------------------------------------------------------- // TASK: Initialize the Board. //------------------------------------------------------------------------- // // PASSED IN: board // 1) TASK: Emply kalahas // 1.1) SET: board[n][0] = 0 for n = {0->1} // 2) TASK: Load bins // 2.1) SET: board[n][b] = 0 for n = {0->1} and b = {1->6} // 3) RETURN: void InitializeBoard(char board[2][7]) { int player, bin; for(player = 0; player < 2; player ++) { board[player][0] = 0; for(bin = 1; bin < 7; bin++) board[player][bin] = 4; } return; } //------------------------------------------------------------------------- // TASK: Select which player will start. //------------------------------------------------------------------------- // // PASSED IN: // 1) TASK: Select starting player // 1.1) SET: player = random integer in the range (0->1) // 2) RETURN: player int SelectStartingPlayer(int how) { switch(how) { case -1: return(rand()%2); case 0: return(0); case 1: return(1); case 2: randomize(); return(SelectStartingPlayer(-1)); } return(0); } //------------------------------------------------------------------------- // TASK: Display the Game Board //------------------------------------------------------------------------- // // PASSED IN: board // 1) TASK: Display Player B Identifier // 2) TASK: Display Player B Bin Labels // 3) TASK: Display Player B Bin Contents // 4) TASK: Display Dividing Line and Kalaha Contents // 5) TASK: Display Player A Bin Contents // 6) TASK: Display Player A Bin Labels // 7) TASK: Display Player A Identifier void DisplayIdentifier(int side, int player); void DisplayBinLabels(int side); void DisplayBinContents(int side, char board[2][7]); void DisplayKalahas(char board[2][7]); void PrintBoard(char board[][7], int player) { printc('\n', 10); DisplayIdentifier(PLAYERA, player); DisplayBinLabels(PLAYERA); DisplayBinContents(PLAYERA, board); DisplayKalahas(board); DisplayBinContents(PLAYERB, board); DisplayBinLabels(PLAYERB); DisplayIdentifier(PLAYERB, player); fflush(stdout); return; } void DisplayIdentifier(int side, int player) { int c; printf("\n"); c = (side==player)? '*' : ' '; printc(' ', 20); printc(c, 10); printf(" PLAYER %c ", ('A' + side)); printc(c, 10); printf("\n\n"); return; } void DisplayBinLabels(int side) { int bin; // Top Line printf(" "); printc('=', 65); printf("\n"); // Bin Labels printf(" "); printf("| |"); switch(side) { case PLAYERA: for(bin = 1; bin <= 6; bin++) printf(" %1i |", bin); break; case PLAYERB: for(bin = 6; bin >= 1; bin--) printf(" %1i |", bin); break; } printf(" |\n"); // Bottom Line printf(" "); printc('=', 65); printf("\n"); return; } void DisplayBinContents(int side, char board[2][7]) { int bin; // Top Line printf(" "); printf("| |"); for(bin = 1; bin <= 6; bin++) printf(" |"); printf(" |\n"); // Bin Contents printf(" "); printf("| |"); switch(side) { case PLAYERA: for(bin = 1; bin <= 6; bin++) printf(" %2i |", board[side][bin]); break; case PLAYERB: for(bin = 6; bin >= 1; bin--) printf(" %2i |", board[side][bin]); break; } printf(" |\n"); // Bottom Line printf(" "); printf("| |"); for(bin = 1; bin <= 6; bin++) printf(" |"); printf(" |\n"); return; } void DisplayKalahas(char board[2][7]) { int bin; printf(" "); printf("| %2i |", board[PLAYERA][0]); for(bin = 1; bin <= 6; bin++) printf("=======|"); printf(" %2i |\n", board[PLAYERB][0]); return; } //------------------------------------------------------------------------- // TASK: Check if Game is over //------------------------------------------------------------------------- // // PASSED IN: board // 1) TASK: Check for any seeds in any bins other than kalahas // 1.1) IF( sum of seeds in both kalahas == 48 ) // 1.1.1) SET: gameover = TRUE // 1.2) ELSE // 1.2.1) SET: gameover = FALSE // 2) RETURN: gameover int IsGameOver(char board[2][7]) { return( 48 == (board[PLAYERA][KALAHA] + board[PLAYERB][KALAHA]) ); } //------------------------------------------------------------------------- // TASK: Get move from present player. //------------------------------------------------------------------------- // // PASSED IN: board, player // 1) TASK: Prompt player which bin they want to sow. // 2) TASK: Get number of bin to sow from player. // 3) RETURN: bin int GetPlayerMove(int player) { int bin; printf("Player %c - Enter Bin to sow (1-6): ", ('A' + player)); scanf("%i", &bin); return(bin); } //------------------------------------------------------------------------- // TASK: Check if move is legal //------------------------------------------------------------------------- // // PASSED IN: board, player, bin // 1) TASK: Check that the player's bin has at least one seed // 1.1) IF( board[player][bin] > 0) // 1.1.2) SET: legal = TRUE // 1.2) ELSE // 1.2.1) SET: legal = FALSE // RETURN: legal int IsMoveLegal(char board[2][7], int player, int bin) { return( (0bin) && (0 < board[player][bin]) ); } //------------------------------------------------------------------------- // TASK: Execute the move //------------------------------------------------------------------------- // // 1) IF: (move is not legal) // 1.1) TASK: Make present player forfeit game. // 1.1.1) OUT: "Illegal Move" message to user. // 1.1.2) SET: bin = 0 (to inform the Execute Move task of the forfeit. // 2) TASK: Make the move // 3) RETURN: Next player (return value from Make Move) int ExecuteMove(char board[2][7], int player, int bin) { if( !IsMoveLegal(board, player, bin) ) { printf(" *** ILLEGAL MOVE - GAME IS FORFEIT! *** "); bin = 0; } return(MakeMove(board, player, bin)); } //------------------------------------------------------------------------- // TASK: Execute the move //------------------------------------------------------------------------- // // PASSED IN: board, player, bin // 1) IF: (game is forfeit) // 1.1) TASK: Empty all bins // 1.2) TASK: Empty player's kalaha // 1.3) TASK: Place all seeds in other players kalaha // 2) ELSE: // 2.1) TASK: Empty the bin to be sown // 2.1.1) SET: board[player][bin] = 0 // 2.2) TASK: Sow the seeds around the board // 3) IF: (last seed placed in empty bin on player's side) // 3.1) TASK: Place last seed sown in player's kalaha // 3.1.1) SET: board[player][kalaha] += 1 // 3.1.2) SET: board[player][lastbin] = 0 // 3.2) TASK: Place seeds in bin opposite in player's kalaha // 3.2.1) SET: board[player][kalaha] += board[other player][7-lastbin] // 3.2.2) SET: board[other player][7 - lastbin] = 0 // 3) IF: (last seed placed in player's kalaha) // 3.1) SET: nextplayer = player // 4) ELSE: // 4.1) SET: nextplayer = other player // 5) RETURN: nextplayer int MakeMove(char board[2][7], int player, int bin) { int side, seeds; // Act on a Forfeit condition if(0 == bin) return(ForfeitGame(board, player)); // returns -1 // Perform the requested (legal) move side = player; seeds = board[player][bin]; board[player][bin] = 0; while(seeds > 0) { bin--; // Move to next counterclockwise bin if( (0 == bin) && (side != player) ) // Jump over opponents kalaha bin--; if(0 > bin) // Moved past the kalaha - got to other side { side = !side; bin = 6; } board[side][bin]++; seeds--; } // IF: last seed placed in an empty bin on player's side - capture if( (side == player) && (0 < bin) && (1 == board[side][bin]) ) { // Place last seed sown in player's kalaha board[player][KALAHA] += 1; board[player][bin] = 0; // TASK: Place seeds in bin opposite in player's kalaha board[player][KALAHA] += board[!player][7-bin]; board[!player][7-bin] = 0; } // IF: Last seed not into player's kalaha - opponent's turn if( !( (0 == bin) && (side == player) ) ) player = !player; // Check for End of Game (either player has no seeds left) if(0 == (SeedsLeft(board, PLAYERA) * SeedsLeft(board, PLAYERB)) ) SweepBoard(board); return(player); } int SeedsLeft(char board[2][7], int player) { int bin, seeds; for(seeds = 0, bin = 1; bin < 7; bin++) seeds += board[player][bin]; return(seeds); } int ForfeitGame(char board[2][7], int player) { int bin; board[player][0] = 0; board[!player][0] = 48; for(player = 0; player < 2; player ++) { for(bin = 1; bin < 7; bin++) board[player][bin] = 0; } return(-1); } void SweepBoard(char board[2][7]) { int player, bin; for(player = 0; player < 2; player ++) { for(bin = 1; bin < 7; bin++) { board[player][0] += board[player][bin]; board[player][bin] = 0; } } return; } //------------------------------------------------------------------------- // TASK: Display the results //------------------------------------------------------------------------- // // PASSED IN: board // 1) TASK: Display final score // 1.1) OUT: Player A: board[0][kalaha] // 1.2) OUT: Player B: board[1][kalaha] // 2) TASK: Announce winner // 2.1) IF: (board[0][kalaha] == board[1][kalaha]) // 2.1.1) OUT: Tie Game // 2.2) ELSE: // 2.2.1) IF: (board[0][kalaha] > board[1][kalaha]) // 2.2.1.1) OUT: Player A wins // 2.2.2) ELSE: // 2.2.2.1) OUT: Player B wins void DisplayResults(char board[2][7]) { BLANKLINE; printf("Final Score:\n"); printf("Player A: %2i", board[PLAYERA][KALAHA]); if(board[PLAYERA][KALAHA] > board[PLAYERB][KALAHA]) printf(" WINNER"); printf("\n"); printf("Player B: %2i", board[PLAYERB][KALAHA]); if(board[PLAYERA][KALAHA] < board[PLAYERB][KALAHA]) printf(" WINNER"); printf("\n"); if(board[PLAYERA][KALAHA] == board[PLAYERB][KALAHA]) printf("TIE GAME"); return; }