Skip to content

Method: build()

1: package de.fhdw.gaming.ipspiel23.dilemma.domain.internals;
2:
3: import java.util.Collections;
4: import java.util.HashMap;
5: import java.util.Map;
6: import java.util.Optional;
7: import java.util.function.Consumer;
8:
9: import de.fhdw.gaming.core.domain.GameException;
10: import de.fhdw.gaming.ipspiel23.dilemma.domain.DilemmaAnswerType;
11: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaPlayer;
12: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaPlayerBuilder;
13: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaStrategy;
14:
15: /**
16: * Implements {@link IDilemmaPlayerBuilder}.
17: */
18: public final class DilemmaPlayerBuilder implements IDilemmaPlayerBuilder {
19:
20: /**
21: * The name of the player.
22: */
23: private Optional<String> name;
24: /**
25: * The possible outcomes of this player. The key for the first-level map is the answer of the first player, the key
26: * for the second-level map is the answer of the second player.
27: */
28: private Optional<Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>>> possibleOutcomes;
29:
30: /**
31: * The hook that is used to inject the strategy into the player object when the player is added to the game.
32: */
33: private final Map<IDilemmaPlayer, Consumer<IDilemmaStrategy>> playerStrategyHooks;
34:
35: /**
36: * The parent game builder. Used to to register new players via callback.
37: */
38: private final DilemmaGameBuilder gameBuilder;
39:
40: /**
41: * Creates an {@link DilemmaPlayerBuilder}.
42: * @param parentBuilder the player builder that created this player instance.
43: */
44: public DilemmaPlayerBuilder(final DilemmaGameBuilder parentBuilder) {
45: this.gameBuilder = parentBuilder;
46: this.name = Optional.empty();
47: this.possibleOutcomes = Optional.empty();
48: this.playerStrategyHooks = new HashMap<>();
49: }
50:
51: @Override
52: public DilemmaPlayerBuilder changeName(final String newName) {
53: this.name = Optional.of(newName);
54: return this;
55: }
56:
57: @Override
58: public DilemmaPlayerBuilder changePossibleOutcomes(
59: final Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>> newPossibleOutcomes) {
60: this.possibleOutcomes = Optional.ofNullable(newPossibleOutcomes);
61: return this;
62: }
63:
64: @Override
65: public IDilemmaPlayer build() throws GameException {
66: final IDilemmaPlayer player = new DilemmaPlayer(
67: this,
68: this.name.orElseThrow(),
69: this.checkPossibleOutcomes(this.possibleOutcomes.orElseThrow()));
70: gameBuilder.onPlayerBuilt(this, player);
71: return player;
72: }
73:
74: /**
75: * Checks if all possible outcomes are defined for a player.
76: *
77: * @param outcomes The possible outcomes for the player.
78: */
79: private Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>> checkPossibleOutcomes(
80: final Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>> outcomes) {
81: this.checkPossibleOutcome(outcomes, DilemmaAnswerType.COOPERATE, DilemmaAnswerType.COOPERATE);
82: this.checkPossibleOutcome(outcomes, DilemmaAnswerType.COOPERATE, DilemmaAnswerType.DEFECT);
83: this.checkPossibleOutcome(outcomes, DilemmaAnswerType.DEFECT, DilemmaAnswerType.COOPERATE);
84: this.checkPossibleOutcome(outcomes, DilemmaAnswerType.DEFECT, DilemmaAnswerType.DEFECT);
85: return outcomes;
86: }
87:
88: /**
89: * Sets the hook that is used to inject the strategy into the player object when the player is added to the game.
90: *
91: * @param player The player for which the hook is registered.
92: * @param value The hook that is used to inject the strategy into the player object when the player is
93: * added to the game.
94: */
95: void registerPlayerStrategyHook(final IDilemmaPlayer player, final Consumer<IDilemmaStrategy> value) {
96: this.playerStrategyHooks.put(player, value);
97: }
98:
99: /**
100: * Injects the strategy into the player object.
101: *
102: * @param player The player object that is injected with the strategy.
103: * @param strategy The strategy that is injected into the player object.
104: */
105: void injectPlayerStrategyUsingHook(final IDilemmaPlayer player, final IDilemmaStrategy strategy) {
106: final Consumer<IDilemmaStrategy> playerStrategyHook = playerStrategyHooks.getOrDefault(player, null);
107: if (playerStrategyHook == null) {
108: throw new IllegalStateException("Attempted to inject strategy into player object before "
109: + "hook was configured!");
110: }
111: // we don't want to expose the strategy setter to anyone, so it's done via this
112: // hook kindly provided to us by the player constructor.
113: playerStrategyHook.accept(strategy);
114: playerStrategyHooks.remove(player);
115: }
116:
117: /**
118: * Checks if a given outcome is defined for a player.
119: * Public for testing.
120: *
121: * @param outcomes The possible outcomes for the player.
122: * @param firstChoice The choice of the first player.
123: * @param secondChoice The choice of the second player.
124: */
125: void checkPossibleOutcome(
126: final Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>> outcomes,
127: final DilemmaAnswerType firstChoice,
128: final DilemmaAnswerType secondChoice) throws IllegalArgumentException {
129: if (outcomes == null || outcomes.getOrDefault(firstChoice, Collections.emptyMap()).get(secondChoice) == null) {
130: throw new IllegalArgumentException(
131: String.format("No outcome defined for player '%s' and combination %s/%s.",
132: this.name.orElse("Unnamed Player"),
133: firstChoice.toString(),
134: secondChoice.toString()));
135: }
136: }
137: }