If/Else Statements in Swtich Statements?

Started by
14 comments, last by rip-off 12 years, 11 months ago
Danny02's code is clever in that it works almost entirely on the integer used to represent a move. The move names are stored in a table that can be quickly consulted by the move's numeric code. The winner is determined by some tricksy manipulation of the numeric representation.

My main criticism of such an approach is that it invests a lot into the "magic numbers" being used. For a known game like Rock, Paper, Scissor this is fine, but if you were writing a bigger game this approach is brittle, any changes to the number of moves can result in the code breaking in subtle ways without any compilation errors.

I would also comment on your code OP, you are comparing objects using "==". This is not a good idea as this compares the objects "identity" rather than their value. Strings are objects, you should use equals() method, like: computerMove.equals("Rock")

I think the program is best written using an enumeration representing all available moves:

public class RockPaperScissor {

public enum Move {
Rock, Paper, Scissor
}

private static final Move [] Moves = Move.values();

public static Move getPlayerMove() {
int index;
do {
TextIO.putln("What's your move?");
TextIO.putln();
for(int i = 0 ; i < Moves.length ; ++i) {
TextIO.putln(i + " " + Moves);
}
index = TextIO.getlnInt();
}
while(index < 0 || index > Moves.length);

return Moves[index];
}

private static Move getComputerMove() {
int index = (int)(Moves.length * Math.random());
return Moves[index];
}

private static boolean beats(Move player, Move computer) {
switch(player) {
case Rock: return computer == Move.Scissor;
case Paper: return computer == Move.Rock;
case Scissor: return computer == Move.Paper;
}

// Hush little compiler, don't you cry
throw new IllegalArgumentException("Unknown player move: " + player);
}

public static void main(String[] args) {
Move player = getPlayerMove();
Move computer = getComputerMove();

TextIO.putln("Computer chose: " + computer.toString());
if(player == computer) {
TextIO.putln("Tie!");
} else {
boolean win = beats(player, computer);
if(win) {
TextIO.putln(player + " beats " + computer);
TextIO.putln("You win!");
} else {
TextIO.putln(computer + " beats " + player);
TextIO.putln("Sorry. You lose.");
}
}
}
}

If you wanted to add an additional moves, to make rock-paper-scissor-bazooka or whatever, there would be a lot less work to do. Also, I believe the code is much clearer than the clever but hard to decipher solution presented earlier. I also like when a program is split up into lots of small, east to understand functions.
Advertisement
Excellent, rip-off! I can understand most of your code, but there are a still few parts that look new to me. The book that I'm reading now is just getting into exceptions and 'try..catch'. Haven't seen anything on 'throw new' yet, but I'm sure I will. Also, thank you for informing me of the difference between the "==" operator and 'equals()' method. I'll certainly consider that for future application. Like I said earlier though, this was the first program I'd written from scratch to suit my desires and I thought it turned out wonderfully, considering I've only been really reading heavily for about a week now. I'm still proud of it. :P I've finally stepped over that boundary of writing a functional (however arbitrary it may be) and interactive program. For the first time since I started reading, I feel like I might actually have a shot at this once I have some experience behind me.




Thank you both for you contributions! Everyone here has helped immensely and I greatly appreciate that. I'm glad I've joined the community.

For a first attempt your original code is quite good. The main weakness was the aforementioned equality bug. Other, minor points to consider are delaying variable declarations to where they are first initialised/used, and reducing the repetition of code for handling win/loss inside each "case" block.

Another thing is to have a clean, consistent code style. In particular the brace placement and indentation of your switch statement is inconsistent.

There are two common styles:

control statement {
// Statments indented one "logical unit" here
}

// and

control statement
{
// Statments indented one "logical unit" here
}

Pick one you like the look of and go with it.

Some code styles allow for single line control blocks to omit the braces. However, most people believe this is a poor idea as you can all too easily add a second line without remembering to put the braces in. I would recommend adopting a style that always using braces around any control block.
Thank you! That actually means a lot. I'll certainly keep your comments in mind. I didn't even think of holding off on declaring variables until it came time to use them. When I first chalked it up in pseudocode, I wrote through the entire function to itemize the variables and types I would need and carelessly declared them at the beginning of the code.

Yeah, I noticed the inconsistency yesterday upon completion and went back to fix it. I come from a background in HTML, CSS, and some Javascript and a little experience in PHP, so I'm not sure why I didn't do it from the beginning. Haste, I suppose.

I plan on returning to this particular project in the future to compare how I do with a bit more familiarity with Java.

some thoughts, I thought about using an enum but for this small program there weren't really a benefit for it(also I tried to write it as small as possible :-) ). Also I didn't wanted to confuse Adderly cause enums are a bit complicated to understand especially in Java.


Of course if u want to extend the choices I probably have done it with an enum, extending it even so that each enum value has an EnumSet against which enum it wins.

On thing more, if I wanted to to it right. I would probably use States for the game(decide pick, want t play again?, enter name for highscore etc.).

@rip-off why do u throw an exception^^
I know, the throw is unreachable but it just don't look right. I think in Java it is also a good habit to only have 1 return in a method(the compiler can optimize better, but who cares :-) )


boolean wins = false;

switch(player) {
case Rock: wins = computer == Move.Scissor;
case Paper: wins = computer == Move.Rock;
case Scissor: wins = computer == Move.Paper;
}
return wins;






some thoughts, I thought about using an enum but for this small program there weren't really a benefit for it(also I tried to write it as small as possible :-) ). Also I didn't wanted to confuse Adderly cause enums are a bit complicated to understand especially in Java.
[/quote]
I don't think enums are particularly confusing. They have a few unusual properties, but they are mostly intuitive. I think they are less confusing than magic numbers.


why do u throw an exception^^
[/quote]
No particular reason, but I don't think it makes sense to continue processing in the case where the Move is not catered for. For example, if such a function was used by AI logic it could end up in an infinite loop (i.e. a general "is move A better than move B").


I think in Java it is also a good habit to only have 1 return in a method

boolean wins = false;

switch(player) {
case Rock: wins = computer == Move.Scissor;
case Paper: wins = computer == Move.Rock;
case Scissor: wins = computer == Move.Paper;
}
return wins;

[/quote]
I think this is limiting. I think early returns are a great way of getting edge cases out of the way quickly. Your code now contains a bug: there are no break statements between the cases, resulting in fall though.


(the compiler can optimize better, but who cares :-) )
[/quote]
I don't believe this is the case. Do you have any evidence for this assertion?

This topic is closed to new replies.

Advertisement