Skip to content
This repository was archived by the owner on Sep 17, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 127 additions & 40 deletions dialog/src/main/java/roboy/dialog/states/gameStates/ChooseGameState.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,183 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import roboy.dialog.Segue;
import roboy.dialog.states.definitions.State;
import roboy.dialog.states.definitions.StateParameters;
import roboy.linguistics.Linguistics;
import roboy.linguistics.sentenceanalysis.Interpretation;
import roboy.talk.PhraseCollection;
import roboy.talk.Verbalizer;
import roboy.util.Maps;
import roboy.util.RandomList;
import java.util.Arrays;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

public class ChooseGameState extends State {

private final static String TRANSITION_CHOSE_SNAPCHAT = "choseSnapchat";
private final static String TRANSITION_CHOSE_20_Q = "chose20questions";

/*
Hey, if you want to add a new GameState, you will need to add your GameState into the HashMap EXISTING_GAME_MAP. That should be it. Don't forget to increment the initialCapacity of the HashMap
*/

private final static String TRANSITION_EXIT = "exitGame";

private final static RandomList<String> EXISTING_GAMES = new RandomList<>(Arrays.asList("Snapchat", "Akinator"));
private final static HashMap<String, GameState> EXISTING_GAME_MAP = new HashMap<>(2); //CHANGE THE VALUE OF THIS TO THE AMOUNT OF GAMES YOU SHALL ADD (EFFICIENCY)

private final Logger LOGGER = LogManager.getLogger();

private String game = null;
private String suggestedGame = null;


public ChooseGameState(String stateIdentifier, StateParameters params) {
super(stateIdentifier, params);
}
//Can't fill this at constructor or static constructor level, so it is done in act()
private void fillExistingGameMap(){
if(EXISTING_GAME_MAP.isEmpty()){
addElement("Akinator", (GamingTwentyQuestionsState .transitionName));
addElement("Snapchat", (GamingSnapchatState .transitionName));
}
}

private void addElement(String key, String transitionName){
if(getAllTransitions().containsKey(transitionName)){
EXISTING_GAME_MAP.put(key, (GameState) getTransition(transitionName));
}
else{
LOGGER.error("Cannot add "+transitionName+" to EXISTING_GAME_MAP because transition does not exist");
}
}

@Override
public Output act() {
do {
suggestedGame = EXISTING_GAMES.getRandomElement();
fillExistingGameMap();

//Pick a game that is playable
RandomList<String> randomList = new RandomList<>();
randomList.addAll(
//Streams to Filter, because why have Java 1.8 if we can't make use of it
//Basically: Get all keys, turn that list into a stream, filter the stream by whether the key's value (the game) is capable of starting. Then put all those who can start into a random list.
EXISTING_GAME_MAP.keySet().stream().filter(s -> EXISTING_GAME_MAP.get(s).canStartGame())
.collect(Collectors.toCollection(ArrayList::new)));

//If no games are playable
if(randomList.isEmpty()){
LOGGER.info("No games available");

suggestedGame = "exit";
return Output.say("I do not think I know any games that are playable in this environment. Should I try again?");
}
//Choose a random game that is playable
else{
LOGGER.debug(""+randomList.size()+" games are available to play");
suggestedGame = randomList.getRandomElement();
return Output.say(String.format(PhraseCollection.GAME_ASKING_PHRASES.getRandomElement(), suggestedGame));
}
while(getRosMainNode() == null && suggestedGame == "Snapchat");

return Output.say(String.format(PhraseCollection.GAME_ASKING_PHRASES.getRandomElement(), suggestedGame));
}

@Override
public Output react(Interpretation input) {
//Reset the Value of Game
game = "";

Linguistics.UtteranceSentiment inputSentiment = getInference().inferSentiment(input);
String inputGame = inferGame(input);

if (inputSentiment == Linguistics.UtteranceSentiment.POSITIVE){
game = suggestedGame;
return Output.say(Verbalizer.startSomething.getRandomElement());
} else if (!inputGame.isEmpty()){
game = inputGame;
if(game.equals("Snapchat") && getRosMainNode() == null){
//If no games can be played, should we try again?
if(suggestedGame.equals("exit")){
if(inputSentiment == Linguistics.UtteranceSentiment.NEGATIVE){
game = suggestedGame;
}
}
//If a game can be played...
else {
//If you AGREE with the selected game, try to play the game
if (inputSentiment == Linguistics.UtteranceSentiment.POSITIVE) {
return attemptGameLaunch(suggestedGame);
}
//If you suggested your OWN game, try to play the game
if (!inputGame.isEmpty()) {
return attemptGameLaunch(inputGame);
}
//If you DISAGREE with the selected game, exit...
if (inputSentiment == Linguistics.UtteranceSentiment.NEGATIVE) {
game = "exit";
LOGGER.info("Trying to start Snapchat Game but ROS is not initialised.");
Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5);
return Output.say(Verbalizer.rosDisconnect.getRandomElement() + String.format("What a pitty, %s. Snapchat is not possible right now. ",
getContext().ACTIVE_INTERLOCUTOR.getValue().getName())).setSegue(s);
}
return Output.say(Verbalizer.startSomething.getRandomElement());
} else if (inputSentiment == Linguistics.UtteranceSentiment.NEGATIVE){
game = "exit";
}

return Output.sayNothing();
}

private Output attemptGameLaunch(String inputGame) {
//Check if Game is playable
if(EXISTING_GAME_MAP.get(inputGame).canStartGame()) {
//If so, lets go start it
game = inputGame;
return Output.say(Verbalizer.startSomething.getRandomElement());
}
else{
//Else, quit and issue a warning
LOGGER.warn("Detected that the given game cannot be played for some reason");

game = "exit";
return EXISTING_GAME_MAP.get(inputGame).cannotStartWarning();
}
}

@Override
public State getNextState() {

switch (game){
case "Akinator":
return getTransition(TRANSITION_CHOSE_20_Q);
case "Snapchat":
return getTransition(TRANSITION_CHOSE_SNAPCHAT);
case "exit":
return getTransition(TRANSITION_EXIT);
default:
//CASE: EXIT
if(game.equals("exit")) {
return getTransition(TRANSITION_EXIT);
}
else{
//Does game exist in Map --> Basically, should we launch a game...
if(EXISTING_GAME_MAP.containsKey(game)) {
String transition = Maps.value2Key( getAllTransitions(), EXISTING_GAME_MAP.get(game)).get();
return getTransition(transition);
}
//Or repeat this state again, because we need to check something
else{
return this;
}
}
// switch (game){
// case "Akinator":
// return getTransition(TRANSITION_CHOSE_20_Q);
// case "Snapchat":
// return getTransition(TRANSITION_CHOSE_SNAPCHAT);
// case "exit":
// return getTransition(TRANSITION_EXIT);
// default:
// return this;
// }

}

private String inferGame(Interpretation input){

//VERY IMPORTANT: If your tags conflict, the one which comes first in the Hash Map shall be taken, the other shall be ignored. If for some reason you have conflicting Tags, rewrite this method
List<String> tokens = input.getTokens();
game = "";
if(tokens != null && !tokens.isEmpty()){
if(tokens.contains("akinator") || tokens.contains("guessing") || tokens.contains("questions")){
game = "Akinator";
} else if (tokens.contains("snapchat") || tokens.contains("filters") || tokens.contains("filter") || tokens.contains("mask")){
game = "Snapchat";
String inferredGame = "";
//If Tokens Exist
if(tokens != null && !tokens.isEmpty()) {
//Get All Keys
for (String key : EXISTING_GAME_MAP.keySet()) {
//Get all Tags from each Keys Value
for (String tag : EXISTING_GAME_MAP.get(key).getTags()) {
//If Tag is found in tokens
if (tokens.contains(tag)) {
//Return the key/game
return key;
}
}
}
}
return game;
return inferredGame;
}


}
58 changes: 58 additions & 0 deletions dialog/src/main/java/roboy/dialog/states/gameStates/GameState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package roboy.dialog.states.gameStates;

import roboy.dialog.states.definitions.State;
import roboy.dialog.states.definitions.StateParameters;
import roboy.linguistics.sentenceanalysis.Interpretation;

import java.util.Collection;
import java.util.List;

public abstract class GameState extends State {

public static String transitionName;

/**
* Create a state object with given identifier (state name) and parameters.
* <p>
* The parameters should contain a reference to a state machine for later use.
* The state will not automatically add itself to the state machine.
*
* @param stateIdentifier identifier (name) of this state
* @param params parameters for this state, should contain a reference to a state machine
*/
public GameState(String stateIdentifier, StateParameters params) {
super(stateIdentifier, params);
}

/**
* Can the game start?
* @return True if game is capable of starting
*/
public abstract boolean canStartGame();

/**
* What Roboy shall say to the user, explaining why he cannot start the given game, ie. Sorry, I need an internet connection to play World of Warcraft.
* @return Output that contains reasoning
*/
public abstract Output cannotStartWarning();

/**
* Tags that shall be used to infer, whether or not the user is specifically asking for a game. See {@link ChooseGameState}.infer method for how this is specifically implemented.
* @return Collection of tags
*/
public abstract Collection<String> getTags();



public boolean checkUserSaidStop(Interpretation input){
boolean stopGame = false;
List<String> tokens = input.getTokens();
if(tokens != null && !tokens.isEmpty()){
if(tokens.contains("boring") || tokens.contains("stop") || tokens.contains("bored")){
stopGame = true;

}
}
return stopGame;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import roboy.dialog.Segue;
import roboy.dialog.states.definitions.State;
import roboy.dialog.states.definitions.StateParameters;
import roboy.linguistics.Linguistics;
import roboy.linguistics.sentenceanalysis.Interpretation;
import roboy.logic.Inference;
import roboy.talk.PhraseCollection;
import roboy.talk.Verbalizer;
import roboy.util.RandomList;

import java.util.*;

import static roboy.util.FileLineReader.readFile;


public class GamingSnapchatState extends State {
public class GamingSnapchatState extends GameState {

private final static String TRANSITION_GAME_ENDED = "gameEnded";
private final static String EXISTING_FILTERS_ID = "filterFile";
Expand All @@ -33,6 +35,8 @@ public class GamingSnapchatState extends State {

private String suggestedFilter = "";

public static String transitionName = "choseSnapchat";

public GamingSnapchatState(String stateIdentifier, StateParameters params) {

super(stateIdentifier, params);
Expand All @@ -54,7 +58,8 @@ public Output react(Interpretation input) {
Linguistics.UtteranceSentiment inputSentiment = getInference().inferSentiment(input);
List<String> inputFilters = localInference.inferSnapchatFilter(input, EXISTING_FILTERS);

if(!checkUserSaidStop(input)) {
stopGame = checkUserSaidStop(input);
if(!stopGame) {
if (inputSentiment == Linguistics.UtteranceSentiment.POSITIVE) {
desiredFilters.add(suggestedFilter);
} else if (inputFilters != null) {
Expand All @@ -79,19 +84,6 @@ public State getNextState() {
}
}

private boolean checkUserSaidStop(Interpretation input){

stopGame = false;
List<String> tokens = input.getTokens();
if(tokens != null && !tokens.isEmpty()){
if(tokens.contains("boring") || tokens.contains("stop") || tokens.contains("bored")){
stopGame = true;

}
}
return stopGame;
}

private Map<String, List<String>> buildSynonymMap(List<String> filters){

Map<String, List<String>> filterMap = new HashMap<>();
Expand Down Expand Up @@ -121,4 +113,21 @@ private Map<String, List<String>> buildSynonymMap(List<String> filters){
return filterMap;
}

@Override
public boolean canStartGame(){
return getRosMainNode() != null;
}

@Override
public Output cannotStartWarning() {
Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5);
return Output.say(Verbalizer.rosDisconnect.getRandomElement() + String.format("What a pity, %s. Snapchat is not possible right now.",
getContext().ACTIVE_INTERLOCUTOR.getValue().getName())).setSegue(s);
}

@Override
public Collection<String> getTags(){
return Arrays.asList("snapchat", "filters", "filter");
}

}
Loading