Skip to contentMethod: DilemmaGameBuilderFactory()
      1: package de.fhdw.gaming.ipspiel23.dilemma.domain.internals;
2: 
3: import java.util.ArrayList;
4: import java.util.LinkedHashMap;
5: import java.util.LinkedHashSet;
6: import java.util.List;
7: import java.util.Map;
8: import java.util.Optional;
9: import java.util.Set;
10: import java.util.regex.Pattern;
11: 
12: import de.fhdw.gaming.core.domain.GameBuilder;
13: import de.fhdw.gaming.core.domain.GameBuilderFactory;
14: import de.fhdw.gaming.core.domain.GameException;
15: import de.fhdw.gaming.core.domain.Strategy;
16: import de.fhdw.gaming.core.ui.InputProvider;
17: import de.fhdw.gaming.core.ui.InputProviderException;
18: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
19: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
20: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
21: import de.fhdw.gaming.ipspiel23.dilemma.domain.DilemmaAnswerType;
22: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaGameBuilder;
23: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaGameBuilderFactory;
24: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaPlayer;
25: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaPlayerBuilder;
26: import de.fhdw.gaming.ipspiel23.dilemma.domain.IDilemmaStrategy;
27: import de.fhdw.gaming.ipspiel23.dilemma.moves.IDilemmaMoveFactory;
28: import de.fhdw.gaming.ipspiel23.dilemma.moves.internals.DilemmaDefaultMoveFactory;
29: import de.fhdw.gaming.ipspiel23.dilemma.strategy.DilemmaDefaultStrategyFactoryProvider;
30: import de.fhdw.gaming.ipspiel23.dilemma.strategy.IDilemmaStrategyFactory;
31: import de.fhdw.gaming.ipspiel23.dilemma.strategy.IDilemmaStrategyFactoryProvider;
32: 
33: /**
34:  * Implements {@link GameBuilderFactory} by creating a Dilemma game builder.
35:  */
36: public final class DilemmaGameBuilderFactory implements IDilemmaGameBuilderFactory {
37: 
38:     /**
39:      * Number of players.
40:      */
41:     private static final int MIN_MAX_NUMBER_OF_PLAYERS = 2;
42:     /**
43:      * Smallest allowed maximum computation time per move in seconds.
44:      */
45:     private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
46:     /**
47:      * Largest allowed maximum computation time per move in seconds.
48:      */
49:     private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
50:     /**
51:      * All available Dilemma strategies.
52:      */
53:     private final Set<IDilemmaStrategy> strategies;
54: 
55:     /**
56:      * Creates a Dilemma game factory. Dilemma strategies are loaded by using the {@link java.util.ServiceLoader}.
57:      * <p>
58:      * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
59:      */
60:     public DilemmaGameBuilderFactory() {
61:         this(new DilemmaDefaultStrategyFactoryProvider());
62:     }
63: 
64:     /**
65:      * Creates a Dilemma game factory.
66:      *
67:      * @param strategyFactoryProvider The {@link IDilemmaStrategyFactoryProvider} for loading Dilemma strategies.
68:      */
69:     DilemmaGameBuilderFactory(final IDilemmaStrategyFactoryProvider strategyFactoryProvider) {
70:         final IDilemmaMoveFactory moveFactory = new DilemmaDefaultMoveFactory();
71: 
72:         final List<IDilemmaStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
73:         this.strategies = new LinkedHashSet<>();
74:         for (final IDilemmaStrategyFactory factory : factories) {
75:             this.strategies.add(factory.create(moveFactory));
76:         }
77:     }
78: 
79:     @Override
80:     public String getName() {
81:         return "Gefangenen-Dilemma";
82:     }
83: 
84:     @Override
85:     public int getMinimumNumberOfPlayers() {
86:         return DilemmaGameBuilderFactory.MIN_MAX_NUMBER_OF_PLAYERS;
87:     }
88: 
89:     @Override
90:     public int getMaximumNumberOfPlayers() {
91:         return DilemmaGameBuilderFactory.MIN_MAX_NUMBER_OF_PLAYERS;
92:     }
93: 
94:     @Override
95:     public List<? extends Strategy<?, ?, ?>> getStrategies() {
96:         return new ArrayList<>(this.strategies);
97:     }
98: 
99:     @Override
100:     public IDilemmaGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
101:         try {
102:             final IDilemmaGameBuilder gameBuilder = new DilemmaGameBuilder();
103: 
104:             @SuppressWarnings("unchecked")
105:             final Map<String, Object> gameData = inputProvider
106:                 .needInteger(
107:                     GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
108:                     "Maximum computation time per move in seconds ",
109:                     Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
110:                     new MinValueValidator<>(DilemmaGameBuilderFactory.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
111:                     new MaxValueValidator<>(DilemmaGameBuilderFactory.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
112:                 .requestData("Game properties");
113: 
114:             /**
115:              * Changes the Computation time per Move according to the input of the player.
116:              */
117:             gameBuilder.changeMaximumComputationTimePerMove(
118:                 (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
119: 
120:             final InputProvider firstPlayerInputProvider = inputProvider.getNext(gameData);
121:             final Map<String, Object> firstPlayerData = this.requestPlayerData(firstPlayerInputProvider, "Player 1");
122:             final IDilemmaPlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), firstPlayerData);
123:             final IDilemmaStrategy firstPlayerStrategy = this.getStrategy(firstPlayerData);
124:             gameBuilder.addPlayer(firstPlayer, firstPlayerStrategy);
125: 
126:             final InputProvider secondPlayerInputProvider = firstPlayerInputProvider.getNext(firstPlayerData);
127:             final Map<String, Object> secondPlayerData = this.requestPlayerData(secondPlayerInputProvider, "Player 2");
128:             final IDilemmaPlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), secondPlayerData);
129:             final IDilemmaStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
130:             gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
131: 
132:             return gameBuilder;
133:         } catch (final InputProviderException e) {
134:             throw new GameException(String.format("Creating Dilemma game was aborted: %s", e.getMessage()), e);
135:         }
136:     }
137: 
138: 
139:     /**
140:      * Returns data for a player builder.
141:      *
142:      * @param inputProvider The input provider.
143:      * @param title         The title for the UI.
144:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
145:      *                                dialog).
146:      */
147:     @SuppressWarnings("unchecked")
148:     private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title)
149:             throws GameException, InputProviderException {
150: 
151:         inputProvider
152:             .needString(
153:                 GameBuilderFactory.PARAM_PLAYER_NAME,
154:                 "Name",
155:                 Optional.empty(),
156:                 new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
157:             .needInteger(
158:                 IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_COOPERATE_COOPERATE,
159:                 "Player's outcome on cooperate/cooperate",
160:                 Optional.of(IDilemmaGameBuilder.DEFAULT_OUTCOME_COOPERATE_COOPERATE))
161:             .needInteger(
162:                 IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_COOPERATE_DEFECT,
163:                 "Player's outcome on cooperate/defect",
164:                 Optional.of(IDilemmaGameBuilder.DEFAULT_OUTCOME_COOPERATE_DEFECT))
165:             .needInteger(
166:                 IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_DEFECT_COOPERATE,
167:                 "Player's outcome on defect/cooperate",
168:                 Optional.of(IDilemmaGameBuilder.DEFAULT_OUTCOME_DEFECT_COOPERATE))
169:             .needInteger(
170:                 IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_DEFECT_DEFECT,
171:                 "Player's outcome on defect/defect",
172:                 Optional.of(IDilemmaGameBuilder.DEFAULT_OUTCOME_DEFECT_DEFECT))
173:             .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
174: 
175:         return inputProvider.requestData(title);
176:     }
177: 
178:     /**
179:      * Creates a Dilemma player.
180:      *
181:      * @param playerBuilder The player builder.
182:      * @param playerData    The requested player data.
183:      * @return The created {@link IDilemmaPlayer}.
184:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
185:      *                                dialog).
186:      */
187:     private IDilemmaPlayer createPlayer(final IDilemmaPlayerBuilder playerBuilder,
188:             final Map<String, Object> playerData) throws GameException, InputProviderException {
189: 
190:         final Map<DilemmaAnswerType, Map<DilemmaAnswerType, Double>> possibleOutcomes = new LinkedHashMap<>();
191: 
192:         final Map<DilemmaAnswerType, Double> possibleOutcomesNo = new LinkedHashMap<>();
193:         possibleOutcomesNo.put(
194:             DilemmaAnswerType.COOPERATE,
195:             (double) (Integer) playerData
196:                 .get(IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_COOPERATE_COOPERATE));
197:         possibleOutcomesNo.put(
198:             DilemmaAnswerType.DEFECT,
199:             (double) (Integer) playerData
200:                 .get(IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_COOPERATE_DEFECT));
201:         possibleOutcomes.put(DilemmaAnswerType.COOPERATE, possibleOutcomesNo);
202: 
203:         final Map<DilemmaAnswerType, Double> possibleOutcomesYes = new LinkedHashMap<>();
204:         possibleOutcomesYes.put(
205:             DilemmaAnswerType.COOPERATE,
206:             (double) (Integer) playerData
207:                 .get(IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_DEFECT_COOPERATE));
208:         possibleOutcomesYes.put(
209:             DilemmaAnswerType.DEFECT,
210:             (double) (Integer) playerData
211:                 .get(IDilemmaGameBuilderFactory.PARAM_OUTCOME_ON_DEFECT_DEFECT));
212:         possibleOutcomes.put(DilemmaAnswerType.DEFECT, possibleOutcomesYes);
213: 
214:         return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
215:             .changePossibleOutcomes(possibleOutcomes).build();
216:     }
217: 
218:     /**
219:      * Returns a Dilemma strategy.
220:      *
221:      * @param playerData The requested player data.
222:      * @return The Dilemma strategy.
223:      */
224:     private IDilemmaStrategy getStrategy(final Map<String, Object> playerData) {
225:         return (IDilemmaStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
226:     }
227: }