I would start by defining classes RPSSystem and RPSObject. The code to construct the classic RPS-game would look like this:
RPSObject rock = new RPSObject("Rock");
RPSObject paper = new RPSObject("Paper");
RPSObject scissors = new RPSObject("Scissors");
RPSSystem classicRPS = new RPSSystem(rock, paper, scissors);
// new RPSSystem(Collection<RPSObject> objects) possible too
classicRPS.defineBeatsRule(rock, scissors);
classicRPS.defineBeatsRule(paper, rock);
classicRPS.defineBeatsRule(scissors, paper);
RPSSystem would have a method
int fight(RPSObject a, RPSObject b)
which would return -1 when a
wins, 1 when b
wins and 0 when the result is not defined. Internally RPSObjects could be stored in a list and beating rules could be stored in a matrix (columns and rows would match the indices of the objects in the list). If multiple instances of similar RPSObject should be allowed, the equals-method of RPSObject should be written accordingly.
Having a separate class for each object in the system seems a bit too complicated.
EDIT:
Complete classes:
package rpsgame;
public final class RPSObject {
private final String name;
public RPSObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString() {
return getName();
}
}
package rpsgame;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class RPSSystem {
private final List<RPSObject> objects;
private final int[][] beatsRules;
public static final int WINS = 1;
public static final int TIE = 0;
public static final int LOSES = -1;
public RPSSystem(RPSObject... objects) {
this.objects = Arrays.asList(objects.clone());
this.beatsRules = new int[objects.length][objects.length];
}
void defineBeatsRule(RPSObject winner, RPSObject loser) {
if (winner.equals(loser)) throw new IllegalArgumentException();
int winnerIndex = getObjectIndex(winner);
int loserIndex = getObjectIndex(loser);
beatsRules[winnerIndex][loserIndex] = WINS;
beatsRules[loserIndex][winnerIndex] = LOSES;
}
public int fight(RPSObject a, RPSObject b) {
int aIndex = getObjectIndex(a);
int bIndex = getObjectIndex(b);
return beatsRules[aIndex][bIndex];
}
public List<RPSObject> getObjects() {
return Collections.unmodifiableList(objects);
}
private int getObjectIndex(RPSObject o) {
int index = objects.indexOf(o);
if (index < 0) throw new IllegalArgumentException();
return index;
}
// test
public static void main(String[] args) {
RPSSystem classicRPS = buildClassicRPS();
List<RPSObject> objects = classicRPS.getObjects();
for (RPSObject a: objects) {
for (RPSObject b: objects) {
int result = classicRPS.fight(a, b);
switch (result) {
case RPSSystem.WINS:
System.out.println(a + " beats " + b);
break;
case RPSSystem.TIE:
System.out.println(a + " vs " + b + " is tied");
break;
case RPSSystem.LOSES:
System.out.println(a + " loses against " + b);
break;
}
}
}
}
private static RPSSystem buildClassicRPS() {
RPSObject rock = new RPSObject("Rock");
RPSObject paper = new RPSObject("Paper");
RPSObject scissors = new RPSObject("Scissors");
RPSSystem classicRPS = new RPSSystem(rock, paper, scissors);
classicRPS.defineBeatsRule(rock, scissors);
classicRPS.defineBeatsRule(paper, rock);
classicRPS.defineBeatsRule(scissors, paper);
return classicRPS;
}
}
Just add RPSSystem.EVERYONE_DIES
and defineEveryoneDiesRule(...)
and you're ready for
rps.add(atombomb);
rps.defineBeatsRule(atombomb, scissors);
rps.defineBeatsRule(atombomb, rock);
rps.defineBeatsRule(atombomb, paper);
rps.defineEveryoneDiesRule(atombomb, atombomb);