Skip to content

Method: getStrategy(Map)

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel24-tictactoe-core.
5: *
6: * ipspiel24-tictactoe-core is free software: you can redistribute it and/or modify it under
7: * the terms of the GNU General Public License as published by the Free Software
8: * Foundation, either version 3 of the License, or (at your option) any later
9: * version.
10: *
11: * ipspiel24-tictactoe-core is distributed in the hope that it will be useful, but WITHOUT
12: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14: * details.
15: *
16: * You should have received a copy of the GNU General Public License along with
17: * ipspiel24-tictactoe-core. If not, see <http://www.gnu.org/licenses/>.
18: */
19: package de.fhdw.gaming.ipspiel24.tictactoe.core.domain.impl;
20:
21: import java.util.ArrayList;
22: import java.util.LinkedHashSet;
23: import java.util.List;
24: import java.util.Map;
25: import java.util.Optional;
26: import java.util.Set;
27: import java.util.regex.Pattern;
28:
29: import de.fhdw.gaming.core.domain.GameBuilder;
30: import de.fhdw.gaming.core.domain.GameBuilderFactory;
31: import de.fhdw.gaming.core.domain.GameException;
32: import de.fhdw.gaming.core.ui.InputProvider;
33: import de.fhdw.gaming.core.ui.InputProviderException;
34: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
35: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
36: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
37: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.TicTacToeGameBuilder;
38: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.TicTacToeGameBuilderFactory;
39: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.TicTacToePlayer;
40: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.TicTacToePlayerBuilder;
41: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.TicTacToeStrategy;
42: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.factory.TicTacToeDefaultStrategyFactoryProvider;
43: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.factory.TicTacToeStrategyFactory;
44: import de.fhdw.gaming.ipspiel24.tictactoe.core.domain.factory.TicTacToeStrategyFactoryProvider;
45: import de.fhdw.gaming.ipspiel24.tictactoe.core.moves.factory.TicTacToeMoveFactory;
46: import de.fhdw.gaming.ipspiel24.tictactoe.core.moves.impl.TicTacToeDefaultMoveFactory;
47:
48: /**
49: * Implements {@link TicTacToeGameBuilderFactory} by creating a Tic Tac Toe game builder.
50: */
51: public final class TicTacToeGameBuilderFactoryImpl implements TicTacToeGameBuilderFactory {
52:
53: /**
54: * The number of players.
55: */
56: private static final int NUMBER_OF_PLAYERS = 2;
57: /**
58: * Minimum number of rows (and columns) of the board.
59: */
60: private static final int MIN_BOARD_SIZE = 3;
61: /**
62: * Maximum number of rows (and columns) of the board.
63: */
64: private static final int MAX_BOARD_SIZE = 16;
65: /**
66: * Smallest allowed maximum computation time per move in seconds.
67: */
68: private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
69: /**
70: * Largest allowed maximum computation time per move in seconds.
71: */
72: private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
73:
74: /**
75: * All available Tic Tac Toe strategies.
76: */
77: private final Set<TicTacToeStrategy> strategies;
78:
79: /**
80: * Creates an Tic Tac Toe game factory. Tic Tac Toe strategies are loaded by using the
81: * {@link java.util.ServiceLoader}.
82: * <p>
83: * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
84: */
85: public TicTacToeGameBuilderFactoryImpl() {
86: this(new TicTacToeDefaultStrategyFactoryProvider());
87: }
88:
89: /**
90: * Creates an Tic Tac Toe game factory.
91: *
92: * @param strategyFactoryProvider The {@link TicTacToeStrategyFactoryProvider} for loading Tic Tac Toe strategies.
93: */
94: public TicTacToeGameBuilderFactoryImpl(final TicTacToeStrategyFactoryProvider strategyFactoryProvider) {
95: final TicTacToeMoveFactory moveFactory = new TicTacToeDefaultMoveFactory();
96:
97: final List<TicTacToeStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
98: this.strategies = new LinkedHashSet<>();
99: for (final TicTacToeStrategyFactory factory : factories) {
100: this.strategies.add(factory.create(moveFactory));
101: }
102: }
103:
104: @Override
105: public String getName() {
106: return "TicTacToe";
107: }
108:
109: @Override
110: public int getMinimumNumberOfPlayers() {
111: return TicTacToeGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
112: }
113:
114: @Override
115: public int getMaximumNumberOfPlayers() {
116: return TicTacToeGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
117: }
118:
119: @Override
120: public List<TicTacToeStrategy> getStrategies() {
121: return new ArrayList<>(this.strategies);
122: }
123:
124: @Override
125: public TicTacToeGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
126: try {
127: final TicTacToeGameBuilder gameBuilder = new TicTacToeGameBuilderImpl();
128:
129: @SuppressWarnings("unchecked")
130: final Map<String, Object> gameData = inputProvider
131: .needInteger(
132: TicTacToeGameBuilderFactory.PARAM_BOARD_SIZE,
133: "Number of rows (and columns)",
134: Optional.of(TicTacToeGameBuilder.DEFAULT_BOARD_SIZE),
135: new MinValueValidator<>(TicTacToeGameBuilderFactoryImpl.MIN_BOARD_SIZE),
136: new MaxValueValidator<>(TicTacToeGameBuilderFactoryImpl.MAX_BOARD_SIZE))
137: .needInteger(
138: GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
139: "Maximum computation time per move in seconds",
140: Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
141: new MinValueValidator<>(TicTacToeGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
142: new MaxValueValidator<>(TicTacToeGameBuilderFactoryImpl.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
143: .requestData("Board properties");
144:
145: gameBuilder.changeBoardSize((Integer) gameData.get(TicTacToeGameBuilderFactory.PARAM_BOARD_SIZE));
146: gameBuilder.changeMaximumComputationTimePerMove(
147: (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
148:
149: final InputProvider firstPlayerInputProvider = inputProvider.getNext(gameData);
150: final Map<String, Object> firstPlayerData = this
151: .requestPlayerData(firstPlayerInputProvider, "Player 1", Optional.empty());
152: final TicTacToePlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), firstPlayerData);
153: final TicTacToeStrategy firstPlayerStrategy = this.getStrategy(firstPlayerData);
154: gameBuilder.addPlayer(firstPlayer, firstPlayerStrategy);
155:
156: final InputProvider secondPlayerInputProvider = firstPlayerInputProvider.getNext(firstPlayerData);
157: final Map<String, Object> secondPlayerData = this.requestPlayerData(
158: secondPlayerInputProvider,
159: "Player 2",
160: Optional.of(
161: !(Boolean) firstPlayerData.get(TicTacToeGameBuilderFactory.PARAM_PLAYER_USING_CROSSES)));
162: final TicTacToePlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(), secondPlayerData);
163: final TicTacToeStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
164: gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
165:
166: return gameBuilder;
167: } catch (final InputProviderException e) {
168: throw new GameException(String.format("Creating Tic Tac Toe game was aborted: %s", e.getMessage()), e);
169: }
170: }
171:
172: /**
173: * Initialises an Tic Tac Toe player builder.
174: *
175: * @param inputProvider The input provider.
176: * @param title The title for the UI.
177: * @param usingCrosses If set, determines whether the player uses crosses or noughts. Otherwise, the setting is
178: * initially set to crosses, and the user can change it at will.
179: * @return {@code playerBuilder}.
180: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
181: * dialog).
182: */
183: @SuppressWarnings("unchecked")
184: private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title,
185: final Optional<Boolean> usingCrosses) throws GameException, InputProviderException {
186:
187: inputProvider
188: .needString(
189: GameBuilderFactory.PARAM_PLAYER_NAME,
190: "Name",
191: Optional.empty(),
192: new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
193: .needBoolean(
194: TicTacToeGameBuilderFactory.PARAM_PLAYER_USING_CROSSES,
195: "Uses crosses",
196: Optional.of(Boolean.TRUE))
197: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
198:
199: if (usingCrosses.isPresent()) {
200: inputProvider.fixedBoolean(TicTacToeGameBuilderFactory.PARAM_PLAYER_USING_CROSSES, usingCrosses.get());
201: }
202:
203: return inputProvider.requestData(title);
204: }
205:
206: /**
207: * Creates an Tic Tac Toe player builder.
208: *
209: * @param playerBuilder The player builder.
210: * @param playerData The requested player data.
211: * @return {@link TicTacToePlayer}.
212: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
213: * dialog).
214: */
215: private TicTacToePlayer createPlayer(final TicTacToePlayerBuilder playerBuilder,
216: final Map<String, Object> playerData) throws GameException, InputProviderException {
217:
218: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
219: .changeUsingCrosses((Boolean) playerData.get(TicTacToeGameBuilderFactory.PARAM_PLAYER_USING_CROSSES))
220: .build();
221: }
222:
223: /**
224: * Returns an Tic Tac Toe strategy.
225: *
226: * @param playerData The requested player data.
227: * @return The Tic Tac Toe strategy.
228: */
229: private TicTacToeStrategy getStrategy(final Map<String, Object> playerData) {
230: return (TicTacToeStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
231: }
232: }