Final documentation updates and additions

This commit is contained in:
Arne Keller 2020-03-24 01:08:10 +01:00
parent 6333f3d6a5
commit 5e6366d0c0
21 changed files with 193 additions and 109 deletions

View File

@ -7,6 +7,7 @@ import edu.kit.informatik.cardgame.ui.CommandLine;
*
* @author Arne Keller
* @version 1.0
* @see CommandLine
*/
public final class Main {
/**

View File

@ -12,19 +12,19 @@ import java.util.Optional;
*/
public enum Card implements RequireDice {
/**
* Wood. Basic resource.
* Wood. Basic resource used to build many {@link Item items}.
*/
WOOD,
/**
* Metal. Basic resource.
* Metal. Fundamental resource for advanced buildings.
*/
METAL,
/**
* Plastic. Basic resource.
* Plastic. Synthetic resource required to construct some items.
*/
PLASTIC,
/**
* Spider. Deadly animal.
* Spider. Will attack the player.
*/
SPIDER,
/**
@ -36,9 +36,10 @@ public enum Card implements RequireDice {
*/
TIGER,
/**
* Thunderstorm. Lifts up items and takes them away. Also blows out the fireplace.
* Thunderstorm. Lifts up the player's items and takes them away. Also blows out the fireplace.
*/
THUNDERSTORM;
// note: new items *require* changes in category, parse and toString
/**
* Return value indicating that the player successfully fought against an animal.
@ -56,7 +57,14 @@ public enum Card implements RequireDice {
public static final String LOSE = "lose";
/**
* Activate this card. Behaviour depends on the {@link #category category} of this card.
* Activate this card. Behaviour depends on the {@link #category category} of this card:
* <ul>
* <li>{@link CardCategory#RESOURCE Resource} cards are {@link CardGame#givePlayerCard added}
* to the player's inventory</li>
* <li>{@link CardCategory#ANIMAL Animal} cards {@link CardGame#waitForDiceRoll start} an encounter</li>
* <li>{@link CardCategory#CATASTROPHE Catastrophe} cards clear the player's resources
* and remove their fireplace</li>
* </ul>
*
* @param game game to use card on
*/
@ -66,11 +74,11 @@ public enum Card implements RequireDice {
game.givePlayerCard(this);
break;
case ANIMAL: // animal cards trigger an encounter
game.startDiceRoll(this);
game.waitForDiceRoll(this);
break;
case CATASTROPHE:
game.deletePlayerResources();
game.deletePlayerItem(Item.FIREPLACE);
game.clearResources();
game.deleteItem(Item.FIREPLACE);
break;
default: // implement behaviour of new card types here
throw new IllegalStateException("encountered unknown card category!");
@ -79,16 +87,19 @@ public enum Card implements RequireDice {
@Override
public Optional<String> activate(CardGame game, int size, int roll) {
// throw if this card does not require a dice roll
if (!this.diceSizeNeeded().isPresent()) {
throw new IllegalStateException("can not process dice roll");
} else if (this.diceSizeNeeded().get() != size || roll > size || roll < 1) {
// unexpected dice size or impossible roll
return Optional.empty();
}
// add the player's combat bonus against animals
if (roll + game.getFightingBonus() >= this.minimumDiceRollNeeded().get()) {
return Optional.of(SURVIVED);
} else {
game.deletePlayerResources();
// animal somehow managed to steal the entirety of the player's resources
game.clearResources();
return Optional.of(LOSE);
}
}
@ -115,6 +126,11 @@ public enum Card implements RequireDice {
}
}
/**
* Dice size needed to {@link #activate(CardGame, int, int) activate} this card.
*
* @return expected dice size, empty if not requiring dice roll
*/
private Optional<Integer> diceSizeNeeded() {
switch (this) {
case SPIDER:
@ -128,6 +144,11 @@ public enum Card implements RequireDice {
}
}
/**
* Minimum dice roll needed to {@link #activate(CardGame, int, int) activate} this card.
*
* @return minimum dice roll for successful activation, empty if not requiring dice roll
*/
private Optional<Integer> minimumDiceRollNeeded() {
switch (this) {
case SPIDER:
@ -142,9 +163,10 @@ public enum Card implements RequireDice {
}
/**
* Get the number of cards of this type needed to {@link CardGame#start start} a game.
* Get the exact number of cards of this type needed to initialize a card stack.
*
* @return amount of cards needed in a card deck
* @see CardStack#CardStack
*/
public int requiredAmount() {
switch (this) {
@ -165,9 +187,9 @@ public enum Card implements RequireDice {
/**
* Parse a single word and return the card represented by the input.
* Fun fact: Card.parse(card.toString()) == card is true for all cards.
* This method is the inverse of {@link #toString}.
*
* @param input text
* @param input card description (usually one word)
* @return card object (null if input invalid)
*/
public static Card parse(String input) {

View File

@ -5,6 +5,7 @@ package edu.kit.informatik.cardgame.model;
*
* @author Arne Keller
* @version 1.0
* @see Card#activate(CardGame)
*/
public enum CardCategory {
/**
@ -13,6 +14,7 @@ public enum CardCategory {
* @see Card#WOOD
* @see Card#METAL
* @see Card#PLASTIC
* @see Item#resourcesNeeded
*/
RESOURCE,
/**
@ -21,12 +23,14 @@ public enum CardCategory {
* @see Card#SNAKE
* @see Card#SPIDER
* @see Card#TIGER
* @see Card#activate(CardGame, int, int)
*/
ANIMAL,
/**
* Catastrophic card, can not harm player.
* Catastrophic card causing clearance of collected cards and fireplace.
*
* @see Card#THUNDERSTORM
* @see CardGame#clearResources
*/
CATASTROPHE
}

View File

@ -10,31 +10,27 @@ import java.util.stream.Collectors;
/**
* Simple card game. Features:
* <ul>
* <li>100% deterministic (user tells game dice roll results)</li>
* <li>100% deterministic (user tells game results of dice rolls)</li>
* <li>64! different card stacks (including functionally equivalent stacks)</li>
* <li>8 buildable {@link Item} items</li>
* <li>8 buildable {@link Item item} items</li>
* <li>7 exciting {@link Card card} types</li>
* <li>3 dice needed</li>
* <li>4 challenging game phases: scavenge (draw and build), encounter (fight), endeavor (escape) and end</li>
* <li>3 dice needed (size 4, 6 and 8)</li>
* <li>2 common game endings ({@link Phase#LOST lost} and {@link Phase#WON win})</li>
* <li>1 player only</li>
* <li>0 skill required</li>
* </ul>
*
* @author Arne Keller
* @version 1.0
* @version 1.2
*/
public class CardGame {
/**
* Return value indicating success.
*
* @see #build(Item)
*/
public static final String OK = "OK";
/**
* Card stack used.
* Card stack used, null if game not yet started.
*/
private CardStack cardStack;
/**
* Inventory of the player, containing {@link Card resources} and {@link Item items}.
* Inventory of the player, containing {@link Card resources} and {@link Item items}, null if game not yet started.
*/
private Inventory inventory;
/**
@ -43,8 +39,11 @@ public class CardGame {
private Phase phase;
/**
* Object currently requiring dice roll, null if not awaiting dice roll.
*
* @see Card
* @see Item
*/
private RequireDice requireDice;
private RequireDice toActivateOnDiceRoll;
/**
* Start a new game with the specified stack of cards. First checks whether the specified stack is correctly
@ -52,7 +51,7 @@ public class CardGame {
*
* @param cardStack stack of cards to use, where the first element is the first to take
* @throws LogicException if card stack has wrong distribution of cards
* @return whether a game was started
* @return whether a new game was started
*/
public boolean start(Collection<Card> cardStack) throws LogicException {
if (gameActive()) {
@ -99,8 +98,8 @@ public class CardGame {
*
* @param requireDice something that requires a dice roll
*/
public void startDiceRoll(RequireDice requireDice) {
this.requireDice = requireDice;
public void waitForDiceRoll(RequireDice requireDice) {
this.toActivateOnDiceRoll = requireDice;
phase = Phase.AWAITING_DICE_ROLL;
}
@ -109,7 +108,7 @@ public class CardGame {
*
* @see Inventory#clearResources
*/
public void deletePlayerResources() {
public void clearResources() {
this.inventory.clearResources();
}
@ -119,7 +118,7 @@ public class CardGame {
* @param item item to remove
* @see Inventory#removeItem
*/
public void deletePlayerItem(Item item) {
public void deleteItem(Item item) {
this.inventory.removeItem(item);
}
@ -136,18 +135,18 @@ public class CardGame {
throw new LogicException("not expecting dice roll");
}
// compute the result of the dice roll
final Optional<String> result = requireDice.activate(this, size, roll);
if (result.isPresent()) {
final Optional<String> result = toActivateOnDiceRoll.activate(this, size, roll);
if (result.isPresent()) { // valid dice roll
// leave encounter/endeavor phase (only if player didn't win)
if (phase == Phase.AWAITING_DICE_ROLL) {
phase = Phase.SCAVENGE;
}
// no longer waiting
requireDice = null;
toActivateOnDiceRoll = null;
return result.get();
} else {
// invalid user input
throw new LogicException("invalid dice input");
throw new LogicException("invalid roll dice input (wrong size or impossible roll)");
}
}
@ -159,15 +158,15 @@ public class CardGame {
}
/**
* Attempt to build the specified item.
* Attempt to build the specified item. Will automatically {@link Item#activate(CardGame) activate} the item.
*
* @param item item to build
* @return building result (see {@link Item#activate(CardGame)}), or null if item can not be built
* @throws LogicException if in wrong phase or item already built
* @return build result
* @throws LogicException if in wrong phase, item already built or missing resources/items
*/
public String build(Item item) throws LogicException {
if (item == null) {
throw new LogicException("can not build null item");
throw new IllegalArgumentException("can not build null item");
} else if (phase != Phase.SCAVENGE) {
throw new LogicException("can only build in scavenge phase");
} else if (inventory.contains(item)) {
@ -175,7 +174,8 @@ public class CardGame {
} else {
if (!inventory.build(item)) {
throw new LogicException("can not build item: missing resources/items");
}
} // else: successfully built and added to the inventory
// make sure to activate the item
return item.activate(this);
}
}
@ -185,16 +185,21 @@ public class CardGame {
*
* @return whether the game was ever started
*/
private boolean gameStarted() {
public boolean gameStarted() {
return phase != null;
}
/**
* Check whether the player can do any actions.
* Check whether the player can do any of these actions:
* <ul>
* <li>{@link #draw draw} a card</li>
* <li>{@link #build build} any item</li>
* <li>{@link #rollDice roll} a dice</li>
* </ul>
*
* @return whether the game is currently active
* @return whether the game is currently active (player can still do an action)
*/
private boolean gameActive() {
public boolean gameActive() {
return gameStarted() && phase != Phase.WON && phase != Phase.LOST;
}
@ -212,6 +217,7 @@ public class CardGame {
&& phase != Phase.AWAITING_DICE_ROLL
// can not build item
&& Arrays.stream(Item.values()).noneMatch(inventory::canBuild)
// can not lose after winning..
&& phase != Phase.WON) {
endGame();
phase = Phase.LOST;
@ -227,7 +233,7 @@ public class CardGame {
}
/**
* End the current game, deleting the active card stack.
* End the current game, {@link CardStack#clearActiveStack deleting} the active card stack.
* Player resources and items are not deleted.
*/
private void endGame() {
@ -236,8 +242,8 @@ public class CardGame {
/**
* Check whether the active game is lost.
* A game is lost if no more player actions ({@link #draw}, {@link #build}, {@link #rollDice}) are possible and
* the player did not win.
* A game is lost if no more player actions (see {@link #gameActive}) are possible and
* the player did not {@link Phase#WON win}.
*
* @return whether the active game is lost
*/
@ -247,10 +253,11 @@ public class CardGame {
}
/**
* Get the resources available for {@link #build building} in chronological order.
* Get the resources available for {@link #build building} in chronological order of acquisition.
*
* @return usable resources
* @throws LogicException if no game is active
* @throws LogicException if game is not {@link #gameStarted started}
* @see Inventory#getResources
*/
public Collection<Card> getResources() throws LogicException {
if (!gameStarted()) {
@ -260,10 +267,11 @@ public class CardGame {
}
/**
* Get the items already built in chronological order.
* Get the items already {@link #build built} in chronological order of construction.
*
* @return items owned by the player
* @throws LogicException if no game is active
* @throws LogicException if game is not {@link #gameStarted started}
* @see Inventory#getItems
*/
public List<Item> getItems() throws LogicException {
if (!gameStarted()) {
@ -275,8 +283,8 @@ public class CardGame {
/**
* Get the currently {@link #build buildable} items.
*
* @return set of items currently buildable
* @throws LogicException if game not in scavenge phase
* @return items currently buildable
* @throws LogicException if items can not be built in current game phase
*/
public Set<Item> getBuildableItems() throws LogicException {
if (!gameStarted()) {
@ -298,7 +306,7 @@ public class CardGame {
}
this.cardStack.reset();
this.inventory.clear();
this.requireDice = null;
this.toActivateOnDiceRoll = null;
this.phase = Phase.SCAVENGE;
}
@ -309,7 +317,7 @@ public class CardGame {
* @author Arne Keller
* @version 1.1
*/
enum Phase {
private enum Phase {
/**
* Player can draw cards and build items.
*
@ -319,7 +327,7 @@ public class CardGame {
*/
SCAVENGE,
/**
* Player has to fight an animal or attempt to escape using {@link #rollDice(int, int)}.
* Player has to fight an animal (encounter) or attempt to escape (endeavor) using {@link #rollDice(int, int)}.
*
* @see CardCategory#ANIMAL
* @see ItemCategory#ESCAPE

View File

@ -9,6 +9,7 @@ import java.util.Optional;
/**
* Simple card stack that remembers its initial state and can be {@link #reset} on demand.
* Always contains the same {@link Card#requiredAmount amount} of each card.
*
* @author Arne Keller
* @version 1.0
@ -31,6 +32,7 @@ public class CardStack {
*
* @param cards (ordered) card collection
* @throws LogicException if card stack has wrong distribution of cards
* @see Card#requiredAmount
*/
public CardStack(Collection<Card> cards) throws LogicException {
if (!Arrays.stream(Card.values())
@ -58,7 +60,7 @@ public class CardStack {
}
/**
* Reset the currently active stack.
* Reset the currently active stack, restoring the original stack.
*/
public void reset() {
activeStack = new ArrayDeque<>(stack);

View File

@ -17,11 +17,12 @@ import java.util.Objects;
*/
public class Inventory {
/**
* Resources collected by the player. Obviously only contains {@link CardCategory#RESOURCE resource} cards.
* Resources collected by the player.
* Obviously only contains {@link CardCategory#RESOURCE resource} cards.
*/
private final Deque<Card> resources = new ArrayDeque<>();
/**
* Items built by the player.
* Items built by the player in chronological order of creation.
*/
private final List<Item> items = new ArrayList<>();
@ -39,7 +40,7 @@ public class Inventory {
}
/**
* Get the resources stored in this inventory in chronological order.
* Get the resources stored in this inventory in chronological order of acquisition.
*
* @return resources owned by the player
*/
@ -49,7 +50,7 @@ public class Inventory {
}
/**
* Clear player resources, {@link Item#itemsSecured keeping} a few items
* Clear player resources, {@link Item#itemsSecured leaving} a few items
* in the {@link Item#SHACK shack} if one is built.
*/
public void clearResources() {
@ -65,7 +66,7 @@ public class Inventory {
* Attempt to build the specified item.
*
* @param item item to build
* @return whether the item could be built
* @return whether the item could be built (false if missing resources or items)
*/
public boolean build(Item item) {
if (!canBuild(item)) {
@ -81,7 +82,7 @@ public class Inventory {
}
/**
* Get the items stored in this inventory in reverse chronological order.
* Get the items stored in this inventory in chronological order of creation.
*
* @return items owned by the player
*/
@ -91,7 +92,7 @@ public class Inventory {
}
/**
* Check whether this inventory contains a specified item.
* Check whether this inventory contains a specific item.
*
* @param item single item
* @return whether this inventory contains that item
@ -124,16 +125,18 @@ public class Inventory {
if (!items.containsAll(item.itemsNeededToBuild())) {
return false;
}
// get the needed resources and overwrite entries with null if available
// get the needed resources and check whether this inventory contains all of them
final Card[] resourcesNeeded = item.resourcesNeeded();
for (final Card resource : resources) {
for (int j = 0; j < resourcesNeeded.length; j++) {
if (resourcesNeeded[j] != null && resourcesNeeded[j] == resource) {
// overwrite entries with null if available in inventory
resourcesNeeded[j] = null;
break;
break; // process next available resource
}
}
}
// now just check whether all of the entries are null
return Arrays.stream(resourcesNeeded).allMatch(Objects::isNull);
}

View File

@ -53,7 +53,8 @@ public enum Item implements RequireDice {
* A misspelled hot-air balloon. Requires a fireplace to build.
*/
BALLON;
// note: new items require changes in resourcesNeeded, parse and toString
// note: new items *require* changes in parse and toString
// addition in resourcesNeeded heavily recommended
/**
* Return value indicating success.
@ -86,7 +87,7 @@ public enum Item implements RequireDice {
if (this.category() == ItemCategory.ESCAPE) {
if (this.diceSizeNeeded().isPresent()) {
// player needs to roll dice to escape
game.startDiceRoll(this);
game.waitForDiceRoll(this);
} else {
// player won
game.winGame();
@ -219,7 +220,7 @@ public enum Item implements RequireDice {
/**
* Parse a single word and return the item represented by the input.
* Fun fact: Item.parse(item.toString()) == item is true for all items.
* This method is the inverse of {@link #toString}.
*
* @param input text
* @return parsed item or null if not found
@ -247,12 +248,6 @@ public enum Item implements RequireDice {
}
}
/**
* Get the textual representation of this item.
* Fun fact: Item.parse(item.toString()) == item is true for all items.
*
* @return textual representation of this item
*/
@Override
public String toString() {
switch (this) {

View File

@ -1,10 +1,12 @@
package edu.kit.informatik.cardgame.model;
/**
* Item category. {@link Item Game items} are categorized into two categories: normal items and items used to escape.
* Item category.
* {@link Item Game items} are categorized into two categories: normal items and items used to escape.
*
* @author Arne Keller
* @version 1.0
* @see Item#activate(CardGame, int, int)
*/
public enum ItemCategory {
/**
@ -17,7 +19,7 @@ public enum ItemCategory {
*/
DEFAULT,
/**
* Item that can be used to escape.
* Item that can be used to escape and {@link CardGame#winGame win} the game.
*
* @see Item#SAILING_RAFT
* @see Item#HANG_GLIDER

View File

@ -3,14 +3,14 @@ package edu.kit.informatik.cardgame.model;
import java.util.Optional;
/**
* Objects of classes implementing this optionally require a dice to be rolled.
* Objects of classes implementing this interface optionally require a dice to be rolled.
*
* @author Arne Keller
* @version 2.0
*/
public interface RequireDice {
/**
* Activate this object in a game if the dice roll is good enough.
* Activate this object in a game if the dice roll is lucky enough.
*
* @param game card game to use
* @param size size of the dice rolled

View File

@ -7,16 +7,23 @@ import edu.kit.informatik.cardgame.ui.command.CommandFactory;
import edu.kit.informatik.Terminal;
/**
* Interactive game runner, gets user inputs and processes commands specified.
* Interactive game runner, gets user inputs and processes {@link Command commands} specified.
*
* @author Arne Keller
* @version 1.0
* @see CardGame
*/
public final class CommandLine {
/**
* Command used to quit the game and terminate the program.
*/
private static final String QUIT = "quit";
/**
* Output text indicating that the player lost the active game.
*
* @see CardGame#gameLost
*/
private static final String LOST = "lost";
/**
* Utility class -> private constructor.
@ -26,11 +33,12 @@ public final class CommandLine {
}
/**
* Start a new interactive user session. Returns when standard in is fully processed or user exits.
* Start a new interactive user session. Returns when terminal input is fully processed or user {@link #QUIT exits}.
*/
public static void startInteractive() {
// create a new simulation
final CardGame simulation = new CardGame();
// whether the player lost
boolean lost = false;
// accept user input indefinitely
while (true) {
@ -50,21 +58,23 @@ public final class CommandLine {
// attempt to parse user input
try {
command = CommandFactory.getCommand(input);
} catch (NumberFormatException | InvalidInputException e) {
} catch (final NumberFormatException | InvalidInputException e) {
Terminal.printError(e.getMessage());
continue; // to next command
}
// attempt to execute command
try {
command.apply(simulation);
} catch (LogicException e) {
} catch (final LogicException e) {
Terminal.printError(e.getMessage());
}
// inform the player if he lost
if (lost != simulation.gameLost() && simulation.gameLost()) {
Terminal.printLine("lost");
// inform the player if they lost
final boolean gameNowLost = simulation.gameLost();
// (only tell them if they lost after last action)
if (gameNowLost && !lost) {
Terminal.printLine(LOST);
}
lost = simulation.gameLost();
lost = gameNowLost;
}
}
}

View File

@ -1,12 +1,14 @@
package edu.kit.informatik.cardgame.ui;
import edu.kit.informatik.cardgame.ui.command.Command;
import edu.kit.informatik.cardgame.ui.command.CommandFactory;
/**
* Thrown on syntactically invalid user input, usually in the {@link Command#parse command parsers}.
* Thrown on syntactically invalid user input, usually in a command {@link Command#parse parsers}.
*
* @author Arne Keller
* @version 1.0
* @see CommandFactory
*/
public class InvalidInputException extends Exception {
/**

View File

@ -10,10 +10,11 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Build command. Allows the player to build a single item.
* Build command. Allows the player to attempt to build a single item.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#build
*/
public final class Build extends Command {
/**
@ -22,6 +23,9 @@ public final class Build extends Command {
public static final String NAME = "build";
private static final Pattern BUILD_ARGUMENT = Pattern.compile(" (\\w+)");
/**
* Item to build.
*/
private Item item;
@Override
@ -44,5 +48,8 @@ public final class Build extends Command {
throw new InvalidInputException("invalid build command");
}
item = Item.parse(matcher.group(1));
if (item == null) { // parse could not process the item name
throw new InvalidInputException("invalid item name");
}
}
}

View File

@ -14,6 +14,7 @@ import java.util.Set;
*
* @author Arne Keller
* @version 1.0
* @see CardGame#getBuildableItems
*/
public final class Buildable extends Command {
/**

View File

@ -10,12 +10,14 @@ import edu.kit.informatik.cardgame.ui.InvalidInputException;
*
* @author Arne Keller
* @version 1.0
* @see CommandFactory
*/
public abstract class Command {
/**
* Apply this command to a game.
*
* @param game game to use
* @throws LogicException on invalid user input
* @throws LogicException on semantically wrong user input
*/
public abstract void apply(CardGame game) throws LogicException;

View File

@ -6,14 +6,14 @@ import java.util.TreeMap;
import java.util.function.Supplier;
/**
* Factory used to parse user input into commands.
* Factory (utility class) used to parse user input into commands.
*
* @author Arne Keller
* @version 1.2
*/
public final class CommandFactory {
/**
* Collection of command suppliers keyed by their respective command name.
* Collection of command suppliers keyed by their name/prefix.
*/
private static final TreeMap<String, Supplier<Command>> COMMANDS = new TreeMap<>();
@ -33,11 +33,12 @@ public final class CommandFactory {
* Utility class -> private constructor.
*/
private CommandFactory() {
}
/**
* Parse a single line of user input into one command.
*
* @param input user input line
* @return a fully specified command object
* @throws InvalidInputException if user input is invalid
@ -51,9 +52,10 @@ public final class CommandFactory {
.findFirst().orElse(null);
if (commandSupplier != null) {
final Command command = commandSupplier.get();
// attempt to parse with the correct command object
command.parse(input);
return command;
} else {
} else { // no matching command found
throw new InvalidInputException("unknown command");
}
}

View File

@ -6,10 +6,11 @@ import edu.kit.informatik.cardgame.model.LogicException;
import edu.kit.informatik.cardgame.ui.InvalidInputException;
/**
* Draw command used to take a card from the stack.
* Draw command used to take a card from the stack. Will print the drawn card to the terminal.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#draw
*/
public final class Draw extends Command {
/**

View File

@ -10,10 +10,11 @@ import java.util.List;
/**
* list-buildings command.
* Prints buildings of the player, starting with the most recently built {@link Item}.
* Prints buildings of the player on the terminal, starting with the most recently built {@link Item}.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#getItems
*/
public final class ListBuildings extends Command {
/**
@ -24,7 +25,7 @@ public final class ListBuildings extends Command {
@Override
public void apply(CardGame game) throws LogicException {
final List<Item> items = game.getItems();
if (items.isEmpty()) {
if (items.isEmpty()) { // player has not built any items yet
Terminal.printLine("EMPTY");
} else {
for (int i = items.size() - 1; i >= 0; i--) {

View File

@ -9,11 +9,12 @@ import edu.kit.informatik.cardgame.ui.InvalidInputException;
import java.util.Collection;
/**
* list-resources command. Prints all of the {@link Card resources} collected by the player,
* starting with the first picked up resource.
* list-resources command.
* Prints all of the {@link Card resources} collected by the player, starting with the first picked up resource.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#getResources
*/
public final class ListResources extends Command {
/**
@ -25,6 +26,7 @@ public final class ListResources extends Command {
public void apply(CardGame game) throws LogicException {
final Collection<Card> resources = game.getResources();
if (resources.isEmpty()) {
// player does not own any resources
Terminal.printLine("EMPTY");
} else {
resources.forEach(Terminal::printLine);

View File

@ -6,10 +6,12 @@ import edu.kit.informatik.cardgame.model.LogicException;
import edu.kit.informatik.cardgame.ui.InvalidInputException;
/**
* Reset command. Removes player progress and restores the original card stack.
* Reset command.
* Removes player progress and restores the original card stack.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#reset
*/
public final class Reset extends Command {
/**

View File

@ -9,10 +9,12 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Roll dice command. Passes dice results to the game.
* Roll dice command.
* Passes dice roll to the game and prints the result.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#rollDice
*/
public final class RollDice extends Command {
/**
@ -21,8 +23,13 @@ public final class RollDice extends Command {
public static final String NAME = "rollD";
private static final Pattern ROLL_DICE_ARGUMENTS = Pattern.compile(NAME + "\\+?(\\d+) \\+?(\\d+)");
/**
* Size of the dice rolled.
*/
private int size;
/**
* User-supplied result of the dice roll.
*/
private int rolledNumber;
@Override

View File

@ -12,26 +12,36 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Start command. Initializes the game with a card stack.
* Start command.
* Initializes the game with a card stack.
*
* @author Arne Keller
* @version 1.0
* @see CardGame#start
*/
public final class Start extends Command {
/**
* Name of this command.
*/
public static final String NAME = "start";
private static final Pattern START_ARGUMENTS = Pattern.compile("start ((\\w+,){63}(\\w+))");
private static final int EXPECTED_CARD_AMOUNT = 64;
private static final String CARD_SEPARATOR = ",";
private static final Pattern START_ARGUMENTS
= Pattern.compile(NAME + " ((\\w+" + CARD_SEPARATOR + "){" + (EXPECTED_CARD_AMOUNT - 1) + "}(\\w+))");
/**
* Cards that should be used to start the game.
*/
private Deque<Card> cards;
@Override
public void apply(CardGame game) throws LogicException {
// attempt to start the game
if (game.start(cards)) {
Terminal.printLine("OK");
} else {
throw new LogicException("could not start game");
// game already started
throw new LogicException("could not start game: not inactive");
}
}
@ -45,7 +55,7 @@ public final class Start extends Command {
throw new InvalidInputException("invalid start arguments");
}
cards = new ArrayDeque<>();
for (final String s : matcher.group(1).split(",")) {
for (final String s : matcher.group(1).split(CARD_SEPARATOR)) {
final Card card = Card.parse(s);
if (card == null) {
throw new InvalidInputException("invalid start argument value(s)");