Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package sk.uniba.fmph.dcs.game_phase_controller;

import java.util.Collection;
import java.util.Map;
import sk.uniba.fmph.dcs.stone_age.PlayerOrder;
import sk.uniba.fmph.dcs.stone_age.Location;
import sk.uniba.fmph.dcs.stone_age.ActionResult;
import sk.uniba.fmph.dcs.stone_age.HasAction;
import sk.uniba.fmph.dcs.stone_age.Effect;

/**
* Represents the game phase where players place their figures on locations.
* Only figure placement actions are valid during this phase.
*
* Note: This class does not check if it's the player's turn - that validation
* is handled by GamePhaseController before any actions are delegated here.
* This separation of concerns keeps turn management logic in one place.
*/
public class PlaceFiguresState implements InterfaceGamePhaseState {

/**
* Maps game locations to their corresponding figure placement handlers
*/
private final Map<Location, InterfaceFigureLocation> places;

/**
* Creates a new PlaceFiguresState with the given location mappings
*
* @param places Map of locations to their figure placement handlers
*/
public PlaceFiguresState(Map<Location, InterfaceFigureLocation> places) {
this.places = places;
}

/**
* Attempts to place figures at the specified location
*
* @param player The player attempting to place figures
* @param location The location where figures should be placed
* @param figuresCount Number of figures to place
* @return ACTION_DONE if placement successful, FAILURE otherwise
*/
@Override
public ActionResult placeFigures(PlayerOrder player, Location location, int figuresCount) {
InterfaceFigureLocation place = places.get(location);
if (place == null) {
return ActionResult.FAILURE;
}

return place.placeFigures(player, figuresCount)
? ActionResult.ACTION_DONE
: ActionResult.FAILURE;
}

/**
* Checks if the player can make any automatic figure placements
*
* @param player The player to check for possible actions
* @return WAITING_FOR_PLAYER_ACTION if player has figures to place,
* NO_ACTION_POSSIBLE if no figures can be placed
*/
@Override
public HasAction tryToMakeAutomaticAction(PlayerOrder player) {
for (InterfaceFigureLocation place : places.values()) {
HasAction result = place.tryToPlaceFigures(player, 1);
if (result == HasAction.WAITING_FOR_PLAYER_ACTION) {
return HasAction.WAITING_FOR_PLAYER_ACTION;
}
}
return HasAction.NO_ACTION_POSSIBLE;
}

// The following methods return FAILURE as they are not valid actions during the Place Figures phase

@Override
public ActionResult makeAction(PlayerOrder player, Location location,
Collection<Effect> inputResources, Collection<Effect> outputResources) {
return ActionResult.FAILURE;
}

@Override
public ActionResult skipAction(PlayerOrder player, Location location) {
return ActionResult.FAILURE;
}

@Override
public ActionResult useTools(PlayerOrder player, int toolIndex) {
return ActionResult.FAILURE;
}

@Override
public ActionResult noMoreToolsThisThrow(PlayerOrder player) {
return ActionResult.FAILURE;
}

@Override
public ActionResult feedTribe(PlayerOrder player, Collection<Effect> resources) {
return ActionResult.FAILURE;
}

@Override
public ActionResult doNotFeedThisTurn(PlayerOrder player) {
return ActionResult.FAILURE;
}

@Override
public ActionResult makeAllPlayersTakeARewardChoice(PlayerOrder player, Effect reward) {
return ActionResult.FAILURE;
}
}
10 changes: 10 additions & 0 deletions src/main/java/sk/uniba/fmph/dcs/stone_age/InterfaceFeedTribe.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package sk.uniba.fmph.dcs.stone_age;

import java.util.Collection;

public interface InterfaceFeedTribe {
boolean feedTribeIfEnoughFood();
boolean feedTribe(Collection<Effect> resources);
boolean doNotFeedThisTurn();
boolean isTribeFed();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sk.uniba.fmph.dcs.stone_age;

import java.util.Collection;

public interface InterfaceFigureLocation {
boolean placeFigures(PlayerOrder player, int figureCount);
HasAction tryToPlaceFigures(PlayerOrder player, int count);
ActionResult makeAction(PlayerOrder player, Collection<Effect> inputResources, Collection<Effect> outputResources);
boolean skipAction(PlayerOrder player);
HasAction tryToMakeAction(PlayerOrder player);
boolean newTurn();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sk.uniba.fmph.dcs.stone_age;

import java.util.Collection;

public interface InterfaceFigureLocationInternal {
boolean placeFigures(Player player, int figureCount);
HasAction tryToPlaceFigures(Player player, int count);
ActionResult makeAction(Player player, Collection<Effect> inputResources, Collection<Effect> outputResources);
boolean skipAction(Player player);
HasAction tryToMakeAction(Player player);
boolean newTurn();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package sk.uniba.fmph.dcs.stone_age;

public interface InterfaceNewTurn {
void newTurn();
}
6 changes: 6 additions & 0 deletions src/main/java/sk/uniba/fmph/dcs/stone_age/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package sk.uniba.fmph.dcs.stone_age;

public interface Player {
PlayerOrder playerOrder();
PlayerBoard playerBoard();
}
5 changes: 5 additions & 0 deletions src/main/java/sk/uniba/fmph/dcs/stone_age/PlayerBoard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package sk.uniba.fmph.dcs.stone_age;

public interface PlayerBoard {
boolean hasFigures(int count);
}
159 changes: 159 additions & 0 deletions src/main/java/sk/uniba/fmph/dcs/stone_age/ResourceSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package sk.uniba.fmph.dcs.stone_age;

import java.util.ArrayList;
import java.util.Collection;
import org.json.JSONObject;
import java.util.Map;

public final class ResourceSource implements InterfaceFigureLocationInternal {
private final String name;
private final Effect resource;
private final int maxFigures;
private final int maxFigureColors;
private final ArrayList<PlayerOrder> figures;

public ResourceSource(String name, Effect resource, int maxFigures, int maxFigureColors) {
if (!resource.isResourceOrFood()) {
throw new IllegalArgumentException("Resource must be food or resource");
}
this.name = name;
this.resource = resource;
this.maxFigures = maxFigures;
this.maxFigureColors = maxFigureColors;
this.figures = new ArrayList<>();
}

@Override
public boolean placeFigures(Player player, int figureCount) {
// Check if player can place figures here
if (!canPlaceFigures(player, figureCount)) {
return false;
}

// Add the figures
for (int i = 0; i < figureCount; i++) {
figures.add(player.playerOrder());
}
return true;
}

@Override
public HasAction tryToPlaceFigures(Player player, int count) {
if (!player.playerBoard().hasFigures(count)) {
return HasAction.NO_ACTION_POSSIBLE;
}

if (canPlaceFigures(player, count)) {
return HasAction.WAITING_FOR_PLAYER_ACTION;
}

return HasAction.NO_ACTION_POSSIBLE;
}

@Override
public ActionResult makeAction(Player player, Collection<Effect> inputResources,
Collection<Effect> outputResources) {
// Verify it's this player's figures
if (!hasFiguresFromPlayer(player.playerOrder())) {
return ActionResult.FAILURE;
}

// Resource sources don't take input resources
if (!inputResources.isEmpty()) {
return ActionResult.FAILURE;
}

// Resource sources must output exactly one type of resource per figure
int playerFigureCount = countPlayerFigures(player.playerOrder());
if (outputResources.size() != playerFigureCount) {
return ActionResult.FAILURE;
}

for (Effect output : outputResources) {
if (output != this.resource) {
return ActionResult.FAILURE;
}
}

return ActionResult.ACTION_DONE_WAIT_FOR_TOOL_USE;
}

@Override
public HasAction tryToMakeAction(Player player) {
if (hasFiguresFromPlayer(player.playerOrder())) {
return HasAction.WAITING_FOR_PLAYER_ACTION;
}
return HasAction.NO_ACTION_POSSIBLE;
}

@Override
public boolean skipAction(Player player) {
return false; // Can't skip resource gathering
}

@Override
public boolean newTurn() {
figures.clear();
return false; // Resource sources don't trigger game end
}

private boolean canPlaceFigures(Player player, int figureCount) {
// Check if player has enough figures
if (!player.playerBoard().hasFigures(figureCount)) {
return false;
}

// Check if space available
if (figures.size() + figureCount > maxFigures) {
return false;
}

// Check if player already has figures here
if (hasFiguresFromPlayer(player.playerOrder())) {
return false;
}

// Check number of different players
if (!figures.isEmpty() && !containsPlayerOrder(figures, player.playerOrder())) {
int currentColors = countDistinctPlayers();
if (currentColors >= maxFigureColors) {
return false;
}
}

return true;
}

private boolean hasFiguresFromPlayer(PlayerOrder player) {
return containsPlayerOrder(figures, player);
}

private int countPlayerFigures(PlayerOrder player) {
int count = 0;
for (PlayerOrder p : figures) {
if (p.equals(player)) {
count++;
}
}
return count;
}

private int countDistinctPlayers() {
return (int) figures.stream().distinct().count();
}

private boolean containsPlayerOrder(Collection<PlayerOrder> collection, PlayerOrder player) {
return collection.stream().anyMatch(p -> p.equals(player));
}

public String state() {
Map<String, Object> state = Map.of(
"name", name,
"resource", resource,
"maxFigures", maxFigures,
"maxFigureColors", maxFigureColors,
"figures", figures.stream().map(PlayerOrder::getOrder).toList()
);
return new JSONObject(state).toString();
}
}
Loading