package org.ggp.base.apps.utilities; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.ggp.base.server.GameServer; import org.ggp.base.server.event.ServerCompletedMatchEvent; import org.ggp.base.server.event.ServerNewGameStateEvent; import org.ggp.base.server.event.ServerNewMovesEvent; import org.ggp.base.util.crypto.BaseCryptography.EncodedKeyPair; import org.ggp.base.util.crypto.SignableJSON; import org.ggp.base.util.files.FileUtils; import org.ggp.base.util.game.Game; import org.ggp.base.util.game.GameRepository; import org.ggp.base.util.gdl.grammar.GdlSentence; import org.ggp.base.util.match.Match; import org.ggp.base.util.observer.Event; import org.ggp.base.util.observer.Observer; import org.ggp.base.util.statemachine.MachineState; import org.ggp.base.util.statemachine.Role; import external.JSON.JSONException; import external.JSON.JSONObject; /** * SimpleGameSim is a utility program that lets you simulate play through a * given game, and see which propositions become true/false in each state as * the game is played. This can be used to understand how a game runs, or to * debug issues in the state machine implementation. * * It can also hide the step counter / control proposition, though this is * done in a very naive way, by just looking for (step ?x) and (control ?x) * propositions. None the less, it's still useful to have. * * @author Sam Schreiber */ public class SimpleGameSim { public static final boolean hideStepCounter = true; public static final boolean hideControlProposition = true; public static final boolean showCurrentState = false; public static void main(String[] args) throws InterruptedException { final Game theGame = GameRepository.getDefaultRepository().getGame("nineBoardTicTacToe"); final Match theMatch = new Match("simpleGameSim." + Match.getRandomString(5), -1, 0, 0, theGame, ""); try { // Load a sample set of cryptographic keys. These sample keys are not secure, // since they're checked into the public GGP Base SVN repository. They are provided // merely to illustrate how the crypto key API in Match works. If you want to prove // that you ran a match, you need to generate your own pair of cryptographic keys, // keep them secure and hidden, and pass them to "setCryptographicKeys" in Match. // The match will then be signed using those keys. Do not use the sample keys if you // want to actually prove anything. theMatch.setCryptographicKeys(new EncodedKeyPair(FileUtils.readFileAsString(new File("src/main/resources/org/ggp/base/apps/utilities/SampleKeys.json")))); } catch (JSONException e) { System.err.println("Could not load sample cryptograhic keys: " + e); } // Set up fake players to pretend to play the game List<String> fakeHosts = new ArrayList<String>(); List<Integer> fakePorts = new ArrayList<Integer>(); for (int i = 0; i < Role.computeRoles(theGame.getRules()).size(); i++) { fakeHosts.add("SamplePlayer" + i); fakePorts.add(9147+i); } // Set up a game server to play through the game, with all players playing randomly. final GameServer theServer = new GameServer(theMatch, fakeHosts, fakePorts); for (int i = 0; i < fakeHosts.size(); i++) { theServer.makePlayerPlayRandomly(i); } // TODO: Allow a custom state machine to be plugged into the GameServer so that we can // simulate games using this tool with custom state machines, to verify they're sane. final Set<GdlSentence> oldContents = new HashSet<GdlSentence>(); final int[] nState = new int[1]; theServer.addObserver(new Observer() { @Override public void observe(Event event) { if (event instanceof ServerNewGameStateEvent) { MachineState theCurrentState = ((ServerNewGameStateEvent)event).getState(); if(nState[0] > 0) System.out.print("State[" + nState[0] + "]: "); Set<GdlSentence> newContents = theCurrentState.getContents(); for(GdlSentence newSentence : newContents) { if(hideStepCounter && newSentence.toString().contains("step")) continue; if(hideControlProposition && newSentence.toString().contains("control")) continue; if(!oldContents.contains(newSentence)) { System.out.print("+" + newSentence + ", "); } } for(GdlSentence oldSentence : oldContents) { if(hideStepCounter && oldSentence.toString().contains("step")) continue; if(hideControlProposition && oldSentence.toString().contains("control")) continue; if(!newContents.contains(oldSentence)) { System.out.print("-" + oldSentence + ", "); } } System.out.println(); oldContents.clear(); oldContents.addAll(newContents); if(showCurrentState) System.out.println("State[" + nState[0] + "] Full: " + theCurrentState); nState[0]++; } else if (event instanceof ServerNewMovesEvent) { System.out.println("Move taken: " + ((ServerNewMovesEvent)event).getMoves()); } else if (event instanceof ServerCompletedMatchEvent) { System.out.println("State[" + nState[0] + "] Full (Terminal): " + oldContents); System.out.println("Match information: " + theMatch); System.out.println("Goals: " + ((ServerCompletedMatchEvent)event).getGoals()); try { System.out.println("Match information cryptographically signed? " + SignableJSON.isSignedJSON(new JSONObject(theMatch.toJSON()))); System.out.println("Match information cryptographic signature valid? " + SignableJSON.verifySignedJSON(new JSONObject(theMatch.toJSON()))); } catch (JSONException je) { je.printStackTrace(); } System.out.println("Game over."); } } }); theServer.start(); theServer.join(); } }