Skip to contentMethod: changePossibleOutcomes(Map)
      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: }