This commit is contained in:
Arne Keller 2020-03-22 11:47:30 +01:00
parent 911c4b3cd1
commit 3ba69ce595
3 changed files with 73 additions and 28 deletions

View File

@ -8,12 +8,12 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* Card game. Features: * Simple card game. Features:
* <ul> * <ul>
* <li>100% deterministic</li> * <li>100% deterministic</li>
* <li>64! different card stacks</li> * <li>64! different card stacks</li>
* <li>8 buildable items</li> * <li>8 buildable {@link Item} items</li>
* <li>7 exciting card types</li> * <li>7 exciting {@link Card card} types</li>
* <li>3 dice needed</li> * <li>3 dice needed</li>
* <li>0 skill required</li> * <li>0 skill required</li>
* </ul> * </ul>
@ -22,12 +22,42 @@ import java.util.stream.Collectors;
* @version 1.0 * @version 1.0
*/ */
public class CardGame { public class CardGame {
/**
* Return value indicating success.
*
* @see #build(Item)
*/
public static final String OK = "OK";
/**
* Return value indicating that the player won.
*
* @see #build(Item)
* @see #rollDice(int, int)
* @see ItemCategory#ESCAPE
*/
public static final String WIN = "win";
/**
* Return value indicating that the player successfully fought against an animal.
*
* @see #rollDice(int, int)
* @see CardCategory#ANIMAL
*/
public static final String SURVIVED = "survived";
/**
* Return value indicating that the player lost against an animal or failed to escape.
*
* @see #rollDice(int, int)
* @see CardCategory#ANIMAL
* @see ItemCategory#ESCAPE
*/
public static final String LOSE = "lose";
/** /**
* Card stack used. * Card stack used.
*/ */
private CardStack cardStack; private CardStack cardStack;
/** /**
* Inventory of the player, containing resources and items. * Inventory of the player, containing {@link Card resources} and {@link Item items}.
*/ */
private Inventory inventory; private Inventory inventory;
/** /**
@ -49,6 +79,7 @@ public class CardGame {
*/ */
public boolean start(Collection<Card> cardStack) throws LogicException { public boolean start(Collection<Card> cardStack) throws LogicException {
if (gameActive()) { if (gameActive()) {
// do not start a new game if one is active already
return false; return false;
} }
if (!Arrays.stream(Card.values()) if (!Arrays.stream(Card.values())
@ -57,13 +88,14 @@ public class CardGame {
} }
this.cardStack = new CardStack(cardStack); this.cardStack = new CardStack(cardStack);
this.inventory = new Inventory(); this.inventory = new Inventory();
this.phase = Phase.SCAVENGE;
// clear player inventory (relevant when restarting game)
reset(); reset();
return true; return true;
} }
/** /**
* Draw a new card. Will automatically add the card to the players resources, start an encounter or let the * Draw a new card. Will automatically add the card to the player's resources or process the card action.
* thunderstorm do its work.
* *
* @return the card * @return the card
* @throws LogicException if no card to draw exists or phase is not scavenge * @throws LogicException if no card to draw exists or phase is not scavenge
@ -87,7 +119,7 @@ public class CardGame {
inventory.clearResources(); inventory.clearResources();
inventory.removeItem(Item.FIREPLACE); inventory.removeItem(Item.FIREPLACE);
break; break;
default: default: // implement game-related behaviour of new card types here
throw new IllegalStateException("encountered unknown card category!"); throw new IllegalStateException("encountered unknown card category!");
} }
checkLost(); checkLost();
@ -99,13 +131,14 @@ public class CardGame {
* *
* @param size dice size * @param size dice size
* @param roll dice result * @param roll dice result
* @return result of the throw (survived, lose or win) * @return result of the throw ({@link #SURVIVED survived}, {@link #LOSE lose} or {@link #WIN win})
* @throws LogicException if not expecting dice roll or dice roll is invalid * @throws LogicException if not expecting dice roll or dice roll is invalid
*/ */
public String rollDice(int size, int roll) throws LogicException { public String rollDice(int size, int roll) throws LogicException {
if (requireDice == null) { if (requireDice == null) {
throw new LogicException("not expecting dice roll"); throw new LogicException("not expecting dice roll");
} }
// compare with currently expected dice
final int sizeNeeded = requireDice.diceSizeNeeded().get(); final int sizeNeeded = requireDice.diceSizeNeeded().get();
final int minimumNeeded = requireDice.minimumDiceRollNeeded().get(); final int minimumNeeded = requireDice.minimumDiceRollNeeded().get();
if (sizeNeeded != size) { if (sizeNeeded != size) {
@ -113,6 +146,7 @@ public class CardGame {
} else if (roll > sizeNeeded || roll < 1) { } else if (roll > sizeNeeded || roll < 1) {
throw new LogicException("impossible roll"); throw new LogicException("impossible roll");
} }
// no longer waiting for dice roll
requireDice = null; requireDice = null;
if (phase == Phase.ENCOUNTER) { if (phase == Phase.ENCOUNTER) {
// calculate fighting bonus, selecting the most powerful item the player owns // calculate fighting bonus, selecting the most powerful item the player owns
@ -120,21 +154,21 @@ public class CardGame {
phase = Phase.SCAVENGE; phase = Phase.SCAVENGE;
checkLost(); checkLost();
if (roll + bonus >= minimumNeeded) { if (roll + bonus >= minimumNeeded) {
return "survived"; return SURVIVED;
} else { } else {
inventory.clearResources(); inventory.clearResources();
return "lose"; return LOSE;
} }
} else { // attempting to escape } else { // attempting to escape
// do not remove item used to escape // do not remove item used to escape
if (roll >= minimumNeeded) { if (roll >= minimumNeeded) {
endGame(); endGame();
phase = Phase.WON; phase = Phase.WON;
return "win"; return WIN;
} else { } else {
phase = Phase.SCAVENGE; phase = Phase.SCAVENGE;
checkLost(); checkLost();
return "lose"; return LOSE;
} }
} }
} }
@ -143,7 +177,7 @@ public class CardGame {
* Attempt to build the specified item. * Attempt to build the specified item.
* *
* @param item item to build * @param item item to build
* @return building result (OK or win), or null if item can not be built * @return building result ({@link #OK} or {@link #WIN win}, or null if item can not be built
* @throws LogicException if in wrong phase or item already built * @throws LogicException if in wrong phase or item already built
*/ */
public String build(Item item) throws LogicException { public String build(Item item) throws LogicException {
@ -166,15 +200,17 @@ public class CardGame {
// player won // player won
endGame(); endGame();
phase = Phase.WON; phase = Phase.WON;
return "win"; return WIN;
} }
} }
checkLost(); checkLost();
return "OK"; return OK;
} }
} }
/** /**
* Check whether this game ever received a {@link #start start} command.
*
* @return whether the game was ever started * @return whether the game was ever started
*/ */
private boolean gameStarted() { private boolean gameStarted() {
@ -182,6 +218,8 @@ public class CardGame {
} }
/** /**
* Check whether the player can do any actions.
*
* @return whether the game is currently active * @return whether the game is currently active
*/ */
private boolean gameActive() { private boolean gameActive() {
@ -191,7 +229,7 @@ public class CardGame {
/** /**
* Check whether the player lost, updating the game state accordingly. * Check whether the player lost, updating the game state accordingly.
* *
* @see CardGame#gameLost * @see #gameLost
*/ */
private void checkLost() { private void checkLost() {
// can not draw new cards // can not draw new cards
@ -206,8 +244,9 @@ public class CardGame {
} }
/** /**
* Check whether the active game is lost. The game is lost if no cards to draw exist and no further actions are * Check whether the active game is lost.
* possible. * A game is lost if no more player actions ({@link #draw}, {@link #build}, {@link #rollDice}) are possible and
* the player did not win.
* *
* @return whether the active game is lost * @return whether the active game is lost
*/ */
@ -216,9 +255,9 @@ public class CardGame {
} }
/** /**
* Get the resources available for building in chronological order. * Get the resources available for {@link #build building} in chronological order.
* *
* @return resources available * @return usable resources
* @throws LogicException if no game is active * @throws LogicException if no game is active
*/ */
public Collection<Card> getResources() throws LogicException { public Collection<Card> getResources() throws LogicException {
@ -229,7 +268,7 @@ public class CardGame {
} }
/** /**
* Get the items already built in reverse chronological order. * Get the items already built in chronological order.
* *
* @return items owned by the player * @return items owned by the player
* @throws LogicException if no game is active * @throws LogicException if no game is active
@ -242,7 +281,7 @@ public class CardGame {
} }
/** /**
* Get the currently buildable items. * Get the currently {@link #build buildable} items.
* *
* @return set of items currently buildable * @return set of items currently buildable
* @throws LogicException if game not in scavenge phase * @throws LogicException if game not in scavenge phase
@ -258,22 +297,22 @@ public class CardGame {
/** /**
* End the current game, deleting the active card stack. * End the current game, deleting the active card stack.
* Player resources and items are not deleted.
*/ */
private void endGame() { private void endGame() {
cardStack.clearActiveStack(); cardStack.clearActiveStack();
} }
/** /**
* Reset the game, restoring the {@link #cardStack original card stack}. * Reset the game, restoring the {@link #cardStack original card stack} and clearing the player's inventory.
* *
* @throws LogicException if game was never started * @throws LogicException if game was never started
*/ */
public void reset() throws LogicException { public void reset() throws LogicException {
if (cardStack == null) { if (!gameStarted()) {
throw new LogicException("can not reset a game that is not started!"); throw new LogicException("can not reset a game that is not started!");
} else {
this.cardStack.reset();
} }
this.cardStack.reset();
this.inventory.clear(); this.inventory.clear();
this.requireDice = null; this.requireDice = null;
this.phase = Phase.SCAVENGE; this.phase = Phase.SCAVENGE;
@ -298,12 +337,14 @@ public class CardGame {
/** /**
* Player has to fight an animal. * Player has to fight an animal.
* *
* @see #rollDice
* @see CardCategory#ANIMAL * @see CardCategory#ANIMAL
*/ */
ENCOUNTER, ENCOUNTER,
/** /**
* Player is attempting to escape. * Player is attempting to escape.
* *
* @see #rollDice
* @see ItemCategory#ESCAPE * @see ItemCategory#ESCAPE
*/ */
ENDEAVOR, ENDEAVOR,
@ -313,6 +354,8 @@ public class CardGame {
WON, WON,
/** /**
* Player lost. * Player lost.
*
* @see #gameLost
*/ */
LOST LOST
} }

View File

@ -9,7 +9,8 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
* Player inventory. Contains {@link CardCategory#RESOURCE resources} and {@link Item items}. * Player inventory.
* Contains {@link CardCategory#RESOURCE resources} and {@link Item items}.
* *
* @author Arne Keller * @author Arne Keller
* @version 1.0 * @version 1.0

View File

@ -9,7 +9,8 @@ import edu.kit.informatik.cardgame.ui.InvalidInputException;
import java.util.List; import java.util.List;
/** /**
* list-buildings command. Prints buildings of the player, starting with the most recently built {@link Item}. * list-buildings command.
* Prints buildings of the player, starting with the most recently built {@link Item}.
* *
* @author Arne Keller * @author Arne Keller
* @version 1.0 * @version 1.0