package bayesGame.minigame; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import org.apache.commons.math3.fraction.Fraction; import bayesGame.levelcontrollers.LevelController; import bayesGame.levelcontrollers.Script; import bayesGame.ui.InterfaceView; import bayesGame.viewcontrollers.MinigameViewController; import bayesGame.viewcontrollers.ViewController; import bayesGame.world.GameCharacters; import bayesGame.world.PlayerCharacter; import bayesGame.bayesbayes.*; public class MinigameController { private MinigameViewController viewController; private Map<Object,String[]> discussions; private DiscussionNet gameNet; private int timeLimit; private Set<Object> hiddenNodes; private Set<Object> targetNodes; private int gameMode; private int reaction; private Object successResult; private Object failureResult; private boolean ready = false; private int turnsTaken; private boolean energycost = false; private PlayerCharacter PC; private LevelController owner; private String helpReference; public MinigameController(DiscussionNet gameNet, Set<Object> targetNodes) { this.gameNet = gameNet; this.targetNodes = targetNodes; this.gameMode = 0; this.reaction = 0; this.successResult = ""; this.failureResult = "Restart"; if (targetNodes.size() == 0){ for (BayesNode n : gameNet.getGraph().getVertices().toArray(new BayesNode[gameNet.getGraph().getVertexCount()])){ targetNodes.add(n.type); } } this.hiddenNodes = new HashSet<Object>(); this.discussions = new HashMap<Object,String[]>(); this.viewController = new MinigameViewController(this, gameNet); } public void setHiddenNodes(Set<Object> hiddenNodes){ this.hiddenNodes = hiddenNodes; } public void setGameMode(int gameMode){ this.gameMode = gameMode; } public void enableEnergyCost(){ this.PC = GameCharacters.PC; energycost = true; } public void hideTargetNodes(){ hiddenNodes.addAll(targetNodes); } public void hideTargetNodeFamily(){ for (Object o : targetNodes){ List<Object> targetNodeFamily = gameNet.getFamily(o); hiddenNodes.addAll(targetNodeFamily); } } public void randomizeHiddenNodes(double percentage){ if (percentage > 1){ percentage = 1; } else if (percentage < 0){ percentage = 0; } int nodecount = gameNet.getGraph().getVertexCount(); int hidden_node_count = (int)(percentage * nodecount); if (hidden_node_count == 0){ hidden_node_count = 1; } if (hidden_node_count == nodecount){ hidden_node_count--; } int nodes_hidden_already = hiddenNodes.size(); int nodes_to_hide = hidden_node_count - nodes_hidden_already; if (nodes_to_hide > 0){ randomizeHiddenNodes(nodes_to_hide); } } public void randomizeHiddenNodes(int amount){ Random random = new Random(); BayesNode[] nodes = gameNet.getGraph().getVertices().toArray(new BayesNode[gameNet.getGraph().getVertexCount()]); for(int i = 0; i < amount; i++){ // pick a random node which is not already in the set of hidden nodes int item; do{ item = random.nextInt(nodes.length); } while (!hiddenNodes.contains(nodes[item].type)); hiddenNodes.add(nodes[item].type); } } public void randomizeTargetNodes(int amount){ Random random = new Random(); BayesNode[] nodes = gameNet.getGraph().getVertices().toArray(new BayesNode[gameNet.getGraph().getVertexCount()]); targetNodes.clear(); for(int i = 0; i < amount; i++){ int item = random.nextInt(nodes.length); targetNodes.add(nodes[item].type); } } public void randomizeTargetNode(){ List<Object> nodefamily; do { randomizeTargetNodes(1); Object[] nodearray = targetNodes.toArray(); Object node = nodearray[0]; nodefamily = gameNet.getFamily(node); } while (nodefamily.size() < 2); } public void setDiscussions(Map<Object,String[]> discussions){ this.discussions = discussions; } public void setHelpReference(String string) { this.helpReference = string; } public void startGame(){ startGame(0, new Object[0]); } // game mode 1 = figure out the contents of target nodes public void startGame(int timeLimit, Object[] knowledges){ this.timeLimit = timeLimit; turnsTaken = 0; viewController.setHelpReference(helpReference); // mark known nodes as known for (Object o : knowledges){ gameNet.observe(o); } for (Object h : hiddenNodes){ gameNet.addProperty(h, "hidden"); } for (Object t : targetNodes){ gameNet.addProperty(t, "target"); } ready = true; viewController.display(); } public void chooseNode(Object node){ if (ready){ if (!hiddenNodes.contains(node) && !gameNet.isObserved(node)){ viewController.displayOptions(node); } } } private void endOfTurn(int timeTaken){ if (ready){ turnsTaken = turnsTaken + timeTaken; boolean allTargetNodesKnown = true; for (Object o : targetNodes){ if (gameNet.getProbability(o).doubleValue() > 0.0d && gameNet.getProbability(o).doubleValue() < 1.0d){ allTargetNodesKnown = false; break; } } if (timeLimit > 0){ viewController.showText("Turn " + turnsTaken + "/" + timeLimit); } if (allTargetNodesKnown && gameMode == 0 && timeLimit > 0){ viewController.showText("Success!"); viewController.showText("Clearing this level with " + (timeLimit - turnsTaken) + " turns to spare confers " + (timeLimit - turnsTaken) + "fame."); clear(true); } else if (turnsTaken == timeLimit && timeLimit > 0){ viewController.showText("Failure!"); clear(false); } else if (allTargetNodesKnown && gameMode == 0){ if (energycost){ finishedThinking(); } else { clear(true); } } } } private void decisionMade(Object node){ Fraction probability = gameNet.getProbability(node); if (probability.doubleValue() > 0.5d){ reaction++; clear(true); // viewController.addText("Positive reaction! Current reaction " + reaction); } else { reaction--; clear(false); // viewController.addText("Negative reaction! Current reaction " + reaction); } } private void clear(boolean success){ ready = false; viewController.processEventQueue(); if (success){ processGameEnd(successResult); } else { processGameEnd(failureResult); } } private void processGameEnd(Object resultType) { if (resultType.equals("Restart")){ // TODO: Restart } else if (resultType instanceof Script){ Script script = (Script)resultType; script.run(); } else { owner.minigameCompleted(viewController); } } public void observeNode(Object type, OptionNodeOption option) { if (ready){ if (!hiddenNodes.contains(type)){ if ((!energycost) || PC.getEnergy() > 0){ boolean nodeTrue = gameNet.observe(type); int timeSpent = 1; if (option != null){ timeSpent = option.getTimeSpent(); viewController.showText(option.getDescription()); String response; if (nodeTrue){ response = option.getPositiveResponse(); } else { response = option.getNegativeResponse(); } viewController.showText(response); // viewController.displayPopup(option.getDescription(), response); } gameNet.updateBeliefs(); viewController.addRefreshDisplay(); viewController.processEventQueue(); if (gameMode == 1 && targetNodes.contains(type)){ decisionMade(type); } if (energycost){ PC.useEnergy(1); viewController.showText("You observe the truth of " + type + " by looking it up, which costs you some mental energy. You have " + PC.getEnergy() + " points of energy left."); } viewController.updateStatusText(); this.endOfTurn(timeSpent); } else if (energycost && PC.getEnergy() <= 0){ viewController.showText("You're exhausted and can't think about this kind of thing anymore."); } } } } public void setOwner(LevelController levelController) { this.owner = levelController; } public void offerViewController(ViewController viewController) { viewController.giveControlTo(this.viewController); } public void setFailureResult(String string) { this.failureResult = string; } public void setSuccessResult(Script script) { this.successResult = script; } public void genericMessageReceived(){ finishedThinking(); } public void setLectureMode(boolean b) { viewController.setLectureMode(b); } public void finishedThinking(){ int correct = 0; int score = 0; List<BayesNode> priorNodes = new ArrayList<BayesNode>(); List<BayesNode> otherNodes = new ArrayList<BayesNode>(); Map<BayesNode,Fraction> probabilities = new HashMap<BayesNode,Fraction>(); for (BayesNode n : gameNet){ if (targetNodes.contains(n.type)){ Fraction probability = n.getProbability(); probabilities.put(n, probability); if (n.cptName.equals("Prior")){ priorNodes.add(n); } else { otherNodes.add(n); } } } int scoreThreshold = probabilities.size() / 2; /* if (probabilities.size() % 2 == 1){ scoreThreshold++; } */ priorNodes.addAll(otherNodes); viewController.clearText(); viewController.showText("With " + probabilities.size() + " variables, you need to get more than " + scoreThreshold + " predictions correct in order to gain points."); for (BayesNode n : priorNodes){ n.observe(); gameNet.updateBeliefs(); Fraction oldProbability = probabilities.get(n); boolean prediction = oldProbability.compareTo(Fraction.ONE_HALF) > 0; Fraction newProbability = n.getProbability(); boolean actualValue = newProbability.equals(Fraction.ONE); String adjective =""; if (prediction == actualValue){ correct++; adjective = " YAY! "; if (correct > scoreThreshold){ score++; adjective = adjective + "SCORE! "; } } else { n.addProperty("misguessed"); } if (correct <= scoreThreshold){ viewController.showText("Variable " + n.type + ": had " + (int)(oldProbability.doubleValue()*100) + "% probability, so you guess that it's " + prediction + ". Is " + actualValue + ". " + adjective + "Correct predictions: " + correct + " (need " + (scoreThreshold+1 - correct) + " more), score: " + score); } else { viewController.showText("Variable " + n.type + ": had " + (int)(oldProbability.doubleValue()*100) + "% probability, so you guess that it's " + prediction + ". Is " + actualValue + ". " + adjective + "Correct predictions: " + correct + " score: " + score); } viewController.updateGraph(); } if (correct == probabilities.size()){ int scorebonus = probabilities.size() / 2; score = score + scorebonus; viewController.showText("All predictions correct! Bonus score: " + scorebonus + ", total score: " + score); } GameCharacters.PC.pointsToSkill("Psychology", score, this); viewController.updateStatusText(); clear(true); } public void showText(String string) { viewController.showText(string); } }