I'm a beginner trying to create a dice game according to the specification given below. This is an improved version of my program based on the feedback given by users on my original question. Again, rather than asking other people to correct my code, I would much prefer to be given hints or general principles as to how my code could be improved. I have been told that there is a hundred way to write a program, a thousand way to break it and a million way to improve it.
Please feel free to pick apart my code and give me any suggestions on areas in my program that could be improved, especially in areas such as code structure and logic.
Program Logic:
The Dice Throwing Game begins with a welcome message followed by a menu with the following options :
Option (1) asks players to enter their names. A player’s name must not be blank (or consists of only spaces and nothing else), but may contain spaces between the characters.
After the names are set up, the game asks for a maximum score. The default maximum score should be set to 200 points. Each player’s initial score is set to 0.
Option (2) simulates the “dice roll” operations for players. When this option is chosen, the computer generates 2 random numbers between 1-6 (ie. simulating a 6-sided dice), representing 2 dice rolls for each player. It then updates players' scores accordingly. The scoring rules for each "round" are as follows :
if the 2 dice rolls have the same value (ie. 1&1, 2&2, …, 6x6), the player scores 2 times the sum of that value (eg. 1&1 scores 4 points, 2&2 scores 8 points, etc) if the 2 dice rolls have different values, the player simply scores the sum of that value (eg. 1&4 scores 5 points, 5&2 scores 7 points, etc) if players reaches a score which is more than the pre-defined maximum, the game’s result is a Draw. note that players can reach over that score at the same time, since for each round, 2 dice rolls are performed for each player, before a winner is decided a player is considered a winner if he accumulates a score which is more than the pre-defined maximum, and the other player has not reached that score Option (3) shows the players current scores, including who is leading the game.
Option (4) displays some brief instructions regarding how to play the game.
Option (5) exits the whole program. All player statistics should be cleared.
Additional Notes :
The menu must be displayed repeatedly after each operation, until the user chooses Option (5). Inputs other than 1-5 should be rejected, with appropriate error messages printed.
If the user chooses Option (2)/(3), before a game has been set up (Option (1)), an appropriate error message should be printed, and the operation aborted.
Your program must deal with invalid values entered by the user in a sensible manner.
Game class:
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
public class Game {
List<Player> listOfPlayers = new ArrayList<>();
private Dice dice = new Dice();
private int scoreToWin = 200;
private void run() {
while (true) {
System.out.println("(1) Start a new game");
System.out.println("(2) Play one round");
System.out.println("(3) Who is leading now?");
System.out.println("(4) Display game help");
System.out.println("(5) Exit game");
System.out.println("Choose an option: ");
try {
Scanner sc = new Scanner(System.in);
int optionSelected = sc.nextInt();
while (optionSelected < 0 || 5 < optionSelected) {
System.out.println("Option entered invalid, please enter a number between 1 - 5");
optionSelected = sc.nextInt();
}
if (optionSelected == 5) {
System.out.println("Exiting...");
break;
}
this.selectOption(optionSelected);
} catch (InputMismatchException e) {
System.out.println("Invalid user input, please enter choose between option 1 - 5");
}
if (this.checkIfAnyoneHasWon()) {
System.out.println("Game ended");
break;
}
}
}
private void selectOption(int optionSelected) {
switch (optionSelected) {
case 1:
this.startNewGame();
break;
case 2:
this.playOneRound();
break;
case 3:
this.whoIsLeading();
break;
case 4:
this.displayGameInstruction();
break;
default:
break;
}
}
private void startNewGame() {
Scanner sc = new Scanner(System.in);
System.out.println("Would you like to create a player? Enter Y or N.");
String answer = sc.nextLine();
while (answer.equalsIgnoreCase("y")) {
System.out.println("Please enter the player's name.");
String playerName = sc.nextLine();
Player newPlayer = new Player(playerName);
listOfPlayers.add(newPlayer);
System.out.println("Would like to create another player? Enter Y or N.");
answer = sc.nextLine();
}
System.out.println("Please enter the upper score limit for the game.");
scoreToWin = sc.nextInt();
}
private void playOneRound() {
for (Player p : listOfPlayers) {
int currentRoundScore;
int firstResult = dice.roll();
int secondResult = dice.roll();
if (firstResult == secondResult) {
currentRoundScore = (firstResult + secondResult) * 2;
p.addToTotalScore(currentRoundScore);
System.out.format("%s rolled %d and %d, "
+ "and scored %d points(BONUS DOUBLE POINTS), "
+ "for a total of %d points.%n",
p.getName(), firstResult, secondResult,
currentRoundScore, p.getTotalScore());
} else {
currentRoundScore = (firstResult + secondResult);
p.addToTotalScore(currentRoundScore);
System.out.format("%s rolled %d and %d, "
+ "and scored %d points, "
+ "for a total of %d points.%n",
p.getName(), firstResult, secondResult,
currentRoundScore, p.getTotalScore());
}
}
}
private void whoIsLeading() {
List<Player> leaders = new ArrayList<>();
int highestScore = 0;
for (Player p : listOfPlayers) {
if (p.getTotalScore() > highestScore) {
leaders = new ArrayList<>();
leaders.add(p);
highestScore = p.getTotalScore();
} else if (p.getTotalScore() == highestScore) {
leaders.add(p);
}
}
for (Player p : leaders) {
System.out.format("%s is currently leading with "
+ "%d points.%n", p.getName(), p.getTotalScore());
}
}
private void displayGameInstruction() {
System.out.println("All players roll a dice twice per turn.");
System.out.println("If 2 dice rolls have the same value, the player scores 2 times the sum two dice rolls.");
System.out.println("If 2 dice rolls have different values, the player simply scores the sum of two dice rolls.");
System.out.println("For each player, result is incremented after each turn.");
System.out.println("First player to reach or exceed the maxScore wins the game");
}
private boolean checkIfAnyoneHasWon() {
List<Player> winners = new ArrayList<>();
listOfPlayers.stream().filter((p) -> (p.getTotalScore() >= scoreToWin)).forEach((p) -> {
winners.add(p);
});
winners.stream().forEach((p) -> {
System.out.printf("%s has reached the game limit of %d for a total "
+ "of %d points, %s has won the game!%n",
p.getName(), scoreToWin,
p.getTotalScore(), p.getName());
});
return !winners.isEmpty();
}
public static void main(String[] args) {
Game newGame = new Game();
System.out.println("Welcome to the Dice and roll game!");
newGame.run();
}
}
Player class:
public class Player {
private String name;
private int totalScore;
Player(String name){
this.name = name;
}
String getName(){
return name;
}
void setName(){
this.name = name;
}
void addToTotalScore(int scoreForCurrentRound){
totalScore += scoreForCurrentRound;
}
int getTotalScore(){
return totalScore;
}
}
Dice class:
import java.util.Random;
public class Dice {
private static final int NUMBER_OF_SIDES = 6;
Random r = new Random();
int roll(){
return r.nextInt(NUMBER_OF_SIDES) + 1;
}
}