mirror of
https://gitlab.com/arnekeller/kit-programmieren-ws1920-final2.git
synced 2024-11-08 09:50:38 +00:00
Final documentation updates and additions
This commit is contained in:
parent
6333f3d6a5
commit
5e6366d0c0
@ -7,6 +7,7 @@ import edu.kit.informatik.cardgame.ui.CommandLine;
|
||||
*
|
||||
* @author Arne Keller
|
||||
* @version 1.0
|
||||
* @see CommandLine
|
||||
*/
|
||||
public final class Main {
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import java.util.Set;
|
||||
*
|
||||
* @author Arne Keller
|
||||
* @version 1.0
|
||||
* @see CardGame#getBuildableItems
|
||||
*/
|
||||
public final class Buildable extends Command {
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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--) {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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)");
|
||||
|
Loading…
Reference in New Issue
Block a user