Merge remote-tracking branch 'origin/main' into main

# Conflicts:
#	.gitignore
#	.idea/.gitignore
#	src/ch/zhaw/catan/Road.java
#	src/ch/zhaw/catan/SiedlerGame.java
This commit is contained in:
Andrin Fassbind 2021-12-04 12:59:31 +01:00
commit 8f12b40e50
34 changed files with 1054 additions and 335 deletions

79
.gitignore vendored
View File

@ -1 +1,80 @@
<<<<<<< HEAD
/out/ /out/
=======
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
misc.xml
SiedlerBoard.class
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
>>>>>>> origin/main

2
.idea/.gitignore vendored
View File

@ -6,3 +6,5 @@
/dataSources.local.xml /dataSources.local.xml
# Editor-based HTTP Client requests # Editor-based HTTP Client requests
/httpRequests/ /httpRequests/
/misc.xml
/out/

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -0,0 +1,43 @@
package ch.zhaw.catan;
import java.util.List;
import java.util.Map;
public class Bank {
private Map<Config.Resource, Integer> resources;
public Bank(){
resources = Config.INITIAL_RESOURCE_CARDS_BANK;
}
public void storeResourceToBank(List<Config.Resource> resourceToGive) {
for (Config.Resource resource : resourceToGive) {
resources.put(resource,resources.get(resource)+1);
}
}
public boolean getResourceFromBank(Config.Resource resource,int numberOfResources) {
if(resources.get(resource) >= numberOfResources) {
Integer newResourceNumber = resources.get(resource) - numberOfResources;
resources.put(resource, newResourceNumber);
return true;
}
else {
return false;
}
}
public boolean tradeWithBank(Config.Resource resourceToReceive, Config.Resource resourceToGive, int toWant, int toGive) {
if(resources.get(resourceToReceive) >= toWant){
Integer newResourceReceived = resources.get(resourceToReceive) + toGive;
Integer newResourcesGiven = resources.get(resourceToGive) - toWant;
resources.put(resourceToReceive, newResourceReceived);
resources.put(resourceToGive, newResourcesGiven);
return true;
}
else{
return false;
}
}
}

View File

@ -0,0 +1,12 @@
package ch.zhaw.catan;
public class City extends Settlement {
public City(Config.Faction faction) {
super(faction);
}
public String toString() {
return super.getFaction().toString().toUpperCase();
}
}

View File

@ -0,0 +1,20 @@
package ch.zhaw.catan;
import org.beryx.textio.TextIO;
public enum Command {
NEXTPLAYER ("next player"), BUILDSETTLEMENT ("build settlement"), BUILDCITY("build city"),
BUILDROAD("build road"), TRADEWITHBANK("trade with bank"),QUIT("quit");
private String commandWord;
Command(String commandWord) {
this.commandWord = commandWord;
}
public String toString() {
return commandWord;
}
}

View File

@ -15,15 +15,13 @@ public class Dummy {
SHOW, QUIT SHOW, QUIT
} }
private void run() { private void run() {
TextIO textIO = TextIoFactory.getTextIO(); TextIO textIO = TextIoFactory.getTextIO();
TextTerminal<?> textTerminal = textIO.getTextTerminal(); TextTerminal<?> textTerminal = textIO.getTextTerminal();
SiedlerBoard board = new SiedlerBoard(); SiedlerBoard board = new SiedlerBoard();
board.addField(new Point(2, 2), Land.FOREST); board.addField(new Point(2, 2), Land.FOREST);
board.setCorner(new Point(3, 3), "RR"); board.setCorner(new Point(3, 3), new Settlement(Config.Faction.RED));
board.setEdge(new Point(2, 0), new Point(3, 1), "r"); board.setEdge(new Point(2, 0), new Point(3, 1), new Road(Config.Faction.BLUE));
board.addFieldAnnotation(new Point(2, 2), new Point(3, 1), "AA"); board.addFieldAnnotation(new Point(2, 2), new Point(3, 1), "AA");
Map<Point, Label> lowerFieldLabel = new HashMap<>(); Map<Point, Label> lowerFieldLabel = new HashMap<>();

View File

@ -0,0 +1,26 @@
package ch.zhaw.catan;
import ch.zhaw.hexboard.Label;
public class Field {
private Config.Land land;
private Label label;
public Field(Config.Land land, Label label){
this.land = land;
this.label = label;
}
public Config.Resource getResource(){
return land.getResource();
}
public Config.Land getLand() {
return land;
}
public Label getLabel() {
return label;
}
}

View File

@ -0,0 +1,88 @@
package ch.zhaw.catan;
import org.beryx.textio.TextIO;
import org.beryx.textio.TextIoFactory;
import org.beryx.textio.TextTerminal;
import java.awt.*;
import java.util.HashMap;
import static ch.zhaw.catan.Command.*;
public class Parser {
TextIO textIO = TextIoFactory.getTextIO();
TextTerminal<?> textTerminal;
public Parser() {
textTerminal = textIO.getTextTerminal();
}
public Point getPoint() {
return new Point(textIO.newIntInputReader().withMinVal(0).read("x coordinate:"),
textIO.newIntInputReader().withMinVal(0).read("y coordinate:"));
}
public void displayGameboard(String gameboard) {
textTerminal.println(gameboard);
}
public void displayPlayerInfo(HashMap<Config.Resource, Integer> currentPlayerResource, int winpoints){
textTerminal.println("You are currently holding " + winpoints + " winpoints.");
textTerminal.println("You own the follwing resources:");
for(Config.Resource resource : currentPlayerResource.keySet()){
textTerminal.println(resource.name() + ":" + currentPlayerResource.get(resource));
}
}
public void displayWinnertext(Config.Faction winner){
textTerminal.println(winner.name() + " won the game!");
}
public HashMap<String, Integer> gameStart(){
HashMap<String, Integer> gameStartValues = new HashMap<>();
gameStartValues.put("NumberOfPlayers", textIO.newIntInputReader().withMinVal(2).withMaxVal(4).read("Number of players:"));
gameStartValues.put("NumberOfWinPoints", textIO.newIntInputReader().withMinVal(5).withMaxVal(15).read("Winpoints needed for Victory:"));
return gameStartValues;
}
public void giveCoordinatesForStructures(Config.Structure structure) {
textTerminal.println("Please insert coordinates for " + structure);
if(structure == Config.Structure.ROAD) {
textTerminal.println("Please first insert the start coordinate and when prompted again the coordinate of the end of the road.");
}
}
public void thrownDices(int number){
textTerminal.println ("Dices have been thrown, the combined value is: " + number);
}
public void playerTurn(Config.Faction faction) {
textTerminal.println("It is " + faction.name() + "'s turn.");
}
public void errorMessage(){
textTerminal.println("The command was not excecuted successfully!");
}
public Command getAction() {
return textIO.newEnumInputReader(Command.class).read("What would you like to do?");
}
/**
*
* @param give if true ask for resource to give if false for resource to receive
* @return
*/
public Config.Resource trade(boolean give) {
String output = "give";
if (!give){
output = "receive";
}
return textIO.newEnumInputReader(Config.Resource.class).read("Which Resource would you like to " + output );
}
public void quit(){
textTerminal.dispose();
textIO.dispose();
}
}

View File

@ -0,0 +1,138 @@
package ch.zhaw.catan;
import java.util.HashMap;
import java.util.List;
/**
* New Class PLayer
* This class is here to add players to the game.
*/
public class Player {
private Config.Faction faction;
private HashMap<Config.Resource,Integer> resources;
private int roadsToUse;
private int settlementsToUse;
private int citiesToUse;
public Player (Config.Faction faction){
//Datenfelder
this.faction = faction;
roadsToUse = Config.Structure.ROAD.getStockPerPlayer();
settlementsToUse = Config.Structure.SETTLEMENT.getStockPerPlayer();
//Ressourcen initialisiern
resources = new HashMap<>();
for(Config.Resource resource : Config.Resource.values()) {
resources.put(resource,0);
}
}
/**
* This method returns all the resources the player has at the moment
* @return HashMap with the count of every resource
*/
public HashMap<Config.Resource,Integer> getResources() {
return resources;
}
/**
* This method returns player faction
* @return
*/
public Config.Faction getFaction() { return faction; }
/**
* This method returns for specific resource how much player possesess.
* @param resource
* @return
*/
public int getSpecificResource(Config.Resource resource) { return resources.get(resource); }
/**
* This method adds a specific resource to resourcess
* @param resource to add
* @param numberToAdd how much to add
*/
public void addResource(Config.Resource resource, int numberToAdd) {
resources.put(resource, resources.get(resource) + numberToAdd);
}
/**
* This method substracts a specific resource from resourcess but check first if player has enough resources.
* @param resource to substract
* @param numberToTake how much to substract
* @return true if resource has been substracted false if player has not enough resources
*/
public boolean substractResource(Config.Resource resource, int numberToTake) {
int inPossesion = resources.get(resource);
if(inPossesion - numberToTake < 0) {
return false;
}
resources.put(resource,inPossesion - numberToTake);
return true;
}
/**
* This method has to be used when a player wants to build a road. It checks if a player has enough roads
* and resources to build one more. If player is able to build, the method substract the buildcost from the resources
* in possesion by the player.
* @return true if road can be created false if road can't be created
*/
public boolean buildRoad() {
List<Config.Resource> costs = Config.Structure.ROAD.getCosts();
if ( roadsToUse == 0 || !checkRessourceToBuild(costs)) {
return false;
}
for (Config.Resource resource : costs) {
resources.put(resource,resources.get(resource)-1);
}
return true;
}
/**
* This method has to be used when a player wants to build a settlement. It checks if a player has enough roads
* and resources to build one more. If the player is able to build, this method subtracts the buildcost from the resources
* in possession by the player.
* @return true if road can be created false if road can't be created.
*/
public boolean buildSettlement() {
List<Config.Resource> costs = Config.Structure.SETTLEMENT.getCosts();
if ( settlementsToUse == 0 || !checkRessourceToBuild(costs)) {
return false;
}
for (Config.Resource resource : costs) {
resources.put(resource,resources.get(resource)-1);
}
return true;
}
/**
* This method has to be used when a player wants to build a city. It checks if a player already has a settlement
* on that position and if he has enough resource to build one. If the player is able to build, this method subtracts
* the buildcost from the resources in possession by the player.
* @return true if road can be created false if road can't be created.
*/
public boolean buildCity() {
List<Config.Resource> costs = Config.Structure.CITY.getCosts();
if ( citiesToUse == 0 || !checkRessourceToBuild(costs)){
return false;
}
for (Config.Resource resource : costs){
resources.put(resource,resources.get(resource)-1);
}
return true;
}
//returns true if player has enough resources else false
private boolean checkRessourceToBuild(List<Config.Resource> liste) {
for (Config.Resource resource : liste) {
int possesion = resources.get(resource);
if (possesion == 0) {
return false;
}
}
return true;
}
}

View File

@ -1,22 +1,8 @@
package ch.zhaw.catan; package ch.zhaw.catan;
import java.util.HashMap; public class Road extends Structure {
/** public Road(Config.Faction faction) {
* This Class represents a Road Object. It informs about the ressources needed to build a road super(faction);
*/
public class Road {
final private HashMap<Config.Resource, Integer> buildCost;
public Road() {
buildCost = new HashMap<>();
buildCost.put(Config.Resource.LUMBER, 1);
buildCost.put(Config.Resource.BRICK, 1);
} }
public HashMap<Config.Resource, Integer> getBuildCost() {
return buildCost;
}
} }

View File

@ -0,0 +1,8 @@
package ch.zhaw.catan;
public class Settlement extends Structure {
public Settlement(Config.Faction faction) {
super(faction);
}
}

View File

@ -1,20 +1,132 @@
package ch.zhaw.catan; package ch.zhaw.catan;
import org.beryx.textio.TextIO; import java.util.HashMap;
import org.beryx.textio.TextIoFactory; import java.util.Random;
import org.beryx.textio.TextTerminal;
public class Siedler { public class Siedler {
public static void main(String[] args) { public static void main(String[] args) {
//Spiel erstellen //Spiel erstellen
SiedlerGame game = new SiedlerGame(0, 0); Parser parser = new Parser();
SiedlerGame game = foundingPhase(parser);
//Spielfeld ausgeben boolean running = true;
TextIO textIO = TextIoFactory.getTextIO(); boolean diceThrown = false;
TextTerminal<?> textTerminal = textIO.getTextTerminal(); while (running){
textTerminal.println(game.getBoard().getTextView()); Config.Faction currentPlayerFaction = game.getCurrentPlayerFaction();
parser.displayGameboard(game.getBoard().getTextView());
parser.playerTurn(currentPlayerFaction);
if(!diceThrown) {
throwDice(game, parser);
diceThrown = true;
}
parser.displayPlayerInfo(game.getCurruntPlayerResource(), game.getCurrentPlayerWinpoints());
switch (parser.getAction()) {
case NEXTPLAYER:
Config.Faction winner = game.getWinner();
if(winner == null) {
game.switchToNextPlayer();
diceThrown = false;
} else {
parser.displayWinnertext(winner);
running = false;
}
break;
case BUILDSETTLEMENT:
parser.giveCoordinatesForStructures(Config.Structure.SETTLEMENT);
if(!game.buildSettlement(parser.getPoint())){
parser.errorMessage();
}
break;
case BUILDCITY:
parser.giveCoordinatesForStructures(Config.Structure.CITY);
if(!game.buildCity(parser.getPoint())){
parser.errorMessage();
}
break;
case BUILDROAD:
parser.giveCoordinatesForStructures(Config.Structure.ROAD);
if(game.buildRoad(parser.getPoint(), parser.getPoint())){
parser.errorMessage();
}
break;
case TRADEWITHBANK:
Config.Resource offer = parser.trade(true);
Config.Resource want = parser.trade(false);
if(!game.tradeWithBankFourToOne(offer, want)){
parser.errorMessage();
}
break;
case QUIT:
running = false;
parser.quit();
break;
default:
parser.errorMessage();
}
}
} }
private static void throwDice(SiedlerGame game, Parser parser) {
Random random = new Random();
//sum of two integers from 0-5 + 2 --> sum of two integers from 1-6
int thrownDices = random.nextInt(6) + random.nextInt(6) + 2;
//todo check if 7
parser.thrownDices(thrownDices);
game.throwDice(thrownDices);
}
private static SiedlerGame foundingPhase(Parser parser) {
HashMap<String, Integer> gameInfo = parser.gameStart();
SiedlerGame game = new SiedlerGame(gameInfo.get("NumberOfWinPoints"), gameInfo.get("NumberOfPlayers"));
for(int player = 1; player <= gameInfo.get("NumberOfPlayers"); player++){
buildStructuresInFoundingPhase(game, parser, false);
if(player < gameInfo.get("NumberOfPlayers")){
game.switchToPreviousPlayer();
}
}
for(int player = 1; player <= gameInfo.get("NumberOfPlayers"); player++){
buildStructuresInFoundingPhase(game, parser, true);
game.switchToNextPlayer();
}
return game;
}
private static void buildStructuresInFoundingPhase(SiedlerGame game, Parser parser, Boolean payout){
parser.displayGameboard(game.getBoard().getTextView());
parser.playerTurn(game.getCurrentPlayerFaction());
//build Settlement
parser.giveCoordinatesForStructures(Config.Structure.SETTLEMENT);
boolean sucessful = false;
do{
if(game.placeInitialSettlement(parser.getPoint(), payout)) {
sucessful = true;
}
else{
parser.errorMessage();
}
} while(!sucessful);
//build Road
parser.displayGameboard(game.getBoard().getTextView());
parser.giveCoordinatesForStructures(Config.Structure.ROAD);
sucessful = false;
do{
if(game.placeInitialRoad(parser.getPoint(), parser.getPoint())) {
sucessful = true;
}
else{
parser.errorMessage();
}
} while(!sucessful);
}
} }

View File

@ -5,66 +5,46 @@ import ch.zhaw.hexboard.HexBoard;
import ch.zhaw.hexboard.Label; import ch.zhaw.hexboard.Label;
import java.awt.*; import java.awt.*;
import java.util.*;
import java.util.List; import java.util.List;
import java.util.*;
public class SiedlerBoard extends HexBoard<Land, String, String, String> { public class SiedlerBoard extends HexBoard<Land, Settlement, Road, String> {
Map<Point, ch.zhaw.hexboard.Label> lowerFieldLabel = new HashMap<>(); Map<Point, Field> fields = new HashMap<>();
public void createFixGamefield(){ public void createFixGamefield(){
Integer[][] waterCoordinates = {{4,2},{6,2},{8,2},{10,2},{3,5},{11,5},{2,8},{12,8},{1,11}, Map<Point,Land> resourcePlacement = Config.getStandardLandPlacement();
{13,11},{2,14},{12,14},{3,17},{11,17},{4,20},{6,20},{8,20},{10,20}}; Map<Point, Integer> dicePlacement = Config.getStandardDiceNumberPlacement();
Integer[][] desertCoordinates = {{7,11}}; for (Map.Entry<Point,Land> resourceField : resourcePlacement.entrySet()) {
Integer[][] forestCoordinates = {{5,5,6},{10,8,10},{3,11,5},{8,14,3}}; addField(resourceField.getKey(),resourceField.getValue());
Integer[][] hillCoordinates = {{5,11,9},{5,17,8},{9,17,11}}; if(dicePlacement.get(resourceField.getKey()) != null){
Integer[][] fieldCoordinates = {{4,8,2},{8,8,5},{11,11,9},{4,14,10}}; String numberAsString = dicePlacement.get(resourceField.getKey()).toString();
Integer[][] pastureCoordinates = {{7,5,3},{9,5,8},{10,14,12},{7,17,4}}; char[] numbersInChar = numberAsString.toCharArray();
Integer[][] mountainCoordinates = {{6,8,4},{9,11,6},{6,14,11}}; if (numberAsString.length() < 2) {
fields.put(resourceField.getKey(), new Field(resourceField.getValue(), new Label('0', numbersInChar[0])));
placeFieldWithoutLabel(Land.WATER, waterCoordinates); }
placeFieldWithoutLabel(Land.DESERT, desertCoordinates); else {
placeFieldWithLabel(Land.FOREST, forestCoordinates); fields.put(resourceField.getKey(), new Field(resourceField.getValue(), new Label(numbersInChar[0],numbersInChar[1])));
placeFieldWithLabel(Land.HILLS, hillCoordinates); }
placeFieldWithLabel(Land.FIELDS, fieldCoordinates); }
placeFieldWithLabel(Land.PASTURE, pastureCoordinates); }
placeFieldWithLabel(Land.MOUNTAIN, mountainCoordinates);
} }
private int getDiceNumber(Point field) { private int getDiceNumber(Point field) {
Label label = lowerFieldLabel.get(field); Label label = fields.get(field).getLabel();
return Integer.parseInt(label.toString()); return Integer.parseInt(label.toString());
} }
public String getTextView () { public String getTextView () {
SiedlerBoardTextView view = new SiedlerBoardTextView(this); SiedlerBoardTextView view = new SiedlerBoardTextView(this);
for (Map.Entry<Point, Label> e : lowerFieldLabel.entrySet()) { for (Map.Entry<Point, Field> field : fields.entrySet()) {
view.setLowerFieldLabel(e.getKey(), e.getValue()); view.setLowerFieldLabel(field.getKey(), field.getValue().getLabel());
} }
return view.toString(); return view.toString();
} }
private void placeFieldWithoutLabel(Land fieldType, Integer[][] fieldCoordinates) {
for(Integer[] coordinates : fieldCoordinates) {
addField(new Point(coordinates[0], coordinates[1]), fieldType);
}
}
private void placeFieldWithLabel(Land fieldType, Integer[][] fieldInformation) {
for(Integer[] information : fieldInformation) {
addField(new Point(information[0], information[1]), fieldType);
char[] label = information[2].toString().toCharArray();
if (label.length == 1) {
lowerFieldLabel.put(new Point(information[0], information[1]), new ch.zhaw.hexboard.Label('0', label[0]));
} else {
lowerFieldLabel.put(new Point(information[0], information[1]), new Label(label[0], label[1]));
}
}
}
//TODO: Add fields, constructors and methods as you see fit. Do NOT change the signature //TODO: Add fields, constructors and methods as you see fit. Do NOT change the signature
// of the methods below. // of the methods below.
@ -77,9 +57,8 @@ public class SiedlerBoard extends HexBoard<Land, String, String, String> {
* @return the fields associated with the dice value * @return the fields associated with the dice value
*/ */
public List<Point> getFieldsForDiceValue(int dice) { public List<Point> getFieldsForDiceValue(int dice) {
//TODO: Implement.
ArrayList<Point> fields = new ArrayList<>(); ArrayList<Point> fields = new ArrayList<>();
for(Point field : lowerFieldLabel.keySet()){ for(Point field : this.fields.keySet()){
if(getDiceNumber(field) == dice){ if(getDiceNumber(field) == dice){
fields.add(field); fields.add(field);
} }
@ -87,6 +66,21 @@ public class SiedlerBoard extends HexBoard<Land, String, String, String> {
return fields; return fields;
} }
public ArrayList<Config.Resource> getResourcesforFaction(Point point, Config.Faction faction){
List <Settlement> possibleSettlementField = super.getCornersOfField(point);
ArrayList<Config.Resource> resourcesToPlayer = new ArrayList<>();
for (Structure structure : possibleSettlementField) {
if (structure.getFaction() == faction) {
resourcesToPlayer.add(fields.get(point).getResource());
if (structure instanceof City) {
resourcesToPlayer.add(fields.get(point).getResource());
}
}
}
return resourcesToPlayer;
}
/** /**
* Returns the {@link Land}s adjacent to the specified corner. * Returns the {@link Land}s adjacent to the specified corner.
* *
@ -94,7 +88,22 @@ public class SiedlerBoard extends HexBoard<Land, String, String, String> {
* @return the list with the adjacent {@link Land}s * @return the list with the adjacent {@link Land}s
*/ */
public List<Land> getLandsForCorner(Point corner) { public List<Land> getLandsForCorner(Point corner) {
//TODO: Implement. Point above = new Point(corner.x, corner.y + 2);
return Collections.emptyList(); Point below = new Point(corner.x, corner.y -2);
Land[] lands = new Land[3];
if (hasField(above)) {
lands[0] = getField(above);
lands[1] = getField(new Point(corner.x + 1, corner.y - 1));
lands[2] = getField(new Point(corner.x - 1, corner.y - 1));
}
else if (hasField(below)) {
lands[0] = getField(below);
lands[1] = getField(new Point(corner.x + 1, corner.y + 1));
lands[2] = getField(new Point(corner.x - 1, corner.y + 1));
}
else {
return Collections.emptyList();
}
return List.of(lands);
} }
} }

View File

@ -5,8 +5,9 @@ import ch.zhaw.hexboard.HexBoardTextView;
import ch.zhaw.hexboard.Label; import ch.zhaw.hexboard.Label;
import java.awt.*; import java.awt.*;
import java.util.Set;
public class SiedlerBoardTextView extends HexBoardTextView<Land, String, String, String> { public class SiedlerBoardTextView extends HexBoardTextView<Land, Settlement, Road, String> {
public SiedlerBoardTextView(SiedlerBoard board) { public SiedlerBoardTextView(SiedlerBoard board) {
super(board); super(board);

View File

@ -2,268 +2,458 @@ package ch.zhaw.catan;
import ch.zhaw.catan.Config.Faction; import ch.zhaw.catan.Config.Faction;
import ch.zhaw.catan.Config.Resource; import ch.zhaw.catan.Config.Resource;
import org.beryx.textio.TextIO;
import org.beryx.textio.TextIoFactory;
import org.beryx.textio.TextTerminal;
import java.awt.Point; import java.awt.*;
import java.util.Collections; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* This class performs all actions related to modifying the game state. * This class performs all actions related to modifying the game state.
* * <p>
* TODO: (your documentation) * TODO: (your documentation)
* *
* @author TODO * @author TODO
*
*/ */
public class SiedlerGame { public class SiedlerGame {
static final int FOUR_TO_ONE_TRADE_OFFER = 4; static final int FOUR_TO_ONE_TRADE_OFFER = 4;
static final int FOUR_TO_ONE_TRADE_WANT = 1; static final int FOUR_TO_ONE_TRADE_WANT = 1;
SiedlerBoard board; private SiedlerBoard board;
private ArrayList<Player> allPlayers;
private int winPointsForWin;
private Bank bank;
private int activePlayer;
/** /**
* Constructs a SiedlerGame game state object. * Constructs a SiedlerGame game state object.
* *
* @param winPoints the number of points required to win the game * @param winPoints the number of points required to win the game
* @param numberOfPlayers the number of players * @param numberOfPlayers the number of players
* * @throws IllegalArgumentException if winPoints is lower than
* @throws IllegalArgumentException if winPoints is lower than * three or players is not between two and four
* three or players is not between two and four */
*/ public SiedlerGame(int winPoints, int numberOfPlayers) {
public SiedlerGame(int winPoints, int numberOfPlayers) { if(winPoints < 3 || numberOfPlayers < 2 || numberOfPlayers > 4) {
board = new SiedlerBoard(); throw new IllegalArgumentException();
board.createFixGamefield(); }
} bank = new Bank();
board = new SiedlerBoard();
/** board.createFixGamefield();
* Switches to the next player in the defined sequence of players. allPlayers = new ArrayList<>();
*/ createPlayer(numberOfPlayers);
public void switchToNextPlayer() { activePlayer = 0;
// TODO: Implement this.winPointsForWin = winPoints;
}
/**
* Switches to the previous player in the defined sequence of players.
*/
public void switchToPreviousPlayer() {
// TODO: Implement
}
/**
* Returns the {@link Faction}s of the active players.
*
* <p>The order of the player's factions in the list must
* correspond to the oder in which they play.
* Hence, the player that sets the first settlement must be
* at position 0 in the list etc.
*
* <strong>Important note:</strong> The list must contain the
* factions of active players only.</p>
*
* @return the list with player's factions
*/
public List<Faction> getPlayerFactions() {
// TODO: Implement
return Collections.emptyList();
}
/**
* Returns the game board.
*
* @return the game board
*/
public SiedlerBoard getBoard() {
// TODO: Implement
return board;
}
/**
* Returns the {@link Faction} of the current player.
*
* @return the faction of the current player
*/
public Faction getCurrentPlayerFaction() {
// TODO: Implement
return null;
}
/**
* Returns how many resource cards of the specified type
* the current player owns.
*
* @param resource the resource type
* @return the number of resource cards of this type
*/
public int getCurrentPlayerResourceStock(Resource resource) {
// TODO: Implement
return 0;
}
/**
* Places a settlement in the founder's phase (phase II) of the game.
*
* <p>The placement does not cost any resource cards. If payout is
* set to true, for each adjacent resource-producing field, a resource card of the
* type of the resource produced by the field is taken from the bank (if available) and added to
* the players' stock of resource cards.</p>
*
* @param position the position of the settlement
* @param payout if true, the player gets one resource card per adjacent resource-producing field
* @return true, if the placement was successful
*/
public boolean placeInitialSettlement(Point position, boolean payout) {
// TODO: Implement
return false;
}
/**
* Places a road in the founder's phase (phase II) of the game.
* The placement does not cost any resource cards.
*
* @param roadStart position of the start of the road
* @param roadEnd position of the end of the road
* @return true, if the placement was successful
*/
public boolean placeInitialRoad(Point roadStart, Point roadEnd) {
// TODO: Implement
return false;
}
/**
* This method takes care of actions depending on the dice throw result.
*
* A key action is the payout of the resource cards to the players
* according to the payout rules of the game. This includes the
* "negative payout" in case a 7 is thrown and a player has more than
* {@link Config#MAX_CARDS_IN_HAND_NO_DROP} resource cards.
*
* If a player does not get resource cards, the list for this players'
* {@link Faction} is <b>an empty list (not null)</b>!.
*
* <p>
* The payout rules of the game take into account factors such as, the number
* of resource cards currently available in the bank, settlement types
* (settlement or city), and the number of players that should get resource
* cards of a certain type (relevant if there are not enough left in the bank).
* </p>
*
* @param dicethrow the resource cards that have been distributed to the players
* @return the resource cards added to the stock of the different players
*/
public Map<Faction, List<Resource>> throwDice(int dicethrow) {
// TODO: Implement
return null;
}
/**
* Builds a settlement at the specified position on the board.
*
* <p>The settlement can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a settlement to place on the board</li>
* <li> the specified position meets the build rules for settlements</li>
* </ul>
*
* @param position the position of the settlement
* @return true, if the placement was successful
*/
public boolean buildSettlement(Point position) {
// TODO: Implement
return false;
}
/**
* Builds a city at the specified position on the board.
*
* <p>The city can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a city to place on the board</li>
* <li> the specified position meets the build rules for cities</li>
* </ul>
*
* @param position the position of the city
* @return true, if the placement was successful
*/
public boolean buildCity(Point position) {
// TODO: OPTIONAL task - Implement
return false;
}
/**
* Builds a road at the specified position on the board.
*
* <p>The road can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a road to place on the board</li>
* <li> the specified position meets the build rules for roads</li>
* </ul>
*
* @param roadStart the position of the start of the road
* @param roadEnd the position of the end of the road
* @return true, if the placement was successful
*/
public boolean buildRoad(Point roadStart, Point roadEnd) {
// TODO: Implement
// 0.Is Edge 1. Check if Edge is empty 2. Check if One neighbors Corner is own settlement 3. Set road
boolean validTask = true;
while (validTask) {
validTask = board.hasEdge(roadStart,roadEnd);
validTask = board.getEdge(roadStart,roadEnd) == null;
} }
return false; private void createPlayer(int numberOfPlayers) {
} for (int i = 0; i < numberOfPlayers; i++) {
allPlayers.add(new Player(Config.Faction.values()[i]));
}
}
/**
* Switches to the next player in the defined sequence of players.
*/
public void switchToNextPlayer() {
if (activePlayer < allPlayers.size() -1){
activePlayer++;
}
else if (activePlayer == allPlayers.size() -1){
activePlayer = 0;
}
}
/**
* Switches to the previous player in the defined sequence of players.
*/
public void switchToPreviousPlayer() {
if (activePlayer > 0){
activePlayer--;
}
else if (activePlayer == 0){
activePlayer = allPlayers.size()-1;
}
}
/**
* Returns the {@link Faction}s of the active players.
*
* <p>The order of the player's factions in the list must
* correspond to the oder in which they play.
* Hence, the player that sets the first settlement must be
* at position 0 in the list etc.
*
* <strong>Important note:</strong> The list must contain the
* factions of active players only.</p>
*
* @return the list with player's factions
*/
public List<Faction> getPlayerFactions() {
List<Faction> factions = new ArrayList<>();
for (Player player: allPlayers ) {
factions.add(player.getFaction());
}
return factions;
}
/** /**
* Trades in {@link #FOUR_TO_ONE_TRADE_OFFER} resource cards of the * Returns the game board.
* offered type for {@link #FOUR_TO_ONE_TRADE_WANT} resource cards of the wanted type. *
* * @return the game board
* The trade only works when bank and player possess the resource cards */
* for the trade before the trade is executed. public SiedlerBoard getBoard() {
* return board;
* @param offer offered type }
* @param want wanted type
* @return true, if the trade was successful
*/
public boolean tradeWithBankFourToOne(Resource offer, Resource want) {
// TODO: Implement
return false;
}
/** /**
* Returns the winner of the game, if any. * Returns the {@link Faction} of the current player.
* *
* @return the winner of the game or null, if there is no winner (yet) * @return the faction of the current player
*/ */
public Faction getWinner() { public Faction getCurrentPlayerFaction() {
// TODO: Implement return allPlayers.get(activePlayer).getFaction();
return null; }
}
/**
* Returns how many resource cards of the specified type
* the current player owns.
*
* @param resource the resource type
* @return the number of resource cards of this type
*/
public int getCurrentPlayerResourceStock(Resource resource) {
return allPlayers.get(activePlayer).getSpecificResource(resource);
}
public HashMap<Resource, Integer> getCurruntPlayerResource() {
return allPlayers.get(activePlayer).getResources();
}
/**
* Places a settlement in the founder's phase (phase II) of the game.
*
* <p>The placement does not cost any resource cards. If payout is
* set to true, for each adjacent resource-producing field, a resource card of the
* type of the resource produced by the field is taken from the bank (if available) and added to
* the players' stock of resource cards.</p>
*
* @param position the position of the settlement
* @param payout if true, the player gets one resource card per adjacent resource-producing field
* @return true, if the placement was successful
*/
public boolean placeInitialSettlement(Point position, boolean payout) {
// TODO: Implement
if(!validPositionForSettlement(position)){
return false;
}
board.setCorner(position, new Settlement(allPlayers.get(activePlayer).getFaction()));
List<Config.Land> lands = board.getLandsForCorner(position);
for (Config.Land land:lands){
allPlayers.get(activePlayer).addResource(land.getResource(), 1);
}
return true;
}
/**
* Places a road in the founder's phase (phase II) of the game.
* The placement does not cost any resource cards.
*
* @param roadStart position of the start of the road
* @param roadEnd position of the end of the road
* @return true, if the placement was successful
*/
public boolean placeInitialRoad(Point roadStart, Point roadEnd) {
// TODO: Implement
if (!validPositionForRoad(roadStart, roadEnd)){
return false;
}
board.setEdge(roadStart, roadEnd, new Road(allPlayers.get(activePlayer).getFaction()));
return true;
}
/**
* This method takes care of actions depending on the dice throw result.
* <p>
* A key action is the payout of the resource cards to the players
* according to the payout rules of the game. This includes the
* "negative payout" in case a 7 is thrown and a player has more than
* {@link Config#MAX_CARDS_IN_HAND_NO_DROP} resource cards.
* <p>
* If a player does not get resource cards, the list for this players'
* {@link Faction} is <b>an empty list (not null)</b>!.
*
* <p>
* The payout rules of the game take into account factors such as, the number
* of resource cards currently available in the bank, settlement types
* (settlement or city), and the number of players that should get resource
* cards of a certain type (relevant if there are not enough left in the bank).
* </p>
*
* @param dicethrow the resource cards that have been distributed to the players
* @return the resource cards added to the stock of the different players
*/
public Map<Faction, List<Resource>> throwDice(int dicethrow) {
Map<Faction,List<Resource>> returnMap= new HashMap<>();
List<Point> diceValueFields = board.getFieldsForDiceValue(dicethrow);
for (Player player : allPlayers) {
returnMap.put(player.getFaction(), new ArrayList());
for (Point field : diceValueFields) {
List<Resource> resources= board.getResourcesforFaction(field,player.getFaction());
for (Config.Resource resource : resources){
returnMap.get(player.getFaction()).add(resource);
player.addResource(resource,1);
}
}
}
return returnMap;
}
/**
* Builds a settlement at the specified position on the board.
*
* <p>The settlement can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a settlement to place on the board</li>
* <li> the specified position meets the build rules for settlements</li>
* </ul>
*
* @param position the position of the settlement
* @return true, if the placement was successful
*/
public boolean buildSettlement(Point position) {
//1. Check if position is corner && is empty && neighbour Corners are empty
if(!validPositionForSettlement(position)) {
return false;
}
//2. Check if neighbourEdge are Roads belong to active Player
if(!checkAdjacentEdgesList(position)) {
return false;
}
//3. Can Player build Settlement
if (!allPlayers.get(activePlayer).buildSettlement()) {
return false;
}
//4. Insert Settlement to map
board.setCorner(position, new Settlement(allPlayers.get(activePlayer).getFaction()));
//5. Give Resources to bank
bank.storeResourceToBank(Config.Structure.SETTLEMENT.getCosts());
return true;
}
/**
* Builds a city at the specified position on the board.
*
* <p>The city can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a city to place on the board</li>
* <li> the specified position meets the build rules for cities</li>
* </ul>
*
* @param position the position of the city
* @return true, if the placement was successful
*/
public boolean buildCity(Point position) {
// TODO: OPTIONAL task - Implement
//1. Check if Corner.
if (!board.hasCorner(position)){
return false;
}
//2. Check if Settlement has already been built
Settlement atCurrentPosition = board.getCorner(position);
if (atCurrentPosition == null){
return false;
}
//3. Can player build a City.
if(!allPlayers.get(activePlayer).buildCity()){
return false;
}
//4.Insert City into the map.
board.setCorner(position,new City(allPlayers.get(activePlayer).getFaction()));
//5. Give resources to the bank.
bank.storeResourceToBank(Config.Structure.CITY.getCosts());
return false;
}
/**
* Builds a road at the specified position on the board.
*
* <p>The road can be built if:
* <ul>
* <li> the player possesses the required resource cards</li>
* <li> a road to place on the board</li>
* <li> the specified position meets the build rules for roads</li>
* </ul>
*
* @param roadStart the position of the start of the road
* @param roadEnd the position of the end of the road
* @return true, if the placement was successful
*/
public boolean buildRoad(Point roadStart, Point roadEnd) {
//1. Check if is edge && is empty && if neighbour Edge or Corners belong to Settlement of active Player
if (!validPositionForRoad(roadStart,roadEnd)){
return false;
}
//2. Can Player build road
if (!allPlayers.get(activePlayer).buildRoad()) {
// TODO: Error message
return false;
}
//3. Insert Road to map
board.setEdge(roadStart, roadEnd, new Road(allPlayers.get(activePlayer).getFaction()));
//4. Give Resource to bank
bank.storeResourceToBank(Config.Structure.ROAD.getCosts());
return true;
}
/** /**
* Places the thief on the specified field and steals a random resource card (if * Can be used for both initial Settlement and normal Phase.
* the player has such cards) from a random player with a settlement at that * @param roadStart
* field (if there is a settlement) and adds it to the resource cards of the * @param roadEnd
* current player. * @return
* */
* @param field the field on which to place the thief private boolean validPositionForRoad(Point roadStart, Point roadEnd){
* @return false, if the specified field is not a field or the thief cannot be //1. Check if Edge
* placed there (e.g., on water) if (!board.hasEdge(roadStart, roadEnd)) {
*/ return false;
public boolean placeThiefAndStealCard(Point field) { }
//TODO: Implement (or longest road functionality) //2. Check if Edge is empty
return false; if (board.getEdge(roadStart, roadEnd) != null) {
} return false;
}
//3. Check if NeighbourEdge are Roads
boolean hasNeighbourRoad = (checkAdjacentEdgesList(roadStart) || checkAdjacentEdgesList(roadEnd));
//4.Check if roadStart or roadEnd is Settlement of current player or if 3. is valid
if(board.getCorner(roadStart).getFaction() == allPlayers.get(activePlayer).getFaction()
|| board.getCorner(roadEnd).getFaction() == allPlayers.get(activePlayer).getFaction()
|| hasNeighbourRoad){
return true;
}
return false;
}
/**
* Can be used for both initial Settlement and normal Phase.
* @param position
* @return
*/
private boolean validPositionForSettlement(Point position){
//1. Check if Corner
if (!board.hasCorner(position)) {
return false;
}
//2. Check if Corner is empty
if(board.getCorner(position) != null) {
return false;
}
//3. Check if neighbourCorners are empty
if(!checkAdjacentCornerList(position)) {
return false;
}
return true;
}
/**
* This method checks if there are Roads build by active Player on adjacent edges
* @param point
* @return
*/
private boolean checkAdjacentEdgesList(Point point) {
List<Road> results = board.getAdjacentEdges(point);
for(int i = 0; i < results.size(); i++) {
if(results.get(i).getFaction() == allPlayers.get(activePlayer).getFaction()) {
return true;
}
}
return false;
}
/**
* Checks if Adjacent Corners are empty
* @param point Corner to check
* @return true if all Neighbour Corners are emtpy
*/
private boolean checkAdjacentCornerList(Point point) {
List<Settlement> results = board.getNeighboursOfCorner(point);
if(results.size() > 0) {
return false;
}
return true;
}
/**
* Trades in {@link #FOUR_TO_ONE_TRADE_OFFER} resource cards of the
* offered type for {@link #FOUR_TO_ONE_TRADE_WANT} resource cards of the wanted type.
* <p>
* The trade only works when bank and player possess the resource cards
* for the trade before the trade is executed.
*
* @param offer offered type
* @param want wanted type
* @return true, if the trade was successful
*/
public boolean tradeWithBankFourToOne(Resource offer, Resource want) {
return bank.tradeWithBank(want, offer, FOUR_TO_ONE_TRADE_WANT, FOUR_TO_ONE_TRADE_OFFER);
}
/**
* Returns the winner of the game, if any.
*
* @return the winner of the game or null, if there is no winner (yet)
*/
public Faction getWinner() {
if(getCurrentPlayerWinpoints() >= winPointsForWin){
return getCurrentPlayerFaction();
}
return null;
}
public int getCurrentPlayerWinpoints(){
int winPoints = 0;
List<Settlement> settlements = board.getCorners();
for(Structure structure : settlements) {
int newWinPoints = 0;
if(structure instanceof City){
newWinPoints = 2;
} else if(structure instanceof Settlement) {
newWinPoints = 1;
}
if(structure.getFaction() == getCurrentPlayerFaction()){
winPoints ++;
}
}
if(getLongestRoadFaction() == getCurrentPlayerFaction()){
winPoints = winPoints + 2;
}
return winPoints;
}
private Faction getLongestRoadFaction() {
return null; //todo implement
}
/**
* Places the thief on the specified field and steals a random resource card (if
* the player has such cards) from a random player with a settlement at that
* field (if there is a settlement) and adds it to the resource cards of the
* current player.
*
* @param field the field on which to place the thief
* @return false, if the specified field is not a field or the thief cannot be
* placed there (e.g., on water)
*/
public boolean placeThiefAndStealCard(Point field) {
//TODO: Implement (or longest road functionality)
return false;
}
} }

View File

@ -0,0 +1,17 @@
package ch.zhaw.catan;
public abstract class Structure {
private Config.Faction faction;
public Structure(Config.Faction faction) {
this.faction = faction;
}
public String toString() {
return faction.toString();
}
public Config.Faction getFaction() {
return faction;
}
}

View File

@ -98,7 +98,7 @@ import java.util.Map;
public class HexBoardTextView<F, C, E, A> { public class HexBoardTextView<F, C, E, A> {
private static final String ONE_SPACE = " "; private static final String ONE_SPACE = " ";
private static final String TWO_SPACES = " "; private static final String TWO_SPACES = " ";
private static final String FOUR_SPACES = " "; private static final String FOUR_SPACES = " ";
private static final String FIVE_SPACES = " "; private static final String FIVE_SPACES = " ";
private static final String SIX_SPACES = " "; private static final String SIX_SPACES = " ";