Skip to content

Method: getStrategies()

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel24-VierConnects-core.
5: *
6: * ipspiel24-VierConnects-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-VierConnects-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-VierConnects-core. If not, see <http://www.gnu.org/licenses/>.
18: */
19: package de.fhdw.gaming.ipspiel24.VierConnects.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.domain.Strategy;
33: import de.fhdw.gaming.core.ui.InputProvider;
34: import de.fhdw.gaming.core.ui.InputProviderException;
35: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
36: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
37: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
38: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsGameBuilder;
39: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsGameBuilderFactory;
40: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPlayer;
41: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPlayerBuilder;
42: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsStrategy;
43: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.factory.VierConnectsDefaultStrategyFactoryProvider;
44: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.factory.VierConnectsStrategyFactory;
45: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.factory.VierConnectsStrategyFactoryProvider;
46: import de.fhdw.gaming.ipspiel24.VierConnects.core.moves.factory.VierConnectsMoveFactory;
47: import de.fhdw.gaming.ipspiel24.VierConnects.core.moves.impl.VierConnectsDefaultMoveFactory;
48:
49: /**
50: * Implements {@link VierConnectsGameBuilderFactory} by creating a Vier Connects game builder.
51: */
52: public final class VierConnectsGameBuilderFactoryImpl implements VierConnectsGameBuilderFactory {
53:
54: /**
55: * The number of players.
56: */
57: private static final int NUMBER_OF_PLAYERS = 2;
58: /**
59: * Minimum number of rows of the board.
60: */
61: private static final int MIN_NR_OF_ROWS = 4;
62: /**
63: * Maximum number of rows of the board.
64: */
65: private static final int MAX_NR_OF_ROWS = 16;
66: /**
67: * Minimum number of columns of the board.
68: */
69: private static final int MIN_NR_OF_COLUMNS = 5;
70: /**
71: * Maximum number of columns of the board.
72: */
73: private static final int MAX_NR_OF_COLUMNS = 16;
74: /**
75: * Smallest allowed maximum computation time per move in seconds.
76: */
77: private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
78: /**
79: * Largest allowed maximum computation time per move in seconds.
80: */
81: private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
82:
83: /**
84: * All available Vier Connects strategies.
85: */
86: private final Set<VierConnectsStrategy> strategies;
87:
88: /**
89: * Creates an Vier Connects game factory. Vier Connects strategies are loaded by using the
90: * {@link java.util.ServiceLoader}.
91: * <p>
92: * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
93: */
94: public VierConnectsGameBuilderFactoryImpl() {
95: this(new VierConnectsDefaultStrategyFactoryProvider());
96: }
97:
98: /**
99: * Creates an Vier Connects game factory.
100: *
101: * @param strategyFactoryProvider The {@link VierConnectsStrategyFactoryProvider} for loading Vier Connects
102: * strategies.
103: */
104: public VierConnectsGameBuilderFactoryImpl(final VierConnectsStrategyFactoryProvider strategyFactoryProvider) {
105: final VierConnectsMoveFactory moveFactory = new VierConnectsDefaultMoveFactory();
106:
107: final List<VierConnectsStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
108: this.strategies = new LinkedHashSet<>();
109: for (final VierConnectsStrategyFactory factory : factories) {
110: this.strategies.add(factory.create(moveFactory));
111: }
112: }
113:
114: @Override
115: public String getName() {
116: return "VierConnects";
117: }
118:
119: @Override
120: public int getMinimumNumberOfPlayers() {
121: return VierConnectsGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
122: }
123:
124: @Override
125: public int getMaximumNumberOfPlayers() {
126: return VierConnectsGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
127: }
128:
129: @Override
130: public List<? extends Strategy<?, ?, ?>> getStrategies() {
131: return new ArrayList<>(this.strategies);
132: }
133:
134: @Override
135: public VierConnectsGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
136: try {
137: final VierConnectsGameBuilder gameBuilder = new VierConnectsGameBuilderImpl();
138:
139: @SuppressWarnings("unchecked")
140: final Map<String, Object> gameData = inputProvider
141: .needInteger(
142: VierConnectsGameBuilderFactory.PARAM_NR_OF_ROWS,
143: "Number of rows",
144: Optional.of(VierConnectsGameBuilder.DEFAULT_NR_OF_ROWS),
145: new MinValueValidator<>(VierConnectsGameBuilderFactoryImpl.MIN_NR_OF_ROWS),
146: new MaxValueValidator<>(VierConnectsGameBuilderFactoryImpl.MAX_NR_OF_ROWS))
147: .needInteger(
148: VierConnectsGameBuilderFactory.PARAM_NR_OF_COLUMNS,
149: "Number of columns",
150: Optional.of(VierConnectsGameBuilder.DEFAULT_NR_OF_COLUMNS),
151: new MinValueValidator<>(VierConnectsGameBuilderFactoryImpl.MIN_NR_OF_COLUMNS),
152: new MaxValueValidator<>(VierConnectsGameBuilderFactoryImpl.MAX_NR_OF_COLUMNS))
153: .needInteger(
154: GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
155: "Maximum computation time per move in seconds",
156: Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
157: new MinValueValidator<>(
158: VierConnectsGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
159: new MaxValueValidator<>(
160: VierConnectsGameBuilderFactoryImpl.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
161: .requestData("Board properties");
162:
163: gameBuilder.changeBoardSize((Integer) gameData.get(VierConnectsGameBuilderFactory.PARAM_NR_OF_ROWS),
164: (Integer) gameData.get(VierConnectsGameBuilderFactory.PARAM_NR_OF_COLUMNS));
165: gameBuilder.changeMaximumComputationTimePerMove(
166: (Integer) gameData.get(GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE));
167:
168: final InputProvider firstPlayerInputProvider = inputProvider.getNext(gameData);
169: final Map<String, Object> firstPlayerData = this
170: .requestPlayerData(firstPlayerInputProvider, "Player 1", Optional.empty());
171: final VierConnectsPlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(),
172: firstPlayerData);
173: final VierConnectsStrategy firstPlayerStrategy = this.getStrategy(firstPlayerData);
174: gameBuilder.addPlayer(firstPlayer, firstPlayerStrategy);
175:
176: final InputProvider secondPlayerInputProvider = firstPlayerInputProvider.getNext(firstPlayerData);
177: final Map<String, Object> secondPlayerData = this.requestPlayerData(
178: secondPlayerInputProvider,
179: "Player 2",
180: Optional.of(
181: !(Boolean) firstPlayerData.get(VierConnectsGameBuilderFactory.PARAM_PLAYER_USING_CROSSES)));
182: final VierConnectsPlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(),
183: secondPlayerData);
184: final VierConnectsStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
185: gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
186:
187: return gameBuilder;
188: } catch (final InputProviderException e) {
189: throw new GameException(String.format("Creating Vier Connects game was aborted: %s", e.getMessage()), e);
190: }
191: }
192:
193: /**
194: * Initialises an Vier Connects player builder.
195: *
196: * @param inputProvider The input provider.
197: * @param title The title for the UI.
198: * @param usingCrosses If set, determines whether the player uses crosses or noughts. Otherwise, the setting is
199: * initially set to crosses, and the user can change it at will.
200: * @return {@code playerBuilder}.
201: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
202: * dialog).
203: */
204: @SuppressWarnings("unchecked")
205: private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title,
206: final Optional<Boolean> usingCrosses) throws GameException, InputProviderException {
207:
208: inputProvider
209: .needString(
210: GameBuilderFactory.PARAM_PLAYER_NAME,
211: "Name",
212: Optional.empty(),
213: new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
214: .needBoolean(
215: VierConnectsGameBuilderFactory.PARAM_PLAYER_USING_CROSSES,
216: "Uses Red",
217: Optional.of(Boolean.TRUE))
218: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
219:
220: if (usingCrosses.isPresent()) {
221: inputProvider.fixedBoolean(VierConnectsGameBuilderFactory.PARAM_PLAYER_USING_CROSSES, usingCrosses.get());
222: }
223:
224: return inputProvider.requestData(title);
225: }
226:
227: /**
228: * Creates an Vier Connects player builder.
229: *
230: * @param playerBuilder The player builder.
231: * @param playerData The requested player data.
232: * @return {@link VierConnectsPlayer}.
233: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
234: * dialog).
235: */
236: private VierConnectsPlayer createPlayer(final VierConnectsPlayerBuilder playerBuilder,
237: final Map<String, Object> playerData) throws GameException, InputProviderException {
238:
239: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
240: .changeUsingCrosses((Boolean) playerData.get(VierConnectsGameBuilderFactory.PARAM_PLAYER_USING_CROSSES))
241: .build();
242: }
243:
244: /**
245: * Returns an Vier Connects strategy.
246: *
247: * @param playerData The requested player data.
248: * @return The Vier Connects strategy.
249: */
250: private VierConnectsStrategy getStrategy(final Map<String, Object> playerData) {
251: return (VierConnectsStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
252: }
253: }