package PinBallDomain; import org.rlcommunity.rlglue.codec.EnvironmentInterface; import org.rlcommunity.rlglue.codec.types.Action; import org.rlcommunity.rlglue.codec.types.Observation; import org.rlcommunity.rlglue.codec.types.Reward_observation_terminal; import org.rlcommunity.rlglue.codec.util.EnvironmentLoader; import org.rlcommunity.rlglue.codec.taskspec.TaskSpecVRLGLUE3; import org.rlcommunity.rlglue.codec.taskspec.TaskSpec; import org.rlcommunity.rlglue.codec.taskspec.ranges.IntRange; import org.rlcommunity.rlglue.codec.taskspec.ranges.DoubleRange; /** * RLGlue interface for PinBall. * This file based on the RLGlue Java codec SkeletonEnvironment. * Many thanks to Brian Tanner and associates at Alberta. *
* Note: change the config_file
variable in this class to
* point to the desired configuration file, or send message
* "config file =..." to set it via RLGlue. The message
* "config file?" returns the current config_file
variable setting.
*
* Please note: I have only tested this briefly (with a random agent connected via * the Java codec). If you find bugs, please let me know and I will fix them ASAP. * * @author George Konidaris (gdk at cs dot umass dot edu) * @version 1.0 */ public class PinBallRLGlue implements EnvironmentInterface { /** * Make the agent easily loadable. * * @param args command line arguments: ignored */ public static void main(String[] args) { EnvironmentLoader theLoader=new EnvironmentLoader(new PinBallRLGlue()); theLoader.run(); } /** * Initialize the domain programmatically. This seems to * return a string describing the environment so an agent can * decide how to deal with it if it doesn't already know. */ public String env_init() { TaskSpecVRLGLUE3 theTaskSpecObject = new TaskSpecVRLGLUE3(); theTaskSpecObject.setEpisodic(); theTaskSpecObject.setDiscountFactor(1.0d); theTaskSpecObject.addContinuousObservation(new DoubleRange(0, 1)); theTaskSpecObject.addContinuousObservation(new DoubleRange(0, 1)); theTaskSpecObject.addContinuousObservation(new DoubleRange(0, 1)); theTaskSpecObject.addContinuousObservation(new DoubleRange(0, 1)); theTaskSpecObject.addDiscreteAction(new IntRange(0, 4)); theTaskSpecObject.setRewardRange(new DoubleRange(-5, 10000)); String taskSpecString = theTaskSpecObject.toTaskSpec(); TaskSpec.checkTaskSpec(taskSpecString); return taskSpecString; } /** * Create the environment and return its initial state. * * @return initial state observation */ public Observation env_start() { pinball = new PinBall(configfile); Observation returnObservation=new Observation(0,4,0); PinBallState s = pinball.getState(); for(int j = 0; j < 4; j++) { returnObservation.doubleArray[j] = s.getDescriptor()[j]; } return returnObservation; } /** * Take one step in the environment. * * @param thisAction the action to take * @return the resulting state observation */ public Reward_observation_terminal env_step(Action thisAction) { boolean episodeOver=false; double theReward=0.0d; int act = thisAction.intArray[0]; theReward = pinball.step(act); PinBallState sprime = pinball.getState(); episodeOver = pinball.episodeEnd(); Observation returnObservation=new Observation(0,4,0); for(int j = 0; j < 4; j++) { returnObservation.doubleArray[j]=sprime.getDescriptor()[j]; } Reward_observation_terminal returnRewardObs=new Reward_observation_terminal(theReward,returnObservation,episodeOver); return returnRewardObs; } /** * Nothing to do here. */ public void env_cleanup() { } /** * Respond to messages. At the moment, this allows you to query and change * the name of the config file. After changing it you should start a new episode. * * @param message incoming message * @return reply */ public String env_message(String message) { if(message.equals("config file?")) { return configfile; } else if(message.startsWith("config file=")) { int pos = message.indexOf('='); configfile = message.substring(pos + 1, message.length()); System.out.println("Config file changed to: " + configfile); return configfile; } return "I don't know how to respond to your message"; } PinBall pinball; String configfile = "../pinball.cfg"; }