How do I transform an IF statement with 2 variables onto a switch function using C?

前端 未结 7 1902
伪装坚强ぢ
伪装坚强ぢ 2021-01-27 07:49

I have an IF-statement that I want to transform into a Switch-statement... But it has 2 variables! Is it possible to do it on C?

It is a rock, paper, scissors game:

相关标签:
7条回答
  • 2021-01-27 08:09
    #include <stdio.h>
    
    #define SWITCH(a, b) char _a = a; char _b = b; if (0)
    #define CASE(a, b) } else if ((a == _a) && (b == _b)) {
    
    int main(void)
    {
        char play1, play2;
    
        printf("\nPlayer 1 - Enter your Play:");
        scanf ("%c", &play1);
        getchar();
        printf("\nPlayer 2 - Enter your Play:");
        scanf ("%c", &play2);
        getchar();
    
        SWITCH(play1, play2) {
            CASE('R','P') printf ("Paper wins!");
            CASE('R','S') printf ("Rock wins!");
            CASE('R','R') printf ("Draw!");
        }
        return 0;
    }
    

    It's a joke :P

    EDIT: case support of ":"

    #define PASTE(a, b) a##b
    #define LABEL(a, b) PASTE(a, b)
    #define SWITCH(a, b) char _a = a; char _b = b; if (0)
    #define CASE(a, b) } else if ((a == _a) && (b == _b)) { LABEL(LBL, __LINE__)
    

    But doesn't work with:

    CASE('R','R'): printf ("Draw a!"); CASE('S','R'): printf ("Draw!");
    

    Two cases in the same line

    Solved using:

    #define SWITCH(a, b) char _a = a; char _b = b; if (0)
    #define CASE(a, b) } else if ((a == _a) && (b == _b)) {switch(1) case 1
    

    Hope nobody use it :)

    0 讨论(0)
  • 2021-01-27 08:11
    #include <stdio.h>
    #include <stdlib.h>
    
    #define PAIR(X,Y) (X<<8)|Y
    
    int main()
    {
        char play1, play2;
    
        printf("\nPlayer 1 - Enter your Play: ");
        scanf ("%c", &play1);
        printf("\nPlayer 2 - Enter your play: ");
        scanf (" %c", &play2); 
    
        switch (PAIR(play1, play2)) {
            case PAIR('R','P'):
                printf ("Paper wins!\n");
                break;
            case PAIR('R','S'):
                printf ("Rock wins!\n");
                break;
            case PAIR('R','R'):
                printf ("Draw!\n");
                break;
            default: //any thing else
                printf ("Default!\n");
                break;
        }
    }
    
    0 讨论(0)
  • 2021-01-27 08:11

    The too-clever-by-half solution:

    enum Play { Rock = 0, Paper = 1, Scissors = 2 };
    enum Outcome { Tie = 0, P1Win = 1, P2Win = 2 };
    
    enum Play parseMove(char input) {
        switch (input) {
            case 'R': return Rock;
            case 'P': return Paper;
            case 'S': return Scissors;
            default: /* invalid input */;
        }
    }
    
    enum Outcome gameResult(enum Play p1, enum Play p2) {
        return (3 + p1 - p2)%3;
    }
    
    ...
    
    switch(gameResult(parseMove(play1), parseMove(play2))) {
        case Tie: printf("Tie!\n");
        case P1Win: printf("Player 1 wins!\n");
        case P2Win: printf("Player 2 wins!\n");
    }
    
    0 讨论(0)
  • 2021-01-27 08:13

    You can nest your switch statements for each expression, such as

    switch(a)
    {
      case 'A':
        switch(b)
        {
          case 0: // do something with A0
            break;
          case 1: // do something with A1
            break;
          ...
        }
        break;
    
      case 'B':
        switch(b)
        {
          case 0: // do something with B0
            break;
          ...
        }
        break;
      ...
    }
    

    As you can see, this has the potential to get very ugly very quickly. If you have to branch based on combinations of values, then you're probably better off keeping the current structure.

    0 讨论(0)
  • 2021-01-27 08:21

    Since switch operates on a single variable, you'd have to be able to combine your multiple inputs into a single value somehow. Given the numerical values for the ASCII characters 'R', 'P', and 'S', adding the two characters together would give you a unique sum for each pairing. However, the resulting code would likely be more difficult to read than the equivalent if tree. In general, this usually isn't a good option because your code will very easily break when new input options are added and the underlying assumptions for your "combination" operation (such as a unique sum) no longer hold. switch also becomes unwieldy as the number of possible input values increases. Since you need a case for every possible combination, your switch would become large and difficult to maintain when used with anything more than a handful of input options.

    A switch block will actually result in more code than using if for this particular case. Using if gives you the ability to handle multiple cases at once. For example, you don't need three separate versions of the code that checks for a tie. You can also use a table to look up answers instead of switch or if. Here's an example that combines these approaches:

    // Table of outcomes.  The option in the second
    // column wins over the option in the first column.
    char matchup[3][2] = {
      {'P', 'S'}, // paper is cut and destroyed
      {'S', 'R'}, // scissors are smashed and destroyed
      {'R', 'P'}, // rock is ... covered up?
    };
    
    void announce_winner(char player1, char player2)
    {
      int i;
    
      if (player1 == player2) {
        printf("Draw\n");
        return;
      }
    
      for (i=0; i<3; ++i) {
        if (player1 == matchup[i][0])
          printf("%c wins\n", (player2 == matchup[i][1]) ? player2 : player1);
      }
    }
    

    The big benefit of the table approach is that your code is separate from your data. If the rules of the game change or if someone is learning the game and wants to find out who wins in what situation, a table becomes much more user-friendly than having to dig through a lot of code. A switch block is essentially the lookup table and the handling code all mixed together and for complex cases, it gets ugly fast.

    0 讨论(0)
  • 2021-01-27 08:24

    I would recommend multi-character character constants to achieve this in a succinct manner:

    switch ((play1 << 8) + play2) {
    
      case 'RP':
    
        printf ("Paper wins!");
        break;
    
      case 'RS':
    
        printf ("Rock wins!");
        break;
    
      case 'RR':
    
        printf ("Draw!");
        break;
     }
    
    0 讨论(0)
提交回复
热议问题