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:
#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 :)
#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;
}
}
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");
}
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.
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.
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;
}