Skip to contentMethod: getStrategy(Map)
      1: package de.fhdw.gaming.ipspiel23.ht.domain.impl;
2: 
3: import java.util.ArrayList;
4: import java.util.HashSet;
5: import java.util.LinkedHashMap;
6: import java.util.LinkedHashSet;
7: import java.util.List;
8: import java.util.Map;
9: import java.util.Optional;
10: import java.util.Set;
11: import java.util.regex.Pattern;
12: 
13: import de.fhdw.gaming.core.domain.GameBuilder;
14: import de.fhdw.gaming.core.domain.GameBuilderFactory;
15: import de.fhdw.gaming.core.domain.GameException;
16: import de.fhdw.gaming.core.domain.Strategy;
17: import de.fhdw.gaming.core.ui.InputProvider;
18: import de.fhdw.gaming.core.ui.InputProviderException;
19: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
20: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
21: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
22: import de.fhdw.gaming.core.ui.type.validator.ValueSetValidator;
23: import de.fhdw.gaming.ipspiel23.ht.domain.Answer;
24: import de.fhdw.gaming.ipspiel23.ht.domain.IHTGameBuilder;
25: import de.fhdw.gaming.ipspiel23.ht.domain.IHTGameBuilderFactory;
26: import de.fhdw.gaming.ipspiel23.ht.domain.IHTPlayer;
27: import de.fhdw.gaming.ipspiel23.ht.domain.IHTPlayerBuilder;
28: import de.fhdw.gaming.ipspiel23.ht.moves.factory.HTDefaultMoveFactory;
29: import de.fhdw.gaming.ipspiel23.ht.moves.factory.IHTMoveFactory;
30: import de.fhdw.gaming.ipspiel23.ht.strategy.IHTStrategy;
31: import de.fhdw.gaming.ipspiel23.ht.strategy.IHTStrategyFactory;
32: import de.fhdw.gaming.ipspiel23.ht.strategy.factory.HTDefaultStrategyFactoryProvider;
33: import de.fhdw.gaming.ipspiel23.ht.strategy.factory.IHTStrategyFactoryProvider;
34: 
35: /**
36:  * Represents a factory for game builder instances.
37:  */
38: public final class HTGameBuilderFactory implements IHTGameBuilderFactory {
39: 
40:     /**
41:      * The number of players.
42:      */
43:     private static final int NUMBER_OF_PLAYERS = 2;
44: 
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:     /**
51:      * Largest allowed maximum computation time per move in seconds.
52:      */
53:     private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
54: 
55:     /**
56:      * The available strategies.
57:      */
58:     private final Set<IHTStrategy> strategies;
59: 
60:     /**
61:      * Creates a new instance of {@link HTGameBuilderFactory}.
62:      */
63:     public HTGameBuilderFactory() {
64:         this(new HTDefaultStrategyFactoryProvider());
65:     }
66: 
67:     /**
68:      * Creates a new instance of {@link HTGameBuilderFactory}.
69:      *
70:      * @param provider The provider for the strategy factories.
71:      */
72:     public HTGameBuilderFactory(final IHTStrategyFactoryProvider provider) {
73:         final IHTMoveFactory moveFactory = new HTDefaultMoveFactory();
74: 
75:         final List<IHTStrategyFactory> factories = provider.getStrategyFactories();
76:         this.strategies = new LinkedHashSet<>();
77:         for (final IHTStrategyFactory factory : factories) {
78:             this.strategies.add(factory.create(moveFactory));
79:         }
80:     }
81: 
82:     @Override
83:     public String getName() {
84:         return "Heads or Tails";
85:     }
86: 
87:     @Override
88:     public int getMinimumNumberOfPlayers() {
89:         return NUMBER_OF_PLAYERS;
90:     }
91: 
92:     @Override
93:     public int getMaximumNumberOfPlayers() {
94:         return NUMBER_OF_PLAYERS;
95:     }
96: 
97:     @Override
98:     public List<? extends Strategy<?, ?, ?>> getStrategies() {
99:         return new ArrayList<>(this.strategies);
100:     }
101: 
102:     @Override
103:     public IHTGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
104:         try {
105:             final IHTGameBuilder gameBuilder = new HTGameBuilder();
106: 
107:             @SuppressWarnings("unchecked")
108:             final Map<String,
109:                 Object> gameData = inputProvider.needInteger(
110:                     GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
111:                     "Maximum computation time per move in seconds",
112:                     Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
113:                     new MinValueValidator<>(HTGameBuilderFactory.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
114:                     new MaxValueValidator<>(HTGameBuilderFactory.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
115:                     .requestData("Game properties");
116: 
117:             gameBuilder.changeMaximumComputationTimePerMove(
118:                     (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
119: 
120:             final InputProvider playerInputProvider1 = inputProvider.getNext(gameData);
121:             final Map<String, Object> playerData1 = this.requestPlayerData(playerInputProvider1, "Player 1", 1);
122:             final IHTPlayer player1 = this.createPlayer(gameBuilder.createPlayerBuilder(), playerData1);
123:             final IHTStrategy playerStrategy1 = this.getStrategy(playerData1);
124:             gameBuilder.addPlayer(player1, playerStrategy1);
125: 
126:             final InputProvider playerInputProvider2 = playerInputProvider1.getNext(playerData1);
127:             final Map<String, Object> playerData2 = this.requestPlayerData(playerInputProvider2, "Player 2", -1);
128:             final IHTPlayer player2 = this.createPlayer(gameBuilder.createPlayerBuilder(), playerData2);
129:             final IHTStrategy playerStrategy2 = this.getStrategy(playerData2);
130:             gameBuilder.addPlayer(player2, playerStrategy2);
131: 
132:             if (player1.getPossibleOutcomes().equals(player2.getPossibleOutcomes())) {
133:                 throw new GameException("Players cannot bet on the same outcome!");
134:             }
135:             
136:             return gameBuilder;
137:         } catch (final InputProviderException e) {
138:             throw new GameException(String.format("Creating HT game was aborted: %s", e.getMessage()), e);
139:         }
140:     }
141: 
142:     /**
143:      * Returns data for a player builder.
144:      *
145:      * @param inputProvider The input provider.
146:      * @param title         The title for the UI.
147:      * @param defaultValueFactor   The factor to be multiplied with the outcomes (allows easily inverting outcomes
148:      * /pre-filling input provider stuff)
149:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
150:      *                                dialog).
151:      */
152:     @SuppressWarnings("unchecked")
153:     private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title, 
154:             final int defaultValueFactor)
155:             throws GameException, InputProviderException {
156:         final Set<Integer> allowedOutcomeValues = new HashSet<>();
157:         allowedOutcomeValues.add(1);
158:         allowedOutcomeValues.add(-1);
159:         
160:         final ValueSetValidator<Integer> outcomeValidator = new ValueSetValidator<>(allowedOutcomeValues);
161:         
162:         inputProvider
163:             .needString(
164:                 GameBuilderFactory.PARAM_PLAYER_NAME,
165:                 "Name",
166:                 Optional.empty(),
167:                 new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
168:             .needInteger(
169:                 PARAM_PLAYER_OUTCOME_EQUAL,
170:                 "Player's outcome on equal sides (HH/TT/EE)",
171:                 Optional.of(1 * defaultValueFactor),
172:                 outcomeValidator)
173:             .needInteger(
174:                 PARAM_PLAYER_OUTCOME_DIFFERENT,
175:                 "Player's outcome on different sides (HT/HE/TH/TE/EH/ET)",
176:                 Optional.of(-1 * defaultValueFactor),
177:                 outcomeValidator)
178:             .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
179: 
180:         return inputProvider.requestData(title);
181:     }
182: 
183:     /**
184:      * Creates a HT player.
185:      *
186:      * @param playerBuilder The player builder.
187:      * @param playerData    The requested player data.
188:      * @return The created {@link IHTPlayer}.
189:      * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
190:      *                                dialog).
191:      */
192:     private IHTPlayer createPlayer(final IHTPlayerBuilder playerBuilder,
193:             final Map<String, Object> playerData) throws GameException, InputProviderException {
194:         final double equalOutcome = (double) (Integer) playerData.get(PARAM_PLAYER_OUTCOME_EQUAL);
195:         final double differentOutcome = (double) (Integer) playerData.get(PARAM_PLAYER_OUTCOME_DIFFERENT);
196:         
197:         if (equalOutcome == differentOutcome) {
198:             throw new GameException("Outcomes for equal and different sides must not be identical.");
199:         }
200:         
201:         final Map<Answer, Map<Answer, Double>> possibleOutcomes = new LinkedHashMap<>();
202:         
203:         final Map<Answer, Double> possibleOutcomesHeads = new LinkedHashMap<>();
204:         possibleOutcomesHeads.put(Answer.HEADS, equalOutcome);
205:         possibleOutcomesHeads.put(Answer.TAILS, differentOutcome);
206:         possibleOutcomesHeads.put(Answer.EDGE, differentOutcome);
207:         possibleOutcomes.put(Answer.HEADS, possibleOutcomesHeads);
208: 
209:         final Map<Answer, Double> possibleOutcomesTails = new LinkedHashMap<>();
210:         possibleOutcomesTails.put(Answer.HEADS, differentOutcome);
211:         possibleOutcomesTails.put(Answer.TAILS, equalOutcome);
212:         possibleOutcomesTails.put(Answer.EDGE, differentOutcome);
213:         possibleOutcomes.put(Answer.TAILS, possibleOutcomesTails);
214:         
215:         final Map<Answer, Double> possibleOutcomesEdge = new LinkedHashMap<>();
216:         possibleOutcomesEdge.put(Answer.HEADS, differentOutcome);
217:         possibleOutcomesEdge.put(Answer.TAILS, differentOutcome);
218:         possibleOutcomesEdge.put(Answer.EDGE, equalOutcome);
219:         possibleOutcomes.put(Answer.EDGE, possibleOutcomesEdge);
220: 
221:         return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
222:             .changePossibleOutcomes(possibleOutcomes).build();
223:     }
224: 
225:     /**
226:      * Returns a HT strategy.
227:      *
228:      * @param playerData The requested player data.
229:      * @return The HT strategy.
230:      */
231:     private IHTStrategy getStrategy(final Map<String, Object> playerData) {
232:         return (IHTStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
233:     }
234: }