Skip to content

Method: createGameBuilder(InputProvider)

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel24-Ssp.
5: *
6: * Ipspiel24-Ssp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
7: * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
8: * version.
9: *
10: * Ipspiel24-Ssp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12: *
13: * You should have received a copy of the GNU General Public License along with ipspiel24-Ssp. If not, see
14: * <http://www.gnu.org/licenses/>.
15: */
16: package de.fhdw.gaming.ipspiel24.ssp.domain.impl;
17:
18: import java.util.ArrayList;
19: import java.util.LinkedHashMap;
20: import java.util.LinkedHashSet;
21: import java.util.List;
22: import java.util.Map;
23: import java.util.Optional;
24: import java.util.Set;
25: import java.util.regex.Pattern;
26:
27: import de.fhdw.gaming.core.domain.GameBuilder;
28: import de.fhdw.gaming.core.domain.GameBuilderFactory;
29: import de.fhdw.gaming.core.domain.GameException;
30: import de.fhdw.gaming.core.domain.Strategy;
31: import de.fhdw.gaming.core.ui.InputProvider;
32: import de.fhdw.gaming.core.ui.InputProviderException;
33: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
34: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
35: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
36: import de.fhdw.gaming.ipspiel24.ssp.domain.SspGameBuilder;
37: import de.fhdw.gaming.ipspiel24.ssp.domain.SspGameBuilderFactory;
38: import de.fhdw.gaming.ipspiel24.ssp.domain.SspPlayer;
39: import de.fhdw.gaming.ipspiel24.ssp.domain.SspPlayerBuilder;
40: import de.fhdw.gaming.ipspiel24.ssp.domain.SspStrategy;
41: import de.fhdw.gaming.ipspiel24.ssp.domain.factory.SspDefaultStrategyFactoryProvider;
42: import de.fhdw.gaming.ipspiel24.ssp.domain.factory.SspStrategyFactory;
43: import de.fhdw.gaming.ipspiel24.ssp.domain.factory.SspStrategyFactoryProvider;
44: import de.fhdw.gaming.ipspiel24.ssp.moves.factory.SspMoveFactory;
45: import de.fhdw.gaming.ipspiel24.ssp.moves.impl.SspDefaultMoveFactory;
46: import de.fhdw.gaming.ipspiel24.ssp.domain.SspPossibleChoice;
47:
48: /**
49: * Implements {@link GameBuilderFactory} by creating a Ssp game builder.
50: */
51: public final class SspGameBuilderFactoryImpl implements SspGameBuilderFactory {
52:
53: /**
54: * The number of players.
55: */
56: private static final int NUMBER_OF_PLAYERS = 2;
57: /**
58: * Smallest allowed maximum computation time per move in seconds.
59: */
60: private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
61: /**
62: * Largest allowed maximum computation time per move in seconds.
63: */
64: private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
65:
66: /**
67: * All available Ssp strategies.
68: */
69: private final Set<SspStrategy> strategies;
70:
71: /**
72: * Creates a Ssp game factory. Ssp strategies are loaded by using the {@link java.util.ServiceLoader}.
73: * <p>
74: * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
75: */
76: public SspGameBuilderFactoryImpl() {
77: this(new SspDefaultStrategyFactoryProvider());
78: }
79:
80: /**
81: * Creates a Ssp game factory.
82: *
83: * @param strategyFactoryProvider The {@link SspStrategyFactoryProvider} for loading Ssp strategies.
84: */
85: SspGameBuilderFactoryImpl(final SspStrategyFactoryProvider strategyFactoryProvider) {
86: final SspMoveFactory moveFactory = new SspDefaultMoveFactory();
87:
88: final List<SspStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
89: this.strategies = new LinkedHashSet<>();
90: for (final SspStrategyFactory factory : factories) {
91: this.strategies.add(factory.create(moveFactory));
92: }
93: }
94:
95: @Override
96: public String getName() {
97: return "Ssp";
98: }
99:
100: @Override
101: public int getMinimumNumberOfPlayers() {
102: return SspGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
103: }
104:
105: @Override
106: public int getMaximumNumberOfPlayers() {
107: return SspGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
108: }
109:
110: @Override
111: public List<? extends Strategy<?, ?, ?>> getStrategies() {
112: return new ArrayList<>(this.strategies);
113: }
114:
115: @Override
116: public SspGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
117: try {
118: final SspGameBuilder gameBuilder = new SspGameBuilderImpl();
119:
120: @SuppressWarnings("unchecked")
121: final Map<String,
122: Object> gameData = inputProvider.needInteger(
123: GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
124: "Maximum computation time per move in seconds",
125: Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
126: new MinValueValidator<>(SspGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
127: new MaxValueValidator<>(SspGameBuilderFactoryImpl.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
128: .requestData("Game properties");
129:
130: gameBuilder.changeMaximumComputationTimePerMove(
131: (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
132:
133: final InputProvider firstPlayerInputProvider = inputProvider.getNext(gameData);
134: final Map<String, Object> firstPlayerData = this.requestPlayerData(firstPlayerInputProvider, "Player 1");
135: final SspPlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), firstPlayerData);
136: final SspStrategy firstPlayerStrategy = this.getStrategy(firstPlayerData);
137: gameBuilder.addPlayer(firstPlayer, firstPlayerStrategy);
138:
139: final InputProvider secondPlayerInputProvider = firstPlayerInputProvider.getNext(firstPlayerData);
140: final Map<String, Object> secondPlayerData = this.requestPlayerData(secondPlayerInputProvider, "Player 2");
141: final SspPlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), secondPlayerData);
142: final SspStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
143: gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
144:
145: return gameBuilder;
146: } catch (final InputProviderException e) {
147: throw new GameException(String.format("Creating Ssp game was aborted: %s", e.getMessage()), e);
148: }
149: }
150:
151: /**
152: * Returns data for a player builder.
153: *
154: * @param inputProvider The input provider.
155: * @param title The title for the UI.
156: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
157: * dialog).
158: */
159: @SuppressWarnings("unchecked")
160: private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title)
161: throws GameException, InputProviderException {
162:
163: inputProvider
164: .needString(
165: GameBuilderFactory.PARAM_PLAYER_NAME,
166: "Name",
167: Optional.empty(),
168: new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
169: .needInteger(
170: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_ROCK,
171: "Player's outcome on Rock/Rock",
172: Optional.of(0))
173: .needInteger(
174: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_PAPER,
175: "Player's outcome on Rock/Paper",
176: Optional.of(-1))
177: .needInteger(
178: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_SCISSORS,
179: "Player's outcome on Rock/Scissors",
180: Optional.of(1))
181: .needInteger(
182: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_ROCK,
183: "Player's outcome on Paper/Rock",
184: Optional.of(1))
185: .needInteger(
186: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_PAPER,
187: "Player's outcome on Paper/Paper",
188: Optional.of(0))
189: .needInteger(
190: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_SCISSORS,
191: "Player's outcome on Paper/Scissors",
192: Optional.of(-1))
193: .needInteger(
194: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCISSORS_ROCK,
195: "Player's outcome on Scissors/Rock",
196: Optional.of(-1))
197: .needInteger(
198: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCISSORS_PAPER,
199: "Player's outcome on Scissors/Paper",
200: Optional.of(1))
201: .needInteger(
202: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SC_SC,
203: "Player's outcome on Scissors/Scissors",
204: Optional.of(0))
205: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
206:
207: return inputProvider.requestData(title);
208: }
209:
210: /**
211: * Creates a Ssp player.
212: *
213: * @param playerBuilder The player builder.
214: * @param playerData The requested player data.
215: * @return The created {@link SspPlayer}.
216: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
217: * dialog).
218: */
219: private SspPlayer createPlayer(final SspPlayerBuilder playerBuilder,
220: final Map<String, Object> playerData) throws GameException, InputProviderException {
221:
222: final Map<SspPossibleChoice, Map<SspPossibleChoice, Double>> possibleOutcomes = new LinkedHashMap<>();
223:
224: final Map<SspPossibleChoice, Double> possibleOutcomesRock = new LinkedHashMap<>();
225: possibleOutcomesRock.put(
226: SspPossibleChoice.SPC_ROCK,
227: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_ROCK));
228: possibleOutcomesRock.put(
229: SspPossibleChoice.SPC_PAPER,
230: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_PAPER));
231: possibleOutcomesRock.put(
232: SspPossibleChoice.SPC_SCISSORS,
233: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_ROCK_SCISSORS));
234: possibleOutcomes.put(SspPossibleChoice.SPC_ROCK, possibleOutcomesRock);
235:
236: final Map<SspPossibleChoice, Double> possibleOutcomesPaper = new LinkedHashMap<>();
237: possibleOutcomesPaper.put(
238: SspPossibleChoice.SPC_ROCK,
239: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_ROCK));
240: possibleOutcomesPaper.put(
241: SspPossibleChoice.SPC_PAPER,
242: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_PAPER));
243: possibleOutcomesPaper.put(
244: SspPossibleChoice.SPC_SCISSORS,
245: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_PAPER_SCISSORS));
246: possibleOutcomes.put(SspPossibleChoice.SPC_PAPER, possibleOutcomesPaper);
247:
248: final Map<SspPossibleChoice, Double> possibleOutcomesScissors = new LinkedHashMap<>();
249: possibleOutcomesScissors.put(
250: SspPossibleChoice.SPC_ROCK,
251: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCISSORS_ROCK));
252: possibleOutcomesScissors.put(
253: SspPossibleChoice.SPC_PAPER,
254: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SCISSORS_PAPER));
255: possibleOutcomesScissors.put(
256: SspPossibleChoice.SPC_SCISSORS,
257: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_ON_SC_SC));
258: possibleOutcomes.put(SspPossibleChoice.SPC_SCISSORS, possibleOutcomesScissors);
259:
260: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
261: .changePossibleOutcomes(possibleOutcomes).build();
262: }
263:
264: /**
265: * Returns a Ssp strategy.
266: *
267: * @param playerData The requested player data.
268: * @return The Ssp strategy.
269: */
270: private SspStrategy getStrategy(final Map<String, Object> playerData) {
271: return (SspStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
272: }
273: }