Skip to contentMethod: getStrategies()
      1: package de.schereSteinPapier.domain.impl;
2: 
3: import static de.schereSteinPapier.SSPConstants.AuswahlConstants.PAPIER;
4: import static de.schereSteinPapier.SSPConstants.AuswahlConstants.SCHERE;
5: import static de.schereSteinPapier.SSPConstants.AuswahlConstants.STEIN;
6: 
7: import java.util.ArrayList;
8: import java.util.LinkedHashMap;
9: import java.util.LinkedHashSet;
10: import java.util.List;
11: import java.util.Map;
12: import java.util.Optional;
13: import java.util.Set;
14: import java.util.regex.Pattern;
15: 
16: import de.fhdw.gaming.core.domain.GameBuilder;
17: import de.fhdw.gaming.core.domain.GameBuilderFactory;
18: import de.fhdw.gaming.core.domain.GameException;
19: import de.fhdw.gaming.core.domain.Strategy;
20: import de.fhdw.gaming.core.ui.InputProvider;
21: import de.fhdw.gaming.core.ui.InputProviderException;
22: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
23: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
24: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
25: import de.schereSteinPapier.domain.SSPGameBuilder;
26: import de.schereSteinPapier.domain.SSPGameBuilderFactory;
27: import de.schereSteinPapier.domain.SSPPlayer;
28: import de.schereSteinPapier.domain.SSPPlayerBuilder;
29: import de.schereSteinPapier.domain.SSPStrategy;
30: import de.schereSteinPapier.domain.factory.SSPDefaultStrategyFactoryProvider;
31: import de.schereSteinPapier.domain.factory.SSPStrategyFactory;
32: import de.schereSteinPapier.domain.factory.SSPStrategyFactoryProvider;
33: import de.schereSteinPapier.moves.factory.SSPMoveFactory;
34: import de.schereSteinPapier.moves.impl.SSPDefaultMoveFactory;
35: 
36: /**
37:  * Implements {@link SSPGameBuilderFactory} by creating a SSP game builder.
38:  */
39: public final class SSPGameBuilderFactoryImpl implements SSPGameBuilderFactory {
40: 
41:     /**
42:      * The number of players.
43:      */
44:     private static final int NUMBER_OF_PLAYERS = 2;
45:     /**
46:      * Smallest allowed maximum computation time per move in seconds.
47:      */
48:     private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
49:     /**
50:      * Largest allowed maximum computation time per move in seconds.
51:      */
52:     private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
53: 
54:     /**
55:      * All available SSP strategies.
56:      */
57:     private final Set<SSPStrategy> strategies;
58: 
59:     /**
60:      * Creates a SSP game factory. SSP strategies are loaded by using the {@link java.util.ServiceLoader}.
61:      * <p>
62:      * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
63:      */
64:     public SSPGameBuilderFactoryImpl() {
65:         this(new SSPDefaultStrategyFactoryProvider());
66:     }
67: 
68:     /**
69:      * Creates a SSP game factory.
70:      *
71:      * @param strategyFactoryProvider The {@link SSPStrategyFactoryProvider} for loading SSP strategies.
72:      */
73:     SSPGameBuilderFactoryImpl(final SSPStrategyFactoryProvider strategyFactoryProvider) {
74:         final SSPMoveFactory moveFactory = new SSPDefaultMoveFactory();
75: 
76:         final List<SSPStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
77:         this.strategies = new LinkedHashSet<>();
78:         for (final SSPStrategyFactory factory : factories) {
79:             this.strategies.add(factory.create(moveFactory));
80:         }
81:     }
82: 
83:     @Override
84:     public String getName() {
85:         return "SSP";
86:     }
87: 
88:     @Override
89:     public int getMinimumNumberOfPlayers() {
90:         return SSPGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
91:     }
92: 
93:     @Override
94:     public int getMaximumNumberOfPlayers() {
95:         return SSPGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
96:     }
97: 
98:     @Override
99:     public List<? extends Strategy<?, ?, ?>> getStrategies() {
100:         return new ArrayList<>(this.strategies);
101:     }
102: 
103:     @Override
104:     public SSPGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
105:         try {
106:             final SSPGameBuilder gameBuilder = new SSPGameBuilderImpl();
107: 
108:             @SuppressWarnings("unchecked")
109:             final Map<String,
110:                     Object> gameData = inputProvider.needInteger(
111:                             GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
112:                             "Maximum computation time per move in seconds",
113:                             Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
114:                             new MinValueValidator<>(SSPGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
115:                             new MaxValueValidator<>(SSPGameBuilderFactoryImpl.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
116:                             .requestData("Game properties");
117: 
118:             gameBuilder.changeMaximumComputationTimePerMove(
119:                     (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
120: 
121:             final InputProvider firstPlayerInputProvider = inputProvider.getNext(gameData);
122:             final Map<String, Object> firstPlayerData = this.requestPlayerData(firstPlayerInputProvider, "Player 1");
123:             final SSPPlayer firstPlayer = this
124:                     .createPlayer(gameBuilder.createPlayerBuilder(), firstPlayerData);
125:             final SSPStrategy firstPlayerStrategy = this.getStrategy(firstPlayerData);
126:             gameBuilder.addPlayer(firstPlayer, firstPlayerStrategy);
127: 
128:             final InputProvider secondPlayerInputProvider = firstPlayerInputProvider.getNext(firstPlayerData);
129:             final Map<String, Object> secondPlayerData = this.requestPlayerData(secondPlayerInputProvider, "Player 2");
130:             final SSPPlayer secondPlayer = this
131:                     .createPlayer(gameBuilder.createPlayerBuilder(), secondPlayerData);
132:             final SSPStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
133:             gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
134: 
135:             return gameBuilder;
136:         } catch (final InputProviderException e) {
137:             throw new GameException(String.format("Creating Demo game was aborted: %s", e.getMessage()), e);
138:         }
139:     }
140: 
141:     /**
142:      * Returns data for a player builder.
143:      *
144:      * @param inputProvider The input provider.
145:      * @param title         The title for the UI.
146:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
147:      *                                dialog).
148:      */
149:     @SuppressWarnings("unchecked")
150:     private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title)
151:             throws GameException, InputProviderException {
152:         if (title.equals("Player 1")) {
153:             inputProvider
154:                     .needString(
155:                             GameBuilderFactory.PARAM_PLAYER_NAME,
156:                             "Name",
157:                             Optional.empty(),
158:                             new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
159:                     .needInteger(
160:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_SCHERE,
161:                             "Player's outcome on Schere/Schere",
162:                             Optional.of(0))
163:                     .needInteger(
164:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_STEIN,
165:                             "Player's outcome on Schere/Stein",
166:                             Optional.of(-1))
167:                     .needInteger(
168:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_PAPIER,
169:                             "Player's outcome on Schere/Papier",
170:                             Optional.of(1))
171:                     .needInteger(
172:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_SCHERE,
173:                             "Player's outcome on Stein/Schere",
174:                             Optional.of(1))
175:                     .needInteger(
176:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_STEIN,
177:                             "Player's outcome on Stein/Stein",
178:                             Optional.of(0))
179:                     .needInteger(
180:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_PAPIER,
181:                             "Player's outcome on Stein/Papier",
182:                             Optional.of(-1))
183:                     .needInteger(
184:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_SCHERE,
185:                             "Player's outcome on Papier/Schere",
186:                             Optional.of(-1))
187:                     .needInteger(
188:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_STEIN,
189:                             "Player's outcome on Papier/Stein",
190:                             Optional.of(1))
191:                     .needInteger(
192:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_PAPIER,
193:                             "Player's outcome on Papier/Papier",
194:                             Optional.of(0))
195:                     .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy",
196:                             Optional.empty(), this.strategies);
197:         } else {
198:             inputProvider
199:                     .needString(
200:                             GameBuilderFactory.PARAM_PLAYER_NAME,
201:                             "Name",
202:                             Optional.empty(),
203:                             new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
204:                     .needInteger(
205:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_SCHERE,
206:                             "Player's outcome on Schere/Schere",
207:                             Optional.of(0))
208:                     .needInteger(
209:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_STEIN,
210:                             "Player's outcome on Schere/Stein",
211:                             Optional.of(1))
212:                     .needInteger(
213:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_PAPIER,
214:                             "Player's outcome on Schere/Papier",
215:                             Optional.of(-1))
216:                     .needInteger(
217:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_SCHERE,
218:                             "Player's outcome on Stein/Schere",
219:                             Optional.of(-1))
220:                     .needInteger(
221:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_STEIN,
222:                             "Player's outcome on Stein/Stein",
223:                             Optional.of(0))
224:                     .needInteger(
225:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_PAPIER,
226:                             "Player's outcome on Stein/Papier",
227:                             Optional.of(1))
228:                     .needInteger(
229:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_SCHERE,
230:                             "Player's outcome on Papier/Schere",
231:                             Optional.of(1))
232:                     .needInteger(
233:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_STEIN,
234:                             "Player's outcome on Papier/Stein",
235:                             Optional.of(-1))
236:                     .needInteger(
237:                             SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_PAPIER,
238:                             "Player's outcome on Papier/Papier",
239:                             Optional.of(0))
240:                     .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy",
241:                             Optional.empty(), this.strategies);
242:         }
243:         return inputProvider.requestData(title);
244:     }
245: 
246:     /**
247:      * Creates a SSP player.
248:      *
249:      * @param playerBuilder The player builder.
250:      * @param playerData    The requested player data.
251:      * @return The created {@link SSPPlayer}.
252:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
253:      *                                dialog).
254:      */
255:     private SSPPlayer createPlayer(final SSPPlayerBuilder playerBuilder,
256:             final Map<String, Object> playerData) throws GameException, InputProviderException {
257: 
258:         final Map<String, Map<String, Double>> possibleOutcomes = new LinkedHashMap<>();
259: 
260:         final Map<String, Double> possibleOutcomesSchere = new LinkedHashMap<>();
261:         possibleOutcomesSchere.put(
262:                 SCHERE,
263:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_SCHERE));
264:         possibleOutcomesSchere.put(
265:                 STEIN,
266:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_STEIN));
267:         possibleOutcomesSchere.put(
268:                 PAPIER,
269:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCHERE_PAPIER));
270:         possibleOutcomes.put(SCHERE, possibleOutcomesSchere);
271: 
272:         final Map<String, Double> possibleOutcomesStein = new LinkedHashMap<>();
273:         possibleOutcomesStein.put(
274:                 SCHERE,
275:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_SCHERE));
276:         possibleOutcomesStein.put(
277:                 STEIN,
278:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_STEIN));
279:         possibleOutcomesStein.put(
280:                 PAPIER,
281:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_STEIN_PAPIER));
282:         possibleOutcomes.put(STEIN, possibleOutcomesStein);
283: 
284:         final Map<String, Double> possibleOutcomesPapier = new LinkedHashMap<>();
285:         possibleOutcomesPapier.put(
286:                 SCHERE,
287:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_SCHERE));
288:         possibleOutcomesPapier.put(
289:                 STEIN,
290:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_STEIN));
291:         possibleOutcomesPapier.put(
292:                 PAPIER,
293:                 (double) (Integer) playerData.get(SSPGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPIER_PAPIER));
294:         possibleOutcomes.put(PAPIER, possibleOutcomesPapier);
295: 
296:         return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
297:                 .changePossibleOutcomes(possibleOutcomes).build();
298:     }
299: 
300:     /**
301:      * Returns a SSP strategy.
302:      *
303:      * @param playerData The requested player data.
304:      * @return The SSP strategy.
305:      */
306:     private SSPStrategy getStrategy(final Map<String, Object> playerData) {
307:         return (SSPStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
308:     }
309: }