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