0

I'm in an intro to C class, and my professor has assigned us to code a game called "tea party" for our current assignment. I've finished coding the game, and it works for the most part, but there are some certain kinks that I can't seem to work out.

The rules of the game are simple: two players take turns spinning the spinner (emulated by entering "0" and pressing enter), and collecting all 7 items for the tea party. The first player to get all 7 items wins. The only catch is that you cannot collect a sandwich, fruit, or dessert unless you have a plate first. If you land on the LOSE A PIECE square, you must give up one of your pieces. Both of the errors come from the lose a piece instance in the game, so I'm thinking the error must originate from the "get_lost_piece" function.

One of them is that the pieces from the "player" array are numbered oddly in that they are 1 value higher than they should be. The other error is that when a player tries to remove their plate while they have an item that requires the plate, it should print out "Sorry, it is bad manners to eat without a plate. Enter another choice:", but instead, I get an infinite loop that reads "You lost item 1."

Here is the code I have:

    #include <stdio.h>
    #include <time.h>

    #define SLOW_MODE 1

    #define NUMPLAYERS 2
    #define NUMPIECES 7
    #define MAXLEN 20
    #define NO_WINNER -1

    const char CHOICES[NUMPIECES+1][MAXLEN] = {"PLATE", "NAPKIN", "TEA CUP", "CREAM AND    SUGAR", "SANDWICH", "FRUIT", "DESSERT", "LOSE A PIECE"};

        void update_player(int player[], int square);
    int get_lost_piece(int player[]);
    int search(int piece_list[], int choice);
    int get_spin();
    void init_player(int player[]);
    int get_winner(int players[][NUMPIECES]);
    int get_next_player(int player_num);
    int count_pieces(int player[]);
    void print_player(int player[], int player_num);

    int main() {

    srand(time(0));

    int players[NUMPLAYERS][NUMPIECES];

    // Initialize each player in the game.
    int i;
    for (i=0; i<NUMPLAYERS; i++)
        init_player(players[i]);

    int player_number = 0;

    // Play until we get a winner.
    int status = get_winner(players);
    while (status == NO_WINNER) {

        int dummy;

        // In slow mode, we stop before every spin.
        if (SLOW_MODE) {
            printf("Player %d, it is your turn. Type 0 and enter to spin.\n", player_number+1);
            scanf("%d", &dummy);
        }

        // Get the current player's spin and print out her pieces.
        int square = get_spin();
        printf("Player %d, have landed on the square %s.\n", player_number+1, CHOICES[square]);
        update_player(players[player_number], square);
        print_player(players[player_number], player_number+1);

        // Update the game status.
        player_number = get_next_player(player_number);
        status = get_winner(players);
        printf("\n\n");
    }

    printf("Congrats player %d, you win!\n", status+1);

    return 0;
}

    // Pre-conditions: player stores the contents of one player and square is in between 0 and 7, inclusive.
    // Post-conditions: The turn for player will be executed with the given square selected.
void update_player(int player[], int square) {

    if (square == 7) {

        if (count_pieces(player) == 0)
        {
            printf("There is no piece for you to lose. Lucky you, sort of.\n");
            return;
        }

        else{
            int q;
            q = get_lost_piece(player);
            player[q]= 0;

        }
        return;
    }

    player[square]=search(player, square);

    // Restricted by having no plate!
    if (player[0] == 0) {

       if(square == 4 || square == 5 ||square == 6){
        printf("Sorry, you can't obtain that item because you don't have a plate yet.\n");}

        else{
            if (player[square] == 0){
                player[square]++;
        }
        }
        }

    // Process a regular case, where the player already has a plate.
    else {
        if (player[square] == 0){
            player[square]++;
        }
        }
    }


    // Pre-conditions: player stores the contents of one player that has at least one piece.
    // Post-conditions: Executes asking a player which item they want to lose, and reprompts them
//                  until they give a valid answer.
int get_lost_piece(int player[]) {


    int choice = -1;



    // Loop until a valid piece choice is made.
    while (1) {
    if (choice == -1){
        printf("Which piece would you like to lose?\n");
        print_player(player,choice);
        scanf("%d", &choice);}
    if (player[choice] == 0 && choice < 7 && choice >= 0){
        printf("Sorry, that was not one of the choices");
        scanf("%d", &choice);
        }
    if (player[0] == 1 && choice == 4 || choice == 5 ||choice == 6){
        printf("Sorry, it is bad manners to eat without a plate. Enter another choice:\n");
        scanf("%d", &choice);
        }

    else{
        printf("You lost piece %d\n", choice);
        }
    }

    return choice;
}

// Pre-conditions: piece_list stores the contents of one player
// Post-conditions: Returns 1 if choice is in between 0 and 6, inclusive and corresponds to
//                  an item in the piece_list. Returns 0 if choice is not valid or if the
//                  piece_list doesn't contain it.
int search(int piece_list[], int choice) {

    int i;
    for (i=0; i<NUMPIECES; i++){
        if(piece_list[i]==choice){
           return 1;}
        else {return 0;}
    }
}
// Pre-condition: None
// Post-condition: Returns a random value in between 0 and 7, inclusive.
int get_spin() {

   return rand() % 8;

}

// Pre-condition: None
// Post-condition: Initializes a player to have no pieces.
void init_player(int player[]) {

  int j;

  for (j=0; j< NUMPIECES; j++)
    player[j]=0;

}

// Pre-condition: players stores the current states of each player in the tea party game.
// Post-condition: If a player has won the game, their 0-based player number is returned.
//                 In the case of no winners, -1 is returned.
int get_winner(int players[][NUMPIECES]) {

   int i =0;
  for (i=0; i<NUMPLAYERS; i++){
    if(count_pieces(players[i]) == NUMPIECES) {
        return i;}
  }
 return -1;


}

// Pre-condition: 0 <= player_num < NUMPLAYERS
// Post-condition: Returns the number of the next player, in numerical order, with
//                 a wrap-around to the beginning after the last player's turn.
int get_next_player(int player_num) {

    player_num++;
    if (player_num == NUMPLAYERS){
        player_num = 0;
    }
    return player_num;

}


// Pre-conditions: player stores the contents of one player
// Post-conditions: Returns the number of pieces that player has.
int count_pieces(int player[]) {

    int y, counter;

    counter = 0;

    for ( y = 0; y < 7; y++){
        if(player[y] == 1){
        counter++;
        }
    }
return counter;
}

// Pre-conditions: player stores the contents of one player and player_num is that
//                 player's 1-based player number.
// Post-conditions: Prints out each item the player has, numbered with the numerical
//                  "codes" for each item.
void print_player(int player[], int player_num) {

    int i;

    printf("\n");
    printf("Player %d\n", player_num);

    for (i=0; i < 7; i++){
        if (player[i] == 1){
            printf("%d. %s\n", i + 1, CHOICES[i]);
        }
    }

}

Thanks for the help in advance. I get the feeling that the solution is staring me right in the face, but after spending a couple of days on this, I'm having difficulty spotting the problem.

Batteries
  • 151
  • 2
  • 2
  • 7
  • 2
    Well, the first problem I see is that there's no way to break out of the `while (1)` loop in `get_lost_piece`. You probably want to move the `return choice;` to right after `printf("You lost piece %d\n", choice);`. – jwodder Apr 14 '12 at 02:53
  • Can you please edit your post and break the initial chunk of text into readable paragraphs? As it is, it's almost impossible to wade through because it's all a jumble. They created paragraphs just to prevent that from being a problem. :) Thanks. – Ken White Apr 14 '12 at 03:01
  • 2
    Sorry about that Ken, I hope it's more readable this time. – Batteries Apr 14 '12 at 03:04
  • Very much an improvement. Thanks. :) – Ken White Apr 14 '12 at 03:05
  • Maybe not the core of the problem, but `if (player[choice] == 0 && choice < 7 && choice >= 0)` should validate choice range first to prevent out of bounds condition. The input loop could be refactored to get input one time. Check the logic on the other if statements in that function. It went into an infinite loop when P2 lost a piece. – hellork Apr 14 '12 at 05:08
  • Avoid `while(1)`: http://stackoverflow.com/a/1420100/59087 – Dave Jarvis Apr 14 '12 at 06:52
  • I don't un derstnd this : // Restricted by having no plate! if (player[0] == 0) { why player[0]? – Deblaton Jean-Philippe Apr 14 '12 at 08:30

1 Answers1

0
  • need #include <stdlib.h> for rand(), srand()
  • add player_number parameter to get_lost_piece() and pass it to print_player.

The following is just one idea for refactoring. It could be done many different ways.

  • Get input once at the start of the loop.
  • Use continue keyword in each if statement to redo the loop.

It works fine when I change the logic of get_lost_piece() to:

 while...
     get choice
     if  choice < 1 || choice > 7   "1-7 please..." continue
     if  player[choice - 1] == 0   "sorry..." continue
     if  choice == 1  (and player[] contains foods)   "bad manners..." continue
 return choice - 1;

Helpful hints

  • Loop should be limited and needs to give player a quit option.
  • Check out FAQ entry: scanf() returns errors, leaves stuff on input stream.
  • Test early, test often.
  • Turn up compiler warnings (as suggested by catcall)
hellork
  • 420
  • 2
  • 5