Instructions
Requirements and Specifications
Source Code
DICE CUP
public class DiceCup {
/**
* Default number of dice
*/
public static final int DEFAULT_NUMBER = 5;
/**
* Number of dice in cup
*/
private int number;
/**
* Array, containing die objects
*/
private final Die[] dice;
/**
* Constructor, creating cup with default number of dice
*/
public DiceCup() {
this(DEFAULT_NUMBER);
}
/**
* Constructor, creating cup with given number of dice
* @param number of dice in cup to create
*/
public DiceCup(int number) {
this.number = number;
this.dice = new Die[number];
for (int i = 0; i<number; i++) {
this.dice[i] = new Die();
}
}
/**
* Method for rolling all dice in cup
*/
public void roll() {
roll(new boolean[number]);
}
/**
* Method for rolling selected dice in cup
* @param keep boolean array to select which dice to roll
*/
public void roll(boolean[] keep) {
for (int i = 0; i<number; i++) {
if (!keep[i]) {
dice[i].roll();
}
}
}
/**
* Method returning current dice values as int array
* @return dice value array
*/
public int[] show() {
int[] result = new int[number];
for (int i = 0; i<number; i++) {
result[i] = dice[i].read();
}
return result;
}
/**
* Overridden toString method
* @return string representation of dice cup
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder("Roll: ");
for (int i = 0; i<number; i++) {
builder.append(" ").append((i+1)).append(":[").append(dice[i].read()).append("]");
}
return builder.toString();
}
}
DIE
import java.util.Random;
public class Die {
/**
* Default number of sides
*/
public static final int DEFAULT_SIDES = 6;
/**
* Number of sides of this dice
*/
private final int sides;
/**
* Current value shown on die
*/
private int shows;
/**
* Constructor, creating die with default number of sides
*/
public Die() {
this(DEFAULT_SIDES);
}
/**
* Constructor, creating die with given number of sides
* @param sides number of sides of this dice
*/
public Die(int sides) {
this.sides = sides;
roll();
}
/**
* Method for making die roll
*/
public void roll() {
// choosing random value in range with random
Random random = new Random();
shows = random.nextInt(sides) + 1;
}
/**
* Method, returning current value shown by die
* @return current value
*/
public int read() {
return shows;
}
}
GAME
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
public class Game {
/**
* Scanner object to read user input
*/
private final Scanner scanner;
/**
* Number of players in game
*/
private final int numPlayers;
/**
* Array, containing player objects
*/
private final Player[] players;
/**
* Dice Cup, which is used for playing
*/
private final DiceCup diceCup;
/**
* Constructor, creating game instance for given number of player
* @param scanner to scan user input
* @param numPlayers number of players in game
*/
public Game(Scanner scanner, int numPlayers) {
this.scanner = scanner;
this.numPlayers = numPlayers;
this.players = new Player[numPlayers];
for (int i = 0; i < numPlayers; i++) {
players[i] = new Player(i + 1);
}
diceCup = new DiceCup();
}
/**
* Auxiliary method for generating string out of boolean keep array
* @param keep boolean array to generate string for
* @return string representation of boolean array
*/
private String generateKeepString(boolean[] keep) {
StringBuilder builder = new StringBuilder("Keep?:");
for (int i = 0; i < keep.length; i++) {
builder.append(" ").append((i + 1)).append(": ").append(keep[i] ? 'y' : 'n').append(" ");
}
builder.append(System.lineSeparator());
return builder.toString();
}
/**
* Auxiliary method for reading user int input
* @param prompt string prompt to ask user with
* @param min minimum allowed value
* @param max maximum allowed value
* @return valid user input
*/
private int getOption(String prompt, int min, int max) {
while (true) {
try {
// asking user
System.out.print(prompt + ": ");
// trying to parse input as int
int choice = Integer.parseInt(scanner.nextLine());
// if it's out of bounds, throwing an exception
if (choice < min || choice > max) {
throw new IllegalArgumentException();
}
// input is valid, returning choice
return choice;
} catch (Exception e) {
// exception was thrown - keep asking and showing error
System.out.println("Invalid input");
}
}
}
/**
* Main play method. Performs all game process
*/
public void play() {
// iterating over rounds
for (int round = 0; round <= 12; round++) {
// iterating over players
for (int turn = 0; turn < numPlayers; turn++) {
// showing current state
Player currPlayer = players[turn];
System.out.println(currPlayer.getName() + "'s turn!");
System.out.println();
System.out.println(currPlayer.getName() + " Scorecard");
System.out.println(currPlayer.getScoreSheet());
System.out.println();
System.out.println("Turn #" + (round + 1));
System.out.println("Roll #1");
diceCup.roll();
System.out.println(diceCup);
// asking user, which dice to keep
boolean[] keep = new boolean[DiceCup.DEFAULT_NUMBER];
for (int roll = 0; roll < 2; roll++) {
System.out.println(generateKeepString(keep));
System.out.println("Which die do you want to keep?");
int choice = getOption("Enter 1 - 5 to toggle that die or 0 to roll", 0, DiceCup.DEFAULT_NUMBER);
while (choice > 0) {
keep[choice-1] = !keep[choice-1];
System.out.println(generateKeepString(keep));
choice = getOption("Enter 1 - 5 to toggle that die or 0 to roll", 0, DiceCup.DEFAULT_NUMBER);
}
System.out.println("Roll #" + (roll + 2));
diceCup.roll(keep);
System.out.println(diceCup);
}
System.out.println("Scoring " + currPlayer.getName() + " turn " + (round + 1));
System.out.println();
System.out.println(diceCup);
System.out.println();
System.out.println("Where would you like to score this roll?");
System.out.println(currPlayer.getScoreSheet());
while (!currPlayer.getScoreSheet().evaluate(getOption("Choose 1 - 13 to score your roll", 1, 13), diceCup.show())) {
System.out.println("This option is already scored");
System.out.println("Where would you like to score this roll?");
System.out.println(currPlayer.getScoreSheet());
}
System.out.println();
}
}
// finding max score
int maxScore = Arrays.stream(players).mapToInt(Player::getTotal).max().orElse(0);
// searching for players with max score
List<Player> winners = Arrays.stream(players).filter(p -> p.getTotal() == maxScore).collect(Collectors.toList());
// printing winners
System.out.println("Winner(s):");
for (Player winner : winners) {
System.out.println(winner.getName());
}
System.out.println("with score " + maxScore);
}
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
// asking for number of players
System.out.print("Please, enter number of players: ");
int players = Integer.parseInt(scanner.nextLine());
System.out.println();
// starting game
Game game = new Game(scanner, players);
game.play();
}
}
}
PLAYER
public class Player {
/**
* Player number
*/
private final int number;
/**
* Player score sheet
*/
private final ScoreSheet scoreSheet;
/**
* Constructor, creating player with given number
* @param number for player to create
*/
public Player(int number) {
this.number = number;
scoreSheet = new ScoreSheet();
}
/**
* Method, returning player name
* @return player name
*/
public String getName() {
return "Player #" + number;
}
/**
* Method for getting current player total score
* @return player total score
*/
public int getTotal() {
return scoreSheet.getTotal();
}
/**
* Getter method for scoreSheet field
* @return player score sheet
*/
public ScoreSheet getScoreSheet() {
return scoreSheet;
}
}
SCORESHEET
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class ScoreSheet {
/**
* Array of combination names
*/
private final static String[] NAMES = new String[]{"Ones", "Twos", "Threes", "Fours", "Fives", "Sixes",
"Triple", "Quad", "Full House", "Small Straight", "Large Straight", "Yahtzee", "Chance"};
/**
* Array of points scored
*/
private final int[] scores;
/**
* Constructor, creating empty scoresheet
*/
public ScoreSheet() {
scores = new int[13];
for (int i = 0; i<13; i++) {
scores[i] = -1;
}
}
/**
* Method, performing evaluation of current dice with given combination option
* @param choice chosen combination
* @param dice dice score array
* @return true, if given option was not evaluated yet, false - otherwise
*/
public boolean evaluate(int choice, int[] dice) {
int option = choice - 1;
// checking, if option is valid
if (scores[option] >= 0) {
return false;
}
// counting entries of each possible score
Map<Integer, Integer> counters = new HashMap<>();
for (int die : dice) {
counters.merge(die, 1, Integer::sum);
}
switch (option) {
// evaluating simple options
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
scores[option] = (option + 1) * counters.get(option + 1);
break;
case 6:
// there must be at least 1 value with count at least 3
scores[option] = (counters.values().stream().anyMatch(i -> i >= 3)) ? Arrays.stream(dice).sum() : 0;
break;
case 7:
// there must be at least 1 value with count at least 4
scores[option] = (counters.values().stream().anyMatch(i -> i >= 4)) ? Arrays.stream(dice).sum() : 0;
break;
case 8:
// looking for two values: one with count 2, another with count 3
boolean fullHouseFound = false;
for (int i = 1; i<=Die.DEFAULT_SIDES; i++) {
if (counters.getOrDefault(i, 0) != 2) {
continue;
}
for (int j = 1; j<=Die.DEFAULT_SIDES; j++) {
if (counters.getOrDefault(i, 0) == 3) {
fullHouseFound = true;
break;
}
}
if (fullHouseFound) {
break;
}
}
scores[option] = fullHouseFound ? 25 : 0;
break;
case 9:
// trying to find large straight, starting from 1,2,3
boolean smallStraightFound = false;
for (int i = 1; i<=Die.DEFAULT_SIDES - 3; i++) {
boolean found = true;
for (int j = 0; j<4; j++) {
if (!counters.containsKey(i+j)) {
found = false;
break;
}
}
if (found) {
smallStraightFound = true;
break;
}
}
scores[option] = smallStraightFound ? 30 : 0;
break;
case 10:
// trying to find large straight, starting from 1,2
boolean largeStraightFound = false;
for (int i = 1; i<=Die.DEFAULT_SIDES - 4; i++) {
boolean found = true;
for (int j = 0; j<DiceCup.DEFAULT_NUMBER; j++) {
if (!counters.containsKey(i+j)) {
found = false;
break;
}
}
if (found) {
largeStraightFound = true;
break;
}
}
scores[option] = largeStraightFound ? 40 : 0;
break;
case 11:
// there must be at least 1 value with count at least 5
scores[option] = (counters.values().stream().anyMatch(i -> i >= 5)) ? 50 : 0;
break;
case 12:
// just summing up all values
scores[option] = Arrays.stream(dice).sum();
break;
default:
throw new IllegalArgumentException();
}
return true;
}
/**
* Method for getting total score from score sheet
* @return total points scored
*/
public int getTotal() {
int total = 0;
for (int i = 0; i<13; i++) {
if (scores[i] >= 0) {
total += scores[i];
}
}
return total;
}
/**
* Overridden toString method
* @return string representation of score sheet
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i<13; i++) {
builder.append(String.format("%-23s", NAMES[i] + ":")).append("[");
if (scores[i] >= 0) {
builder.append(String.format("%2d", scores[i]));
}
else {
builder.append("--");
}
builder.append("]").append(System.lineSeparator());
}
builder.append("---------------------------").append(System.lineSeparator());
builder.append(String.format("%-23s%3d", "Total:", getTotal()));
return builder.toString();
}
}