HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Another Rock Paper Scissors Lizard Spock implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scissorspaperspockrockanotherimplementationlizard

Problem

The Challenge

Create an implementation of "Rock - Paper - Scissors - Lizard - Spock".

The rules:


Scissors cuts paper, paper covers rock, rock crushes lizard, lizard poisons Spock, Spock smashes scissors, scissors decapitate lizard, lizard eats paper, paper disproves Spock, Spock vaporizes rock. And as it always has, rock crushes scissors. -- Dr. Sheldon Cooper

My approach

I wanted to make the game flexible and general. It should not be necessary to change much to create a "normal" Rock-Paper-Scissors implementation. It should also be possible to add elements such as Water balloon if you'd like. Technically, it should also be possible without too much effort to modify the elements at runtime (this is currently not supported in the below implementation, but there's not many changes needed to make it a reality).

Players. All players have a score that gets increased when they win. A player should have a method to return which item the player chooses, this implementation can vary (a human can write input, an AI can return something random, some other AIs should perhaps always choose SPOCK...)

Code

Because I am lazy, I have put all the classes/interfaces in the same file. Of course, all of them could be placed in their own files as public. The code is stand-alone, just copy it and paste it to your favorite IDE (Eclipse) and run it as a JUnit test case.

```
interface IItem {
/**
* To allow configuration "from both sides", use an int instead of a boolean.
* For example, if SCISSORS have -1 edge against ROCK, it will lose as long as ROCK doesn't have an edge below -1 against SCISSORS.
* This way, it is possible to configure both "beats" and "gets beaten by". It is also possible to return a randomized value here to allow for more complex game styles.
*/
int edge(IItem opponent);
}

abstract class ItemPlayer {
public abstract IItem chooseOne(IItem[] possibles);
private int score = 0;

public void wonAGame() {
score+

Solution

ItemPlayer is a really good idea. Keeping the logic and score centralized in an abstract class for the AI and Human player is a good design, but, you have not taken the idea far enough.

The abstract class should have a name field, and a constructor that takes the name:

abstract class ItemPlayer {
    private final String name;

    ItemPlayer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}


Using the toString() on the concrete classes to get the name is not a great option. Instead, for example, the AI class should be:

public static class AIInput extends ItemPlayer {

    AIInput() {
        super("AI");
    }

    ....
}


Similarly, the HumanInput can be changed..... but, with the Human input, I like how you've made it Closable.... but then, why didn't you use a try-with-resources structure in your main loop?

Finally, I like the use of the Enum for the valid moves (and I did something similar), but having the rules for the moves outside of the enum is cumbersome. using a static initializer block inside the enum class would solve that problem instead of having to have the setup() method call

Code Snippets

abstract class ItemPlayer {
    private final String name;

    ItemPlayer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
public static class AIInput extends ItemPlayer {

    AIInput() {
        super("AI");
    }

    ....
}

Context

StackExchange Code Review Q#36412, answer score: 12

Revisions (0)

No revisions yet.