Implement more commands and add test case

This commit is contained in:
Arne Keller 2020-02-25 18:19:52 +01:00
parent e36116701b
commit bffdf9112c
11 changed files with 291 additions and 31 deletions

117
game1_input.txt Normal file
View File

@ -0,0 +1,117 @@
startn
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
spider
spider
spider
spider
spider
snake
snake
snake
snake
snake
tiger
tiger
tiger
tiger
tiger
thunderstorm
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
draw
build?
build steamboat
build fireplace
build steamboat

60
game1_output.txt Normal file
View File

@ -0,0 +1,60 @@
OK
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
wood
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
plastic
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
metal
axe
ballon
club
fireplace
hangglider
sailingraft
shack
steamboat
Error, need fireplace to build
OK
OK

View File

@ -0,0 +1,30 @@
package edu.kit.informatik;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.nio.file.Files;
import static org.junit.jupiter.api.Assertions.*;
class MainTest {
@Test
void game1() throws IOException {
cmpInOut("game1_input.txt", "game1_output.txt");
}
private void cmpInOut(String in, String out) throws IOException {
System.setIn(new ByteArrayInputStream(readFile(in)));
ByteArrayOutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
Terminal.reload();
Main.main(null);
String expected = new String(readFile(out));
assertEquals(expected, output.toString());
}
private byte[] readFile(String name) throws IOException {
File file = new File(name);
return Files.readAllBytes(file.toPath());
}
}

View File

@ -8,16 +8,21 @@ import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static edu.kit.informatik.model.Item.AXE;
import static edu.kit.informatik.model.Item.BALLOON;
import static edu.kit.informatik.model.Item.CLUB;
import static edu.kit.informatik.model.Item.FIREPLACE;
import static edu.kit.informatik.model.Item.HANG_GLIDER;
import static edu.kit.informatik.model.Item.SAILING_RAFT;
import static edu.kit.informatik.model.Item.SHACK;
import static edu.kit.informatik.model.Item.STEAMBOAT;
public class CardGame {
private Deque<Card> cardStack;
private Deque<Card> resources = new ArrayDeque<>();
private List<Item> buildings = new ArrayList<>();
private List<Item> items = new ArrayList<>();
private boolean fightingAnimal = false;
private Integer awaitedDiceSize = null;
private Integer minimumDiceRoll = null;
@ -52,7 +57,7 @@ public class CardGame {
minimumDiceRoll = card.minimumDiceRollNeeded();
} else if (card.isCatastrophe()) {
clearResources();
buildings.remove(FIREPLACE);
items.remove(FIREPLACE);
}
return card;
}
@ -65,22 +70,24 @@ public class CardGame {
throw new InvalidInputException("unexpected dice size");
}
if (fightingAnimal) {
int bonus = buildings.contains(AXE) ? 2 : buildings.contains(CLUB) ? 1 : 0;
if (roll + bonus < minimumDiceRoll) {
int bonus = items.contains(AXE) ? 2 : items.contains(CLUB) ? 1 : 0;
if (roll + bonus >= minimumDiceRoll) {
return "survived";
} else {
clearResources();
return "lose";
} else {
return "survived";
}
} else {
// TODO trying to flee
return "win";
// return "lose";
if (roll >= minimumDiceRoll) {
return "win";
} else {
return "lose";
}
}
}
public void clearResources() {
int keepLastResources = buildings.contains(SHACK) ? 5 : 0;
int keepLastResources = items.contains(SHACK) ? 5 : 0;
while (resources.size() > keepLastResources) {
resources.removeFirst();
}
@ -90,6 +97,32 @@ public class CardGame {
if (item == null) {
throw new InvalidInputException("can not build null item");
}
if (item.requiresFireplace() && !items.contains(FIREPLACE)) {
throw new InvalidInputException("need fireplace to build");
}
if (canBuild(item)) {
// remove used resources
for (Card resource : item.resourcesNeeded()) {
assert(resources.removeLastOccurrence(resource)); // TODO: remove assert
}
items.add(item);
// TODO: building to flee
if (items.equals(STEAMBOAT) || items.equals(BALLOON)) {
// player won
reset();
} else if (items.equals(SAILING_RAFT) || items.equals(HANG_GLIDER)) {
// need at least a 4/d6
fightingAnimal = false;
awaitedDiceSize = 6;
minimumDiceRoll = 4;
}
return true;
} else {
return false;
}
}
private boolean canBuild(Item item) {
Card[] resourcesNeeded = item.resourcesNeeded();
for (Card resource : resources) {
for (int j = 0; j < resourcesNeeded.length; j++) {
@ -99,17 +132,7 @@ public class CardGame {
}
}
}
if (Arrays.stream(resourcesNeeded).allMatch(Objects::isNull)) {
// remove used resources
for (Card resource : item.resourcesNeeded()) {
assert(resources.remove(resource)); // TODO: remove assert
}
buildings.add(item);
// TODO: building to flee
return true;
} else {
return false;
}
return Arrays.stream(resourcesNeeded).allMatch(Objects::isNull);
}
public Deque<Card> getResources() {
@ -117,15 +140,19 @@ public class CardGame {
return new ArrayDeque<>(resources);
}
public List<Item> getBuildings() {
public List<Item> getItems() {
// do not allow caller to modify internal list
return new ArrayList<>(buildings);
return new ArrayList<>(items);
}
public List<Item> getBuildableItems() {
return Arrays.stream(Item.values()).filter(this::canBuild).collect(Collectors.toList());
}
public void reset() {
this.cardStack = null;
this.resources = new ArrayDeque<>();
this.buildings = new ArrayList<>();
this.items = new ArrayList<>();
this.fightingAnimal = false;
this.awaitedDiceSize = null;
this.minimumDiceRoll = null;

View File

@ -37,6 +37,10 @@ public enum Item {
}
}
public boolean requiresFireplace() {
return this.equals(STEAMBOAT) || this.equals(BALLOON);
}
public static Item parse(String input) {
switch (input) {
case "axe":

View File

@ -5,6 +5,9 @@ import edu.kit.informatik.Terminal;
import edu.kit.informatik.ui.command.Command;
import edu.kit.informatik.ui.command.CommandFactory;
import java.util.StringJoiner;
import java.util.stream.IntStream;
/**
* Interactive game runner, gets user inputs and processes commands specified.
*
@ -39,6 +42,12 @@ public final class CommandLine {
if (input.startsWith("#")) {
continue; // TODO remove
}
if (input.startsWith("startn")) {
// TODO remove
StringJoiner j = new StringJoiner(",");
IntStream.range(0, 64).mapToObj(x -> Terminal.readLine()).forEach(j::add);
input = "start " + j.toString();
}
if (input.startsWith(QUIT)) {
if (input.length() != QUIT.length()) {

View File

@ -19,6 +19,8 @@ public class Build extends Command {
public void apply(CardGame game) throws InvalidInputException {
if (game.build(item)) {
Terminal.printLine("OK");
} else {
Terminal.printError("could not build item");
}
}

View File

@ -1,14 +1,25 @@
package edu.kit.informatik.ui.command;
import edu.kit.informatik.Terminal;
import edu.kit.informatik.model.CardGame;
import edu.kit.informatik.model.Item;
import edu.kit.informatik.ui.InvalidInputException;
import java.util.Comparator;
import java.util.List;
import static edu.kit.informatik.ui.command.CommandFactory.BUILDABLE;
public class Buildable extends Command {
@Override
public void apply(CardGame game) {
List<Item> buildable = game.getBuildableItems();
if (buildable.isEmpty()) {
Terminal.printLine("EMPTY");
} else {
buildable.sort(Comparator.comparing(Object::toString));
buildable.forEach(Terminal::printLine);
}
}
@Override

View File

@ -12,7 +12,7 @@ import static edu.kit.informatik.ui.command.CommandFactory.LIST_BUILDINGS;
public class ListBuildings extends Command {
@Override
public void apply(CardGame game) throws InvalidInputException {
List<Item> items = game.getBuildings();
List<Item> items = game.getItems();
if (items.isEmpty()) {
Terminal.printLine("EMPTY");
} else {

View File

@ -5,14 +5,14 @@ import edu.kit.informatik.model.Card;
import edu.kit.informatik.model.CardGame;
import edu.kit.informatik.ui.InvalidInputException;
import java.util.List;
import java.util.Deque;
import static edu.kit.informatik.ui.command.CommandFactory.LIST_RESOURCES;
public class ListResources extends Command {
@Override
public void apply(CardGame game) throws InvalidInputException {
List<Card> resources = game.getResources();
Deque<Card> resources = game.getResources();
if (resources.isEmpty()) {
Terminal.printLine("EMPTY");
} else {

View File

@ -6,6 +6,7 @@ import edu.kit.informatik.model.CardGame;
import edu.kit.informatik.ui.InvalidInputException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.Objects;
import java.util.regex.Matcher;
@ -16,7 +17,7 @@ import java.util.stream.IntStream;
import static edu.kit.informatik.ui.command.CommandFactory.CARD;
public class Start extends Command {
private static final Pattern START_ARGUMENTS = Pattern.compile("start (?:(" + CARD + "),){63},(" + CARD + ")");
private static final Pattern START_ARGUMENTS = Pattern.compile("start ((?:(?:" + CARD + "),){63}(?:" + CARD + "))");
private Deque<Card> cards;
@ -38,8 +39,7 @@ public class Start extends Command {
if (!matcher.matches()) {
throw new InvalidInputException("invalid start arguments");
}
cards = IntStream.rangeClosed(1, matcher.groupCount())
.mapToObj(matcher::group)
cards = Arrays.stream(matcher.group(1).split(","))
.map(Card::parse)
.collect(Collectors.toCollection(ArrayDeque::new));
if (cards.stream().anyMatch(Objects::isNull)) {