aboutsummaryrefslogtreecommitdiff
path: root/example/src/main/java/zajc
diff options
context:
space:
mode:
Diffstat (limited to 'example/src/main/java/zajc')
-rw-r--r--example/src/main/java/zajc/akiwrapper/AkinatorExample.java307
1 files changed, 141 insertions, 166 deletions
diff --git a/example/src/main/java/zajc/akiwrapper/AkinatorExample.java b/example/src/main/java/zajc/akiwrapper/AkinatorExample.java
index 148394f..0a903e6 100644
--- a/example/src/main/java/zajc/akiwrapper/AkinatorExample.java
+++ b/example/src/main/java/zajc/akiwrapper/AkinatorExample.java
@@ -3,7 +3,7 @@ package zajc.akiwrapper;
3import static com.github.markozajc.akiwrapper.Akiwrapper.Answer.*; 3import static com.github.markozajc.akiwrapper.Akiwrapper.Answer.*;
4import static com.github.markozajc.akiwrapper.core.entities.Server.GuessType.CHARACTER; 4import static com.github.markozajc.akiwrapper.core.entities.Server.GuessType.CHARACTER;
5import static com.github.markozajc.akiwrapper.core.entities.Server.Language.ENGLISH; 5import static com.github.markozajc.akiwrapper.core.entities.Server.Language.ENGLISH;
6import static java.lang.Integer.parseInt; 6import static java.lang.Character.toLowerCase;
7import static java.lang.System.*; 7import static java.lang.System.*;
8import static java.util.stream.Collectors.joining; 8import static java.util.stream.Collectors.joining;
9 9
@@ -19,121 +19,82 @@ import com.github.markozajc.akiwrapper.core.exceptions.ServerNotFoundException;
19@SuppressWarnings("javadoc") 19@SuppressWarnings("javadoc")
20public class AkinatorExample { 20public class AkinatorExample {
21 21
22 public static final double PROBABILITY_THRESHOLD = 0.85; 22 private static final String ANSWER_TIP =
23 // This is used to determine which guesses are probable (probability is determined by 23 "Y or yes, N or no, DK or don't know, P or probably, PN or probably not, or go back one step with B or back.";
24 // Akinator) enough to propose to the player. 24 private static final Scanner IN = new Scanner(System.in).useDelimiter("\n");
25 25
26 @SuppressWarnings("null") 26 public static void main(String[] args) {
27 public static void main(String[] args) throws Exception { 27 boolean filterProfanity = getProfanityFilter();
28 try (var in = new Scanner(System.in)) { 28 // Gets player's age. Like the Akinator's website, this will turn on the profanity
29 boolean filterProfanity = getProfanityFilter(in); 29 // filter if the age entered is below 16.
30 // Gets player's age. Like the Akinator's website, this will turn on the profanity 30
31 // filter if the age entered is below 16. 31 var language = getLanguage();
32 32 // Gets player's language. Akinator will give the user localized questions and
33 var language = getLanguage(in); 33 // guesses depending on user's language.
34 // Gets player's language. Akinator will give the user localized questions and 34
35 // guesses depending on user's language. 35 var guessType = getGuessType();
36 36 // Gets the guess type.
37 var guessType = getGuessType(in); 37
38 // Gets the guess type. 38 Akiwrapper aw;
39 39 try {
40 Akiwrapper aw; 40 aw = new AkiwrapperBuilder().setFilterProfanity(filterProfanity)
41 try { 41 .setLanguage(language)
42 aw = new AkiwrapperBuilder().setFilterProfanity(filterProfanity) 42 .setGuessType(guessType)
43 .setLanguage(language) 43 .build();
44 .setGuessType(guessType) 44 } catch (ServerNotFoundException e) {
45 .build(); 45 err.println("Unsupported combination of language and guess type");
46 } catch (ServerNotFoundException e) { 46 return;
47 err.println("Unsupported combination of language and guess type");
48 return;
49 }
50 // Builds the Akiwrapper instance, this is what we'll be using to perform
51 // operations such as answering questions, fetching guesses, etc
52
53 var rejected = new ArrayList<Long>();
54 // A list of rejected guesses, used to prevent them from repeating
55
56 while (aw.getQuestion() != null) {
57 // Runs while there are still questions left
58
59 Question question = aw.getQuestion();
60 if (question == null)
61 break;
62 // Breaks the loop if question is null; /should/ not occur, but safety is still
63 // first
64
65 out.printf("Question #%d%n", question.getStep() + 1);
66 out.printf("\t%s%n", question.getQuestion());
67 // Displays the question.
68
69 if (question.getStep() == 0)
70 out.printf("%nAnswer with " +
71 "Y (yes), N (no), DK (don't know), P (probably) or PN (probably not) " +
72 "or go back in time with B (back).%n");
73 // Displays the tip (only for the first time)
74
75 answerQuestion(in, aw);
76
77 reviewGuesses(in, aw, rejected);
78 // Iterates over any available guesses.
79 }
80
81 for (Guess guess : aw.getGuesses()) {
82 if (reviewGuess(guess, in)) {
83 // Reviews all final guesses.
84 finish(true);
85 exit(0);
86 }
87 }
88
89 finish(false);
90 // Loses if all guesses are rejected.
91 } 47 }
92 } 48 // Builds the Akiwrapper instance, this is what we'll be using to perform
49 // operations such as answering questions, fetching guesses, etc
93 50
94 private static void answerQuestion(@Nonnull Scanner sc, @Nonnull Akiwrapper aw) { 51 while (aw.getQuestion() != null) {
95 boolean answered = false; 52 // Runs while there are still questions left
96 while (!answered) {
97 // Iterates while the questions remains unanswered.
98 53
99 var answer = sc.nextLine().toLowerCase(); 54 Question question = aw.getQuestion();
55 if (question == null)
56 break;
57 // Breaks the loop if question is null; /should/ not occur, but safety is still
58 // first
100 59
101 if (answer.equals("y")) { 60 out.printf("Question #%d%n\t%s%n", question.getStep() + 1, question.getQuestion());
102 aw.answer(YES); 61 // Displays the question.
103 62
104 } else if (answer.equals("n")) { 63 if (question.getStep() == 0)
105 aw.answer(NO); 64 out.printf("%nAnswer with %s%n", ANSWER_TIP);
65 // Displays the tip (only for the first time)
106 66
107 } else if (answer.equals("dk")) { 67 out.print("> ");
108 aw.answer(DONT_KNOW);
109 68
110 } else if (answer.equals("p")) { 69 answerQuestion(aw);
111 aw.answer(PROBABLY); 70 // Displays the question and prompts the player for an answer
112 71
113 } else if (answer.equals("pn")) { 72 reviewSuggestedGuess(aw);
114 aw.answer(PROBABLY_NOT); 73 // Checks if any guess is available and prompts the player
74 }
115 75
116 } else if (answer.equals("b")) { 76 reviewSuggestedGuess(aw);
117 aw.undoAnswer(); 77 // Reviews the final guess
118 78
119 } else if (answer.equals("debug")) { 79 finish(false);
120 out.printf("Debug information:%n\tCurrent API server: %s%n\tCurrent guess count: %d%n", 80 // Loses if all guesses are rejected.
121 aw.getServer().getUrl(), aw.getGuesses().size()); 81 }
122 continue;
123 // Displays some debug information.
124 82
83 private static Guess reviewSuggestedGuess(@Nonnull Akiwrapper aw) {
84 var guess = aw.suggestGuess();
85 if (guess != null) {
86 if (reviewGuess(guess)) {
87 aw.confirmGuess(guess);
88 finish(true);
89 exit(0);
125 } else { 90 } else {
126 out.println("Please answer with either " + 91 aw.rejectLastGuess();
127 "[Y]ES, [N]O, [D|ONT |K]NOW, [P]ROBABLY or [P|ROBABLY |N]OT or go back one step with [B]ACK.");
128 continue;
129 } 92 }
130
131 answered = true;
132 // Answers the question.
133 } 93 }
94 return guess;
134 } 95 }
135 96
136 private static boolean reviewGuess(@Nonnull Guess guess, @Nonnull Scanner sc) { 97 private static boolean reviewGuess(@Nonnull Guess guess) {
137 out.println(guess.getName()); 98 out.println(guess.getName());
138 out.print("\t"); 99 out.print("\t");
139 if (guess.getDescription() == null) 100 if (guess.getDescription() == null)
@@ -143,49 +104,77 @@ public class AkinatorExample {
143 out.println(); 104 out.println();
144 // Displays the guess' information 105 // Displays the guess' information
145 106
146 boolean answered = false; 107 out.print("Is this what you're thinking of? [Y/n] ");
147 boolean isCharacter = false; 108 var input = IN.next().trim();
148 while (!answered) { 109 // Asks the player if the guess is correct
149 // Asks the player if the guess is correct 110
111 return input.isEmpty() || toLowerCase(input.charAt(0)) == 'y';
112 }
113
114 private static void answerQuestion(@Nonnull Akiwrapper aw) {
115 main: while (true) {
116 // Prompts the player for an answer
117
118 var input = IN.next().toLowerCase();
150 119
151 out.println("Is this your character? (y/n)"); 120 switch (input) {
152 String line = sc.nextLine();
153 switch (line) {
154 case "y": 121 case "y":
155 // If the player has responded positively. 122 case "yes":
156 answered = true; 123 aw.answer(YES);
157 isCharacter = true; 124 break main;
158 break;
159 125
160 case "n": 126 case "n":
161 // If the player has responded negatively. 127 case "no":
162 answered = true; 128 aw.answer(NO);
163 isCharacter = false; 129 break main;
130
131 case "dk":
132 case "don'tknow":
133 case "dontknow":
134 case "dont know":
135 case "don't know":
136 aw.answer(DONT_KNOW);
137 break main;
138
139 case "p":
140 case "probably":
141 aw.answer(PROBABLY);
142 break main;
143
144 case "pn":
145 case "probablynot":
146 case "probably not":
147 aw.answer(PROBABLY_NOT);
148 break main;
149
150 case "b":
151 case "back":
152 if (aw.getStep() == 0)
153 out.println("Can't undo on the first question.");
154 else
155 aw.undoAnswer();
156 break main;
157
158 case "debug":
159 displayDebug(aw);
164 break; 160 break;
161 // Displays some debug information.
165 162
166 default: 163 default:
164 out.println("Please answer with either " + ANSWER_TIP);
167 break; 165 break;
168 } 166 }
169 } 167 }
170
171 return isCharacter;
172 } 168 }
173 169
174 private static void reviewGuesses(@Nonnull Scanner sc, @Nonnull Akiwrapper aw, @Nonnull List<Long> declined) { 170 private static void displayDebug(Akiwrapper aw) {
175 for (var guess : aw.getGuessesAboveProbability(PROBABILITY_THRESHOLD)) { 171 var question = aw.getQuestion();
176 if (!declined.contains(Long.valueOf(guess.getIdLong()))) { 172 out.println("Debug information:");
177 // Checks if this guess complies with the conditions. 173 out.printf("\tCurrent API server: %s%n", aw.getServer().getUrl());
178 174 out.printf("\tProgression: %f%%%n", question == null ? -1 : question.getProgression());
179 if (reviewGuess(guess, sc)) { 175 out.println("\tGuesses:");
180 // If the player accepts this guess 176 aw.getGuesses().stream().forEach(g -> out.printf("\t\t%f - %s%n", g.getProbability(), g.getName()));
181 finish(true); 177 out.print("> ");
182 exit(0);
183 }
184
185 declined.add(guess.getIdLong());
186 // Registers this guess as rejected.
187 }
188 }
189 } 178 }
190 179
191 private static void finish(boolean win) { 180 private static void finish(boolean win) {
@@ -200,67 +189,53 @@ public class AkinatorExample {
200 } 189 }
201 } 190 }
202 191
203 private static boolean getProfanityFilter(@Nonnull Scanner sc) { 192 private static boolean getProfanityFilter() {
204 out.println("What's your age? (default: 18)"); 193 out.print("Enable profanity filtering? [y/N] ");
205 while (true) { 194 var input = IN.next().trim();
206 var age = sc.nextLine(); 195 return !input.isEmpty() && toLowerCase(input.charAt(0)) == 'y';
207
208 if (age.equals(""))
209 return false;
210
211 try {
212 return parseInt(age) < 16;
213 } catch (NumberFormatException e) {
214 out.println("That's not a number");
215 }
216 }
217 } 196 }
218 197
219 @Nonnull 198 @Nonnull
220 private static Language getLanguage(@Nonnull Scanner sc) { 199 @SuppressWarnings("null")
200 private static Language getLanguage() {
221 var languages = EnumSet.allOf(Language.class); 201 var languages = EnumSet.allOf(Language.class);
222 202
223 out.println("What's your language? (default: English)"); 203 out.print("What's your language? [English] ");
224 while (true) { 204 while (true) {
225 String selectedLanguage = sc.nextLine().toLowerCase().trim(); 205 var input = IN.next().trim().toUpperCase();
226 206
227 if (selectedLanguage.equals("")) 207 if (input.isEmpty())
228 return ENGLISH; 208 return ENGLISH;
229 209
230 var language = languages.stream() 210 var language = languages.stream().filter(l -> l.toString().equals(input)).findAny();
231 .filter(l -> l.toString().toLowerCase().equals(selectedLanguage))
232 .findAny()
233 .orElse(null);
234 211
235 if (language != null) { 212 if (language.isPresent()) {
236 return language; 213 return language.orElseThrow();
237 214
238 } else { 215 } else {
239 out.println(languages.stream() 216 out.println(languages.stream()
240 .map(Enum::toString) 217 .map(Enum::toString)
241 .collect(joining("\n-", "Sorry, that language isn't supported. Choose between\n-", ""))); 218 .collect(joining("\n-", "Sorry, that language isn't supported. Available options:\n-", "")));
242 } 219 }
243 } 220 }
244 } 221 }
245 222
246 @Nonnull 223 @Nonnull
247 private static GuessType getGuessType(@Nonnull Scanner sc) { 224 @SuppressWarnings("null")
225 private static GuessType getGuessType() {
248 var guessTypes = EnumSet.allOf(GuessType.class); 226 var guessTypes = EnumSet.allOf(GuessType.class);
249 227
250 out.println("What will you be guessing? (default: character)"); 228 out.print("What will you be guessing? [character] ");
251 while (true) { 229 while (true) {
252 String selectedGuessType = sc.nextLine().toLowerCase().trim(); 230 var input = IN.next().trim().toUpperCase();
253 231
254 if (selectedGuessType.equals("")) 232 if (input.isEmpty())
255 return CHARACTER; 233 return CHARACTER;
256 234
257 var guessType = guessTypes.stream() 235 var guessType = guessTypes.stream().filter(l -> l.toString().equals(input)).findAny();
258 .filter(l -> l.toString().toLowerCase().equals(selectedGuessType))
259 .findAny()
260 .orElse(null);
261 236
262 if (guessType != null) { 237 if (guessType.isPresent()) {
263 return guessType; 238 return guessType.orElseThrow();
264 239
265 } else { 240 } else {
266 out.println("" + guessTypes.stream() 241 out.println("" + guessTypes.stream()