2
\$\begingroup\$
  • What can make this code better?
  • And how could I improve this code?
  • Oh and what I would love is if someone has a project that is not that challenging but I could learn a lot from it :)

 

import java.util.Scanner;

public class RockPaperScissors {
    final static int ROCK = 1;
    final static int PAPER = 2;
    final static int SCISSORS = 3;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("Start By Entering A number");
        int human = input.nextInt();
        System.out.println("ROCK IS 1 :: PAPER IS 2 :: SCISSORS 3");
        int computerScore = 0, humanScore = 0, computer;
        while (human != -1) {
            human = input.nextInt();
            computer = (int) (Math.random() * 3 + 1);
            String h = human == 1 ? "ROCK" : human == 2 ? "PAPER" : "SCISSORS";
            String c = computer == 1 ? "ROCK" : computer == 2 ? "PAPER" : "SCISSORS";
            if ((human == ROCK && computer == SCISSORS) || (human == PAPER && computer == ROCK) || (human == SCISSORS && computer == PAPER)) {
                humanScore++;
                System.out.println("Human Won : " + humanScore);
                System.out.println("Human Chose " + h + " and Computer Chose " + c);
            } else if ((computer == ROCK && human == SCISSORS) || (computer == PAPER && human == ROCK) || (computer == SCISSORS && human == PAPER)) {
                computerScore++;
                System.out.println("Computer Won : " + computerScore);
                System.out.println("Human Chose " + h + " and Computer Chose " + c);
            } else if (human == computer) {
                System.out.println("HAH YOU BOTH THINK THE SAME! ");
                System.out.println("DRAW!");
            } else {
                System.out.println("Something Went Wrong Try Again:( ");
            }
        }
        System.out.println("\n\nThe Scores Are *DRUM NOISES* ");
        for (int i = 0; i < 4; i++) {
            System.out.println("------------------------------");
        }
        System.out.println("Human score : " + humanScore);
        System.out.println("Computer score : " + computerScore);
        if (humanScore > computerScore) {
            System.out.println("Human Race Is saved! We Won!");
        } else if (computerScore > humanScore) {
            System.out.println("Sadly We Lost. Better Luck Next Time:)");
        } else {
            System.out.println("Scores are Tied");
        }
    }
}
\$\endgroup\$
1

4 Answers 4

5
\$\begingroup\$

This is a reasonable first attempt but there are many ways to make it better:

public class RockPaperScissors {
    final static int ROCK = 1;
    final static int PAPER = 2;
    final static int SCISSORS = 3;
  • Consider using an enumerated type to hold related constants.

    System.out.println("Start By Entering A number");
    
  • Your capitalization is not standard English.

  • Tell the user how to quit.

    int human = input.nextInt();
    System.out.println("ROCK IS 1 :: PAPER IS 2 :: SCISSORS 3");
    
  • Put the explanation before fetching input!

  • Why is there no "is" for the scissors case?

    int computerScore = 0, humanScore = 0, computer;
    while (human != -1) {
    
  • Consider refactoring the main method so that it more clearly reflects what is happening, and extracting state to an object. I'd prefer to see your main look like this:


public static void main(String[] args) {
    initialize();
    Game g = new Game();
    g.printStartingText();
    while(!g.finished())
      g.playRound();
    g.printEndText();
}

Can you structure your program like that? It will be more clear if you do.

        String h = human == 1 ? "ROCK" : human == 2 ? "PAPER" : "SCISSORS";
        String c = computer == 1 ? "ROCK" : computer == 2 ? "PAPER" : "SCISSORS";
  • You've replicated some code here; it would be better to make a map from integer to the enumerated value and do two lookups in the map here.

        if ((human == ROCK && computer == SCISSORS) || (human == PAPER && computer == ROCK) || (human == SCISSORS && computer == PAPER)) {
    
  • Instead of doing this work twice, write a method that returns PLAYER_1, PLAYER_2 or TIE:

        Winner w = getWinner(human, computer);
    

That will let you simplify the logic that follows, and it will be easier to read.

            System.out.println("Something Went Wrong Try Again:( ");
  • This should never happen. A better choice would be to assert that the condition is impossible.

        System.out.println("Human Race Is saved! We Won!");
    

Why are the humans "we"? The message is being produced by a computer! It should be "The human race is saved; you won and we computers lost." :)

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Nice review, except for the snake_case. Have you been away from Java and C# for a while? Or maybe there is a new trend that I missed … ;) \$\endgroup\$ Commented Dec 4, 2019 at 23:39
  • 3
    \$\begingroup\$ @RolandIllig: I have spent the last couple years programming in C#, Java, Scala, Python and OCAML and I am now thoroughly confused as to what the right conventions are. :) \$\endgroup\$ Commented Dec 4, 2019 at 23:48
  • 2
    \$\begingroup\$ Awesome!!!I should apply objects to my game as you said.I know basic so far,arrays,loops,methods,String and chars.I should as you said start Implementing more OOP into my Programming.PS Sorry for my English its not my native language \$\endgroup\$ Commented Dec 5, 2019 at 18:37
  • 2
    \$\begingroup\$ @IslamŠakrak: Your English is very good! But you might want to find a native speaker to do a quick check for oddities in punctuation or spelling. English is a bizarre language with crazy rules. \$\endgroup\$ Commented Dec 5, 2019 at 18:40
3
\$\begingroup\$

You should split your code up into methods. Methods generally improve code readability, increase robustness, and allow for faster development time.

Try to split the code into methods based on behaviour. So for example, you may have a method to handle user input, a method to generate the computer's response (rock, paper or scissors), a method to display the scores, and a method to find the winner.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ The advice you give is good, but it may not be the right level of concreteness for a beginner. Imagine you were in the state of having written Rock Paper Scissors and being proud of your first program. What could you possibly get out of this code review? \$\endgroup\$ Commented Dec 4, 2019 at 23:42
  • 2
    \$\begingroup\$ Thank You bro I will try to apply methods to my code ASAP!:D \$\endgroup\$ Commented Dec 5, 2019 at 18:38
3
\$\begingroup\$
String h = human == 1 ? "ROCK" : human == 2 ? "PAPER" : "SCISSORS";
String c = computer == 1 ? "ROCK" : computer == 2 ? "PAPER" : "SCISSORS";

This line is duplicated and can be converted into a method.

System.out.println("Computer Won : " + computerScore);
System.out.println("Human Chose " + h + " and Computer Chose " + c);

and

System.out.println("Human Won : " + humanScore);
System.out.println("Human Chose " + h + " and Computer Chose " + c);

have very similar logic, and can be refactored into another method where the differing strings can be substituted.

((computer == ROCK && human == SCISSORS) || (computer == PAPER && human == ROCK) || (computer == SCISSORS && human == PAPER))

This comparison check is duplicated twice, and could be refactored into another method.

Each player has three properties: a name, score, and current move and needs to know if another move beats theirs. This can be converted into a Player class and the beats(x, y) comparison can be done there so that human.beats(computer) can be run. This makes it easier to read as there is more English.

for (int i = 0; i < 4; i++) {
    System.out.println("------------------------------");
}

This loop can be replaced with a .repeat(n) invocation, which duplicates the string four times.

while (human != -1) {

This could be converted into a while true loop and then this condition can be specified as if (human == -1) break which simplifies the control flow.

ROCK IS 1 :: PAPER IS 2 :: SCISSORS 3

It is unclear that the user has to enter in -1 to end the program. Perhaps the message could be added here.

Applying these suggestions, I get the following code:

package com.company;

import java.util.Scanner;

public class RockPaperScissors {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("Start By Entering A number");
        Player human = new Player("Human");
        Player computer = new Player("Computer");
        human.move = input.nextInt();
        System.out.println("ROCK IS 1 :: PAPER IS 2 :: SCISSORS 3");

        while (true) {
            if (human.move == -1) break;
            human.move = input.nextInt();
            makeComputerMove(computer);
            if (human.beats(computer)) {
                processWinner(human, computer);
            } else if (computer.beats(human)) {
                processWinner(computer, human);
            } else {
                System.out.println("HAH YOU BOTH THINK THE SAME! ");
                System.out.println("DRAW!");
            }
        }
        printFinalWinner(human, computer);
    }

    private static void makeComputerMove(Player computer) {
        computer.move = (int) (Math.random() * 3 + 1);
    }

    /**
     * Prints the final winner to the console with the scores
     * @param human The human player
     * @param computer The computer player
     */
    private static void printFinalWinner(Player human, Player computer) {
        System.out.println("\n\nThe Scores Are *DRUM NOISES* ");
        System.out.println("------------------------------\n".repeat(4));
        System.out.println("Human score : " + human.getScore());
        System.out.println("Computer score : " + computer.getScore());
        if (human.getScore() > computer.getScore()) {
            System.out.println("Human Race Is saved! We Won!");
        } else if (computer.getScore() > human.getScore()) {
            System.out.println("Sadly We Lost. Better Luck Next Time:)");
        } else {
            System.out.println("Scores are Tied");
        }
    }

    /**
     * Increments the score of the winner and prints the summary
     * @param winner The winning player
     * @param loser The player who lost
     */
    private static void processWinner(Player winner, Player loser) {
        winner.incrementScore();
        System.out.printf("%s Chose %s and %s Chose %s%n", winner.name, winner.moveString(), loser.name, loser.moveString());
    }
}

/**
 * Holds information about the player such as score, name, and move
 */
class Player {
    final static int ROCK = 1;
    final static int PAPER = 2;
    final static int SCISSORS = 3;
    String name;
    int move;
    private int score;

    public int getScore() {
        return this.score;
    }

    public void incrementScore() {
        this.score++;
    }

    public Player(String name) {
        this.name = name;
    }

    /**
     * Checks if the move of another player beats the current player
     * @param another The other player
     * @return Whether the other player's move beats this player's
     */
    public boolean beats(Player another) {
        return (this.move == ROCK && another.move == SCISSORS
                || (this.move == PAPER && another.move == ROCK)
                || (this.move == SCISSORS && another.move == PAPER));
    }

    /**
     * The move integer into a string such as "ROCK", "PAPER", or "SCISSORS"
     * @return The string interpretation of the move
     */
    public String moveString() {
        return this.move == 1 ? "ROCK" : this.move == 2 ? "PAPER" : "SCISSORS";
    }
}
```
\$\endgroup\$
0
1
\$\begingroup\$

I like putting those moves into enums. This is quite common so I've found nice solution already. This will make your checking for who won a lot nicer and readable: https://codereview.stackexchange.com/a/90552/214636

Also I feel like there definitely should be some thread sleeps after drumroll to add some more tension! Ex:

    for (int i = 0; i < 4; i++) {
        System.out.println("------------------------------");
        Thread.sleep(500);
    }

This will also require to add throws Exception (or InterruptedException) to main method signature.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.