Skip to content

Method: createGameBuilder(InputProvider)

1: package de.fhdw.gaming.ipspiel22.kopfundzahl.domain.impl;
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.ipspiel22.kopfundzahl.domain.KopfundZahlGameBuilder;
22: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.KopfundZahlGameBuilderFactory;
23: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.KopfundZahlPlayer;
24: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.KopfundZahlPlayerBuilder;
25: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.KopfundZahlStrategy;
26: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.factory.KopfundZahlDefaultStrategyFactoryProvider;
27: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.factory.KopfundZahlStrategyFactory;
28: import de.fhdw.gaming.ipspiel22.kopfundzahl.domain.factory.KopfundZahlStrategyFactoryProvider;
29: import de.fhdw.gaming.ipspiel22.kopfundzahl.moves.factory.KopfundZahlMoveFactory;
30: import de.fhdw.gaming.ipspiel22.kopfundzahl.moves.impl.DefaultKopfundZahlMoveFactory;
31:
32: /**
33: * Implements {@link KopfundZahlGameBuilderFactory} by creating a KopfundZahl game builder.
34: */
35: public final class KopfundZahlGameBuilderFactoryImpl implements KopfundZahlGameBuilderFactory {
36:
37: /**
38: * The number of players.
39: */
40: private static final int NUMBER_OF_PLAYERS = 2;
41:
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: /**
48: * Largest allowed maximum computation time per move in seconds.
49: */
50: private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
51:
52: /**
53: * All available Head and Tail strategies.
54: */
55: private final Set<KopfundZahlStrategy> strategies;
56:
57: /**
58: * Creates a Head and Tail game factory. Head and Tail strategies are loaded
59: * by using the {@link java.util.ServiceLoader}.
60: * <p>
61: * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
62: */
63: public KopfundZahlGameBuilderFactoryImpl() {
64: this(new KopfundZahlDefaultStrategyFactoryProvider());
65: }
66:
67: /**
68: * Creates a Head and Tail game factory.
69: *
70: * @param strategyFactoryProvider The {@link KopfundZahlStrategyFactoryProvider} for loading Head and
71: * Tail strategies.
72: */
73: KopfundZahlGameBuilderFactoryImpl(final KopfundZahlDefaultStrategyFactoryProvider strategyFactoryProvider) {
74: final KopfundZahlMoveFactory moveFactory = new DefaultKopfundZahlMoveFactory();
75:
76: final List<KopfundZahlStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
77: this.strategies = new LinkedHashSet<>();
78: for (final KopfundZahlStrategyFactory factory : factories) {
79: this.strategies.add(factory.create(moveFactory));
80: }
81: }
82:
83: @Override
84: public String getName() {
85: return "KopfundZahl";
86: }
87:
88: @Override
89: public int getMinimumNumberOfPlayers() {
90: return KopfundZahlGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
91: }
92:
93: @Override
94: public int getMaximumNumberOfPlayers() {
95: return KopfundZahlGameBuilderFactoryImpl.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 KopfundZahlGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
105: try {
106: final KopfundZahlGameBuilder gameBuilder = new KopfundZahlGameBuilderImpl();
107:
108: @SuppressWarnings("unchecked")
109: final Map<String, 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<>(KopfundZahlGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
114: new MaxValueValidator<>(KopfundZahlGameBuilderFactoryImpl.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 firstPlayerInputProvider = inputProvider.getNext(gameData);
121: final Map<String, Object> firstPlayerData = this.requestPlayerData(firstPlayerInputProvider, "Player 1");
122: final KopfundZahlPlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), firstPlayerData);
123: final KopfundZahlStrategy 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 KopfundZahlPlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(),
129: secondPlayerData);
130: final KopfundZahlStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
131: gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
132:
133: return gameBuilder;
134: } catch (final InputProviderException e) {
135: throw new GameException(String.format("Creating KopfundZahl game was aborted: %s", e.getMessage()), e);
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: if (title.equals("Player 1")) {
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: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_TAIL,
159: "Player's outcome on Tail/Tail",
160: Optional.of(1))
161: .needInteger(
162: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_HEAD,
163: "Player's outcome on Tail/Head",
164: Optional.of(-1))
165: .needInteger(
166: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_TAIL,
167: "Player's outcome on Head/Tail",
168: Optional.of(-1))
169: .needInteger(
170: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_HEAD,
171: "Player's outcome on Head/Head",
172: Optional.of(1))
173: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(),
174: this.strategies);
175:
176: } else {
177: inputProvider
178: .needString(
179: GameBuilderFactory.PARAM_PLAYER_NAME,
180: "Name",
181: Optional.empty(),
182: new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
183: .needInteger(
184: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_TAIL,
185: "Player's outcome on Tail/Tail",
186: Optional.of(-1))
187: .needInteger(
188: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_HEAD,
189: "Player's outcome on Tail/Head",
190: Optional.of(1))
191: .needInteger(
192: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_TAIL,
193: "Player's outcome on Head/Tail",
194: Optional.of(1))
195: .needInteger(
196: KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_HEAD,
197: "Player's outcome on Head/Head",
198: Optional.of(-1))
199: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(),
200: this.strategies);
201:
202: }
203: return inputProvider.requestData(title);
204: }
205:
206: /**
207: * Creates a KopfundZahl player.
208: *
209: * @param playerBuilder The player builder.
210: * @param playerData The requested player data.
211: * @return The created {@link KopfundZahlPlayer}.
212: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
213: * dialog).
214: */
215: private KopfundZahlPlayer createPlayer(final KopfundZahlPlayerBuilder playerBuilder,
216: final Map<String, Object> playerData) throws GameException, InputProviderException {
217:
218: final Map<Boolean, Map<Boolean, Double>> possibleOutcomes = new LinkedHashMap<>();
219:
220: final Map<Boolean, Double> possibleOutcomesNo = new LinkedHashMap<>();
221: possibleOutcomesNo.put(
222: Boolean.FALSE,
223: (double) (Integer) playerData.get(KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_TAIL));
224: possibleOutcomesNo.put(
225: Boolean.TRUE,
226: (double) (Integer) playerData.get(KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_TAIL_HEAD));
227: possibleOutcomes.put(Boolean.FALSE, possibleOutcomesNo);
228:
229: final Map<Boolean, Double> possibleOutcomesYes = new LinkedHashMap<>();
230: possibleOutcomesYes.put(
231: Boolean.FALSE,
232: (double) (Integer) playerData.get(KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_TAIL));
233: possibleOutcomesYes.put(
234: Boolean.TRUE,
235: (double) (Integer) playerData.get(KopfundZahlGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_HEAD_HEAD));
236: possibleOutcomes.put(Boolean.TRUE, possibleOutcomesYes);
237:
238: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
239: .changePossibleOutcomes(possibleOutcomes).build();
240: }
241:
242: /**
243: * Returns a KopfundZahl strategy.
244: *
245: * @param playerData The requested player data.
246: * @return The KopfundZahl strategy.
247: */
248: private KopfundZahlStrategy getStrategy(final Map<String, Object> playerData) {
249: return (KopfundZahlStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
250: }
251:
252: }