Skip to content

Method: GDGameBuilderFactoryImpl(GDStrategyFactoryProvider)

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel24-GD.
5: *
6: * ipspiel24-GD 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: * ipspiel24-GD 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 ipspiel24-GD. If not, see
14: * <http://www.gnu.org/licenses/>.
15: */
16: package de.fhdw.gaming.GefangenenDilemma.domain.impl;
17:
18: import java.util.ArrayList;
19: import java.util.LinkedHashMap;
20: import java.util.LinkedHashSet;
21: import java.util.List;
22: import java.util.Map;
23: import java.util.Optional;
24: import java.util.Set;
25: import java.util.regex.Pattern;
26:
27: import de.fhdw.gaming.GefangenenDilemma.domain.GDGameBuilder;
28: import de.fhdw.gaming.GefangenenDilemma.domain.GDGameBuilderFactory;
29: import de.fhdw.gaming.GefangenenDilemma.domain.GDPlayer;
30: import de.fhdw.gaming.GefangenenDilemma.domain.GDPlayerBuilder;
31: import de.fhdw.gaming.GefangenenDilemma.domain.GDStrategy;
32: import de.fhdw.gaming.GefangenenDilemma.domain.factory.GDDefaultStrategyFactoryProvider;
33: import de.fhdw.gaming.GefangenenDilemma.domain.factory.GDStrategyFactory;
34: import de.fhdw.gaming.GefangenenDilemma.domain.factory.GDStrategyFactoryProvider;
35: import de.fhdw.gaming.GefangenenDilemma.moves.factory.GDMoveFactory;
36: import de.fhdw.gaming.GefangenenDilemma.moves.impl.GDDefaultMoveFactory;
37: import de.fhdw.gaming.core.domain.GameBuilder;
38: import de.fhdw.gaming.core.domain.GameBuilderFactory;
39: import de.fhdw.gaming.core.domain.GameException;
40: import de.fhdw.gaming.core.domain.Strategy;
41: import de.fhdw.gaming.core.ui.InputProvider;
42: import de.fhdw.gaming.core.ui.InputProviderException;
43: import de.fhdw.gaming.core.ui.type.validator.MaxValueValidator;
44: import de.fhdw.gaming.core.ui.type.validator.MinValueValidator;
45: import de.fhdw.gaming.core.ui.type.validator.PatternValidator;
46:
47: /**
48: * Implements {@link GameBuilderFactory} by creating a Gefangenen-Dilemma game builder.
49: */
50: public final class GDGameBuilderFactoryImpl implements GDGameBuilderFactory {
51:
52: /**
53: * The number of players.
54: */
55: private static final int NUMBER_OF_PLAYERS = 2;
56: /**
57: * Smallest allowed maximum computation time per move in seconds.
58: */
59: private static final int MIN_MAX_COMPUTATION_TIME_PER_MOVE = 1;
60: /**
61: * Largest allowed maximum computation time per move in seconds.
62: */
63: private static final int MAX_MAX_COMPUTATION_TIME_PER_MOVE = 3600;
64:
65: /**
66: * Implements {@link MOVES}.
67: */
68: public enum MOVES {
69: /**
70: * Implements{@link SNITCH_MOVE}.
71: */
72: SNITCH,
73: /**
74: * Implements{@link REMAIN_MOVE}.
75: */
76: REMAINSILENT
77: }
78:
79: /**
80: * All available Gefangenen-Dilemma strategies.
81: */
82: private final Set<GDStrategy> strategies;
83:
84: /**
85: * Creates a Gefangenen-Dilemma game factory.
86: * Gefangenen-Dilemma strategies are loaded by using the {@link java.util.ServiceLoader}.
87: * <p>
88: * This constructor is meant to be used by the {@link java.util.ServiceLoader}.
89: */
90: public GDGameBuilderFactoryImpl() {
91: this(new GDDefaultStrategyFactoryProvider());
92: }
93:
94: /**
95: * Creates a Gefangenen-Dilemma game factory.
96: *
97: * @param strategyFactoryProvider The {@link GDStrategyFactoryProvider} for loading Gefangenen-Dilemma strategies.
98: */
99: GDGameBuilderFactoryImpl(final GDStrategyFactoryProvider strategyFactoryProvider) {
100: final GDMoveFactory moveFactory = new GDDefaultMoveFactory();
101:
102: final List<GDStrategyFactory> factories = strategyFactoryProvider.getStrategyFactories();
103: this.strategies = new LinkedHashSet<>();
104:• for (final GDStrategyFactory factory : factories) {
105: this.strategies.add(factory.create(moveFactory));
106: }
107: }
108:
109: @Override
110: public String getName() {
111: return "GefangenenDilemma";
112: }
113:
114: @Override
115: public int getMinimumNumberOfPlayers() {
116: return GDGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
117: }
118:
119: @Override
120: public int getMaximumNumberOfPlayers() {
121: return GDGameBuilderFactoryImpl.NUMBER_OF_PLAYERS;
122: }
123:
124: @Override
125: public List<? extends Strategy<?, ?, ?>> getStrategies() {
126: return new ArrayList<>(this.strategies);
127: }
128:
129: @Override
130: public GDGameBuilder createGameBuilder(final InputProvider inputProvider) throws GameException {
131: try {
132: final GDGameBuilder gameBuilder = new GDGameBuilderImpl();
133:
134: @SuppressWarnings("unchecked")
135: final Map<String,
136: Object> gameData = inputProvider.needInteger(
137: GameBuilderFactory.PARAM_MAX_COMPUTATION_TIME_PER_MOVE,
138: "Maximum computation time per move in seconds",
139: Optional.of(GameBuilder.DEFAULT_MAX_COMPUTATION_TIME_PER_MOVE),
140: new MinValueValidator<>(
141: GDGameBuilderFactoryImpl.MIN_MAX_COMPUTATION_TIME_PER_MOVE),
142: new MaxValueValidator<>(
143: GDGameBuilderFactoryImpl.MAX_MAX_COMPUTATION_TIME_PER_MOVE))
144: .requestData("Game properties");
145:
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.requestPlayerData(firstPlayerInputProvider, "Player 1");
151: final GDPlayer firstPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(),
152: firstPlayerData);
153: final GDStrategy 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(secondPlayerInputProvider, "Player 2");
158: final GDPlayer secondPlayer = this.createPlayer(gameBuilder.createPlayerBuilder(),
159: secondPlayerData);
160: final GDStrategy secondPlayerStrategy = this.getStrategy(secondPlayerData);
161: gameBuilder.addPlayer(secondPlayer, secondPlayerStrategy);
162:
163: return gameBuilder;
164: } catch (final InputProviderException e) {
165: throw new GameException(
166: String.format("Creating Gefangenen-Dilemma game was aborted: %s", e.getMessage()), e);
167: }
168: }
169:
170: /**
171: * Returns data for a player builder.
172: *
173: * @param inputProvider The input provider.
174: * @param title The title for the UI.
175: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
176: * dialog).
177: */
178: @SuppressWarnings("unchecked")
179: private Map<String, Object> requestPlayerData(final InputProvider inputProvider, final String title)
180: throws GameException, InputProviderException {
181:
182: inputProvider
183: .needString(
184: GameBuilderFactory.PARAM_PLAYER_NAME,
185: "Name",
186: Optional.empty(),
187: new PatternValidator(Pattern.compile("\\S+(\\s+\\S+)*")))
188: .needInteger(
189: GDGameBuilderFactory.OUTCOME_ON_SNITCH_SNITCH,
190: "Player's outcome on Snitch/Snitch",
191: Optional.of(-8))
192: .needInteger(
193: GDGameBuilderFactory.OUTCOME_ON_SNITCH_REMAINSILENT,
194: "Player's outcome on Snitch/RemainSilent",
195: Optional.of(0))
196: .needInteger(
197: GDGameBuilderFactory.OUTCOME_ON_REMAINSILENT_SNITCH,
198: "Player's outcome on RemainSilent/Snitch",
199: Optional.of(-10))
200: .needInteger(
201: GDGameBuilderFactory.OUTCOME_ON_REMAINSILENT_REMAINSILENT,
202: "Player's outcome on RemainSilent/RemainSilent",
203: Optional.of(-1))
204: .needObject(GameBuilderFactory.PARAM_PLAYER_STRATEGY, "Strategy", Optional.empty(), this.strategies);
205:
206: return inputProvider.requestData(title);
207: }
208:
209: /**
210: * Creates a Gefangenen-Dilemma player.
211: *
212: * @param playerBuilder The player builder.
213: * @param playerData The requested player data.
214: * @return The created {@link GDPlayer}.
215: * @throws InputProviderException if the operation has been aborted prematurely (e.g. if the user cancelled a
216: * dialog).
217: */
218: private GDPlayer createPlayer(final GDPlayerBuilder playerBuilder,
219: final Map<String, Object> playerData) throws GameException, InputProviderException {
220: final Map<MOVES, Map<MOVES, Double>> possibleOutcomes = new LinkedHashMap<>();
221: final Map<MOVES, Double> possibleOutcomesSnitch = new LinkedHashMap<>();
222: possibleOutcomesSnitch.put(
223: MOVES.SNITCH,
224: (double) (Integer) playerData
225: .get(GDGameBuilderFactory.OUTCOME_ON_SNITCH_SNITCH));
226: possibleOutcomesSnitch.put(
227: MOVES.REMAINSILENT,
228: (double) (Integer) playerData
229: .get(GDGameBuilderFactory.OUTCOME_ON_SNITCH_REMAINSILENT));
230: possibleOutcomes.put(MOVES.SNITCH, possibleOutcomesSnitch);
231:
232: final Map<MOVES, Double> possibleOutcomesRemainSilent = new LinkedHashMap<>();
233: possibleOutcomesRemainSilent.put(
234: MOVES.SNITCH,
235: (double) (Integer) playerData
236: .get(GDGameBuilderFactory.OUTCOME_ON_REMAINSILENT_SNITCH));
237: possibleOutcomesRemainSilent.put(
238: MOVES.REMAINSILENT,
239: (double) (Integer) playerData
240: .get(GDGameBuilderFactory.OUTCOME_ON_REMAINSILENT_REMAINSILENT));
241: possibleOutcomes.put(MOVES.REMAINSILENT, possibleOutcomesRemainSilent);
242: return playerBuilder.changeName((String) playerData.get(GameBuilderFactory.PARAM_PLAYER_NAME))
243: .changePossibleOutcomes(possibleOutcomes).build();
244: }
245:
246: /**
247: * Returns a Gefangenen-Dilemma strategy.
248: *
249: * @param playerData The requested player data.
250: * @return The Gefangenen-Dilemma strategy.
251: */
252: private GDStrategy getStrategy(final Map<String, Object> playerData) {
253: return (GDStrategy) playerData.get(GameBuilderFactory.PARAM_PLAYER_STRATEGY);
254: }
255:
256: }