0

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:

(R for rock, P for Paper, S for Scissors)

     char play1, play2;

     printf("\nPlayer 1 - Enter your Play: ");
     scanf ("%c", &play1);
     printf("\nPlayer 2 - Enter your Play: ");
     scanf (" %c", &play2); 


     if (play1 == 'R' && play2 == 'P') {
       printf ("Paper wins!"); }
      else if (play1 == 'R' && play2 == 'S') {
        printf ("Rock wins!");}
      else if (play1 == 'R' && play2 == 'R) {
        printf ("Draw!");}

and I have to do this for the others options, so it would be better to use switch!

Derek
  • 1,104
  • 13
  • 35
Tiago C.
  • 39
  • 1
  • 7
  • Please show us your code. – SLaks Jan 04 '13 at 15:55
  • 1
    1. Why do you want to do this? 2. Post the actual if-statement in question. – Stephen Canon Jan 04 '13 at 15:55
  • 1
    it is possible if your variables can be combined into one. Sort of like a C++ multiplexer. If the possible values of the "supervariable" clearly dictate the states of the original two variables, then it is possible. examples: string concatenation, bitmasking, etc – im so confused Jan 04 '13 at 15:58

7 Answers7

9
#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 :)

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • 5
    This is really beautiful in a terrifying sort of way. – Stephen Canon Jan 04 '13 at 17:53
  • I'll be even more impressed if you abuse the preprocessor so that there can be a `:` after `CASE(a,b)`. – Stephen Canon Jan 04 '13 at 20:53
  • @StephenCanon sure :) `#define CASE(a, b) } else if ((a == _a) && (b == _b)) { _a != a ? 0` – David Ranieri Jan 04 '13 at 21:13
  • 1
    @DavidRF: that doesn't work if the first expression after the `:` is an assignment (i.e. `CASE(a,b): x = 2;` really doesn't parse the way you would like it to). (It also won't work nicely if `_a` happens to be a floating-point NaN). I think you need to create a dummy label for it to really work properly. Probably just `{ dummylabel ## __LINE__` or similar. – Stephen Canon Jan 04 '13 at 21:18
6

In general, the answer is "no": switch statements work with a single variable. However, in some cases you can do the conversion. For example, if you have two variables, a and b, where a can be 0, 1, or 2, and b that can be 0, 1, 2, or 3, you can do a switch like this:

switch (a*10+b) {
    case  0: break; // a == 0, b == 0
    case 10: break; // a == 1, b == 0
    case 20: break; // a == 2, b == 0
    case  1: break; // a == 0, b == 1
    case 11: break; // a == 1, b == 1
    case 21: break; // a == 2, b == 1
    case  2: break; // a == 0, b == 2
    case 12: break; // a == 1, b == 2
    case 22: break; // a == 2, b == 2
    case  3: break; // a == 0, b == 3
    case 13: break; // a == 1, b == 3
    case 23: break; // a == 2, b == 3
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2
#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;
    }
}
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
1

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;
 }
Don Cruickshank
  • 5,641
  • 6
  • 48
  • 48
0

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.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

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");
}
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
0

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.

bta
  • 43,959
  • 6
  • 69
  • 99