Skip to content

Method: getStrategies()

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel23-Ssp.
5: *
6: * Ipspiel23-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: * Ipspiel23-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 ipspiel23-Ssp. If not, see
14: * <http://www.gnu.org/licenses/>.
15: */
16: package de.fhdw.gaming.ipspiel23.ssp.domain.impl;
17:
18: import de.fhdw.gaming.core.domain.GameBuilder;
19: import de.fhdw.gaming.core.domain.GameBuilderFactory;
20: import de.fhdw.gaming.core.domain.GameException;
21: import de.fhdw.gaming.core.domain.Strategy;
22: import de.fhdw.gaming.core.ui.InputProvider;
23: import de.fhdw.gaming.core.ui.InputProviderException;
24: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
25: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
26: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
27: import de.fhdw.gaming.ipspiel23.ssp.domain.SspGameBuilder;
28: import de.fhdw.gaming.ipspiel23.ssp.domain.SspGameBuilderFactory;
29: import de.fhdw.gaming.ipspiel23.ssp.domain.SspPlayer;
30: import de.fhdw.gaming.ipspiel23.ssp.domain.SspPlayerBuilder;
31: import de.fhdw.gaming.ipspiel23.ssp.domain.SspStrategy;
32: import de.fhdw.gaming.ipspiel23.ssp.domain.factory.SspDefaultStrategyFactoryProvider;
33: import de.fhdw.gaming.ipspiel23.ssp.domain.factory.SspStrategyFactory;
34: import de.fhdw.gaming.ipspiel23.ssp.domain.factory.SspStrategyFactoryProvider;
35: import de.fhdw.gaming.ipspiel23.ssp.domain.impl.outcomes.SspAnswer;
36: import de.fhdw.gaming.ipspiel23.ssp.moves.factory.SspMoveFactory;
37: import de.fhdw.gaming.ipspiel23.ssp.moves.impl.SspDefaultMoveFactory;
38:
39: import java.util.ArrayList;
40: import java.util.LinkedHashMap;
41: import java.util.LinkedHashSet;
42: import java.util.List;
43: import java.util.Map;
44: import java.util.Optional;
45: import java.util.Set;
46: import java.util.regex.Pattern;
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_STONE_STONE,
171: "Player's outcome on Stone/Stone",
172: Optional.of(0))
173: .needInteger(
174: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_STONE_SCISSORS,
175: "Player's outcome on Stone/Scissors",
176: Optional.of(1))
177: .needInteger(
178: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_STONE_PAPER,
179: "Player's outcome on Stone/Paper",
180: Optional.of(-1))
181: .needInteger(
182: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_PAPER,
183: "Player's outcome on Paper/Paper",
184: Optional.of(0))
185: .needInteger(
186: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_SCISSORS,
187: "Player's outcome on Paper/Scissors",
188: Optional.of(-1))
189: .needInteger(
190: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_STONE,
191: "Player's outcome on Paper/Stone",
192: Optional.of(1))
193: .needInteger(
194: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_PAPER,
195: "Player's outcome on Scissors/Paper",
196: Optional.of(1))
197: .needInteger(
198: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_STONE,
199: "Player's outcome on Scissors/Stone",
200: Optional.of(-1))
201: .needInteger(
202: SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_SCISSORS,
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<SspAnswer, Map<SspAnswer, Double>> possibleOutcomes = new LinkedHashMap<>();
223:
224: final Map<SspAnswer, Double> possibleOutcomesStone = new LinkedHashMap<>();
225: possibleOutcomesStone.put(
226: SspAnswer.PAPER,
227: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_STONE_PAPER));
228: possibleOutcomesStone.put(
229: SspAnswer.STONE,
230: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_STONE_STONE));
231: possibleOutcomesStone.put(
232: SspAnswer.SCISSORS,
233: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_STONE_SCISSORS));
234:
235: possibleOutcomes.put(SspAnswer.STONE, possibleOutcomesStone);
236:
237: final Map<SspAnswer, Double> possibleOutcomesPaper = new LinkedHashMap<>();
238: possibleOutcomesPaper.put(
239: SspAnswer.PAPER,
240: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_PAPER));
241: possibleOutcomesPaper.put(
242: SspAnswer.STONE,
243: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_STONE));
244: possibleOutcomesPaper.put(
245: SspAnswer.SCISSORS,
246: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_PAPER_SCISSORS));
247:
248: possibleOutcomes.put(SspAnswer.PAPER, possibleOutcomesPaper);
249:
250: final Map<SspAnswer, Double> possibleOutcomesScissors = new LinkedHashMap<>();
251: possibleOutcomesScissors.put(
252: SspAnswer.STONE,
253: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_STONE));
254: possibleOutcomesScissors.put(
255: SspAnswer.PAPER,
256: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_PAPER));
257: possibleOutcomesScissors.put(
258: SspAnswer.SCISSORS,
259: (double) (Integer) playerData.get(SspGameBuilderFactory.PARAM_PLAYER_OUTCOME_SCISSORS_SCISSORS));
260:
261: possibleOutcomes.put(SspAnswer.SCISSORS, possibleOutcomesScissors);
262:
263: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
264: .changePossibleOutcomes(possibleOutcomes).build();
265: }
266:
267: /**
268: * Returns a Ssp strategy.
269: *
270: * @param playerData The requested player data.
271: * @return The Ssp strategy.
272: */
273: private SspStrategy getStrategy(final Map<String, Object> playerData) {
274: return (SspStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
275: }
276: }