Skip to content

Method: getMinimumNumberOfPlayers()

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