I was taken with tucuxi's version, but wanted to get more data-driven, with tables to represent combinations of plays, and their outcomes.
To take it a stage further, I included the Lizard and Spock ;-)
From the point of view of reviewing the original code, I dislike complex multi-part "if" statements, and will look for clearer ways to represent the logic. In this case, the set of rules can be encapsulated as data (thanks to Roland for suggesting the rule() method), and, for me, that is a preferable approach. Expressing Rock,Paper,Scissors,Lizard,Spock in the original's style would be very ugly...
package com.acme.rps;
import java.util.HashMap;
import java.util.Map;
/**
* OOP approach to Rock, Paper, Scissors, Lizard, Spock
*/
public class RockPaperScissors {
private static enum Outcome {
WIN, LOSE, DRAW;
}
private static class Result {
private Outcome outcome;
private String winDescription;
Result(Outcome outcome, String winDescription) {
this.outcome = outcome;
this.winDescription = winDescription;
}
Outcome getOutcome() {
return outcome;
}
String getWinDescription() {
return winDescription;
}
}
private static enum Play {
/* The five "Plays" */
ROCK, PAPER, SCISSORS, LIZARD, SPOCK;
/*
* For the current play,
* the plays we can defeat and how we defeat them
*/
Map<Play /*defeatablePlay*/, String /*how*/> winDescriptions = new HashMap<>();
Result resultAgainst(Play opponentsPlay) {
if (opponentsPlay == this) { // enums can be compared with object equality
return new Result(Outcome.DRAW, null);
}
// Can we defeat them?
String winDescription = winDescriptions.get(opponentsPlay);
if (winDescription != null) {
return new Result(Outcome.WIN, winDescription);
}
// If not, then they must be able to defeat us
winDescription = opponentsPlay.winDescriptions.get(this);
return new Result(Outcome.LOSE, winDescription);
}
/**
* A nice way to express one of the rules
* @param winningPlay
* @param winDescription
* @param losingPlay
*/
static void rule(Play winningPlay, String winDescription, Play losingPlay) {
winningPlay.winDescriptions.put(losingPlay, winDescription);
}
static {
rule(ROCK, "crushes", SCISSORS);
rule(ROCK, "crushes", LIZARD);
rule(PAPER, "covers", ROCK);
rule(PAPER, "disproves", SPOCK);
rule(SCISSORS, "cuts", PAPER);
rule(SCISSORS, "decapitates", LIZARD);
rule(LIZARD, "eats", PAPER);
rule(LIZARD, "poisons", SPOCK);
rule(SPOCK, "smashes", SCISSORS);
rule(SPOCK, "vaporizes", ROCK);
}
}
/**
* Show all possible plays and their results
* @param args ignored
*/
public static void main(String[] args) {
for (Play yourPlay : Play.values()) {
for (Play opponentPlay : Play.values()) {
System.out.format("You play %s, opponent plays %s, you ", yourPlay.name(), opponentPlay.name());
Result result = yourPlay.resultAgainst(opponentPlay);
switch (result.getOutcome()) {
case DRAW :
System.out.format("DRAW%n");
break;
case LOSE :
System.out.format("LOSE (%s %s %s)%n", opponentPlay.name(), result.getWinDescription(), yourPlay.name());
break;
case WIN :
System.out.format("WIN (%s %s %s)%n", yourPlay.name(), result.getWinDescription(), opponentPlay.name());
break;
default :
break;
}
}
System.out.println();
}
}
}