This project has been developed as part of the Master of Professional Engineering (software) research project at the University of Western Australia.
Building primarily on the research done by Michael Thielscher to further research on General Game Playing (GGP) in incomplete information games.
The base code to run the basic agents (legal, random) came from combining code from the following resources:
- https://github.com/arnaudsj/ggpserver
- https://sourceforge.net/projects/ggpserver/files/gamecontroller/
To build GameController run:
$ ant -f my-build.xml
This will create three jar files:
- gamecontroller.jar - used by ggpserver
- gamecontroller-cli.jar - the command line version
- gamecontroller-gui.jar - a version with a simple gui
You can run the CLI and GUI versions of gamecontroller with $ java -jar gamecontroller-???.jar
To use the stylesheets in the resources/ directory you have
to run GameController with the parameter "-printxml OUTPUTDIR XSLT"
where OUTPUTDIR is a directory in which GameController writes xml files,
one for each state of the match and XSLT is a relative or absolute URL
to some xslt stylesheet that is referenced from the state xml files.
It's a bit tricky to get the directories right, because image references
in the xslt have to be relative to the state xml. The xsl files in the
resources directory assume that OUTPUTDIR is in the same directory as the
stylesheets directory.
E.g., the following directory structure and parameter should work:
./matches/ # a directory for the xml files
./stylesheets/ # the stylesheets from resources directory
$ java -jar gamecontroller-cli.jar SomeMatchID bidding-tictactoe.gdl 120 30
-remote 2 MyPlayer localhost 4000
-printxml matches/ ../../stylesheets/bidding_tictactoe/bidding_tictactoe.xsl
This should generate the following files:
./matches/SomeMatchID/step_*.xml
./matches/SomeMatchID/finalstate.xml
Just open any of the xml files in a web browser that supports xslt (the stylesheets
are known to work with Firefox 3).
If you open local files you might have to change settings in Firefox, because the URL
to the stylesheets contains "..". Type "about:config" in the address bar and change
the following setting:
security.fileuri.strict_origin_policy=false
- Run the following command
$ java -jar gamecontroller-gui.jar
- Select a valid gdl game and select the version
- Choose the players (only works for local players)
- View the results
This method allows the running of multiple games through scripting and outputs the results in xml format for automatic parsing.
Run the following command:
java -jar gamecontroller-cli.jar MATCH_ID GAMEFILE START_CLOCK PLAY_CLOCK GDL_VERSION -PLAYER_NAME_1 ROLE_ID_1 -PLAYER_NAME_2 ROLE_ID_2 -printxml OUTPUT_DIR/ ../../stylesheets/2player_normal_form/2player_normal_form.xsl
Where:
- MATCH_ID - Unique ID for each match
- GAMEFILE - A valid GDL or GDL-II game (ending in .kif or .gdl)
- START_CLOCK - The length in seconds before the game begins
- PLAY_CLOCK - The length in seconds given to each player on every turn
- GDL_VERSION - An integer representing the version of GDL the GAMEFILE uses (GDL -> 1, GDL-II -> 2)
- -PLAYER_NAME - A valid name given to the player implemented (instructions below)
- ROLE_ID - An integer representing the role of the player (>=1)
- -printxml OUTPUT_DIR/ ../../stylesheets/2player_normal_form/2player_normal_form.xsl - Outputs the results of the game to OUTPUT_DIR for a generic two player normal form game (use when the GAMEFILE doesn't match any other stylesheet)
- XXXXPlayer.java
- XXXXPlayerInfo.java
- players\PlayerInfo.java
- players\PlayerFactory.java
- gui\PlayerType.java
- gui\PlayerTableModel.java
- gui\JPlayerTable.java
-
Create a new XXXXPlayer.java class from an existing LegalPlayer.java class and change the move selection as required
-
Create a new XXXXPlayerInfo.java class from an existing LegalPlayerInfo.java class and rename it
-
Add the line:
public static final String TYPE_XXXX = "xxxx";
to the top of the PlayerInfo.java class -
Add a createXXXPlayer function to PlayerFactory.java
e.g.public static <TermType extends TermInterface, StateType extends StateInterface<TermType, ? extends StateType>> Player<TermType, StateType> createXXXXPlayer(XXXXPlayerInfo info) { return newXXXX Player<TermType, StateType>(info.getName(), info.getGdlVersion()); }
-
Extend the else-if logic in the createPlayer function in PlayerFactory.java e.g.
else if(info instanceof XXXXPlayerInfo){ return PlayerFactory. <TermType, StateType> createXXXXPlayer((XXXXPlayerInfo)info); }
-
Add XXXX to the PlayerType.java enum
-
Extend the else-if logic in the getPlayerInfo function in the PlayerTableModel.java class e.g.
else if(type.equals(PlayerType.XXXX)){ return new XXXXPlayerInfo(row,GDLVersion.v1); }
-
Add PlayerType.XXXX to the PlayerTypeCellEditor constructor in the PlayerTypeCellEditor private class in the JPlayerTable.java class
- XXXXPlayer.java
- XXXXPlayerInfo.java
- players\PlayerInfo.java
- players\PlayerFactory.java
- cli\AbstractGameControllerCLIRunner.java
-
Create a new XXXXPlayer.java class from an existing LegalPlayer.java class and change the move selection as required
-
Create a new XXXXPlayerInfo.java class from an existing LegalPlayerInfo.java class and rename it
-
Add the line:
public static final String TYPE_XXXX = "xxxx";
to the top of the PlayerInfo.java class -
Add a createXXXPlayer function to PlayerFactory.java
e.g.public static <TermType extends TermInterface, StateType extends StateInterface<TermType, ? extends StateType>> Player<TermType, StateType> createXXXXPlayer(XXXXPlayerInfo info) { return newXXXX Player<TermType, StateType>(info.getName(), info.getGdlVersion()); }
-
Extend the else-if logic in the createPlayer function in PlayerFactory.java e.g.
else if(info instanceof XXXXPlayerInfo){ return PlayerFactory. <TermType, StateType> createXXXXPlayer((XXXXPlayerInfo)info); }
-
Extend the else-if logic in the parsePlayerArguments funciton in AbstractGameControllerCLIRunner.java e.g.
else if(argv[index].equals("-xxxx")){ ++index; if(argv.length>=index+1){ int roleindex=getIntArg(argv[index], "roleindex"); ++index; if(roleindex<1){ System.err.println("roleindex out of bounds"); printUsage(); System.exit(-1); } player=new XXXXPlayerInfo(roleindex-1, getGdlVersion()); }else{ missingArgumentsExit(argv[index-1]); } }
The testing script works by reading a config file to run multiple games and uses a python script to parse the results to multiple .csv files.
The output of the matches is contained in a file 'testOutput_TIMESTAMP' of the format:
match_id, game_name, gdl_version, timestamp, startclock, playclock, sight_of, num_steps, role_1, player_1, player_1_score, role_2, player_2, player_2_score
And the output of each move for each game is put in a file titles 'match_id' that links to the match_id of the game above. It is of the form:
match_id, game_name, step, role_name, player_name, count_hypergames, num_probes, time_to_update, time_to_select_move, move_chosen
-
First build the application by running
$ ant -f my-build.xml
-
Define a config file of the following format:
- MATCH_ID = Identifier for the match to be carried out (will be enumerated for multiple tests)
- GAMEFILE = Location of the game to play
- GAMENAME = Name of the game for logging purposes
- START_CLOCK = Number of seconds before the game beings
- PLAY_CLOCK = Number of seconds each player will have for each turn
- GDL_VERSION = The version of GDL the game uses [1 or 2]
- PLAYER_NAME_1 = The PlayerInfo type of player
- ROLE_ID_1=1
- ROLE_NAME_1 = The name of the role player 1 will have in the game for logging purposes
- PLAYER_NAME_2 = The PlayerInfo type of player
- ROLE_ID_2=2
- ROLE_NAME_2 = The name of the role player 2 will have in the game for logging purposes
- OUTPUT_DIR = The directory to output the data to
- STYLESHEET="../../stylesheets/2player_normal_form/2player_normal_form.xsl"
- NUMTESTS = Number of games to run
e.g.
MATCH_ID="randomhyper" GAMEFILE="testdata/games/games_gdl/montyhall/montyhall.gdl" GAMENAME="montyhall" START_CLOCK=10 PLAY_CLOCK=60 GDL_VERSION=2 PLAYER_NAME_1="hyper" ROLE_ID_1=1 ROLE_NAME_1="CANDIDATE" PLAYER_NAME_2="random" ROLE_ID_2=2 ROLE_NAME_2="RANDOM" OUTPUT_DIR="matches/" STYLESHEET="../../stylesheets/2player_normal_form/2player_normal_form.xsl" NUMTESTS=10
-
Modify the runTest.sh script so the SOURCE points to the config file e.g.
source tests/testConfig/gdl2_montyhall.txt
-
Run the testing script
runTest.sh
A Jupyter Notebook was developed since this is the most obvious way to analyze .csv data and display it in an easy to read and modify way.
The notebook is stored in the folder '/tests/testAnalysis/TestAnalysis.ipynb'