Skip to content

Commit

Permalink
Merge pull request #70 from allenai/obj_tree
Browse files Browse the repository at this point in the history
Expose underlying ObjectTree that represents the state of the game.
  • Loading branch information
MarcCote committed Jun 6, 2024
2 parents 35a9500 + dbc2c18 commit 4f86d5e
Show file tree
Hide file tree
Showing 16 changed files with 206 additions and 2 deletions.
Binary file modified scienceworld/scienceworld.jar
Binary file not shown.
17 changes: 17 additions & 0 deletions scienceworld/scienceworld.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from typing import OrderedDict as OrderedDictType
import json
import logging
import tempfile
from collections import OrderedDict
from os.path import join as pjoin

from py4j.java_gateway import JavaGateway, GatewayParameters, launch_gateway, CallbackServerParameters

Expand Down Expand Up @@ -79,6 +81,8 @@ def __init__(self, taskName: str = None, serverPath: str = None, envStepLimit: i
# By default, set that the gold path was not generated unless the user asked for it
self.goldPathGenerated = False

self._obj_tree_tempdir = tempfile.TemporaryDirectory()

# Ask the simulator to load an environment from a script
def load(self, taskName: str, variationIdx: int = 0, simplificationStr: str = "",
generateGoldPath: bool = False) -> None:
Expand Down Expand Up @@ -271,6 +275,19 @@ def get_task_description(self) -> str:
''' Get the description of the current task. '''
return self.server.getTaskDescription()

# Get the current game's task description
def getObjectTree(self):
msg = self.server.getObjectTree(self._obj_tree_tempdir.name)
if msg:
# Game is not initialized.
raise RuntimeError(msg)

with open(pjoin(self._obj_tree_tempdir.name, 'objectTree.json')) as f:
payload = json.load(f)

return payload

#
# History
def get_run_history(self) -> Dict[str, Any]:
''' Get the run history '''
Expand Down
2 changes: 1 addition & 1 deletion simulator/build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name := "scienceworld-scala"

version := "1.2.0rc1"
version := "1.2.0rc2"

scalaVersion := "2.12.9"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ class ContainerProperties(
// Add properties for storing different kinds of things? (e.g. can store solids? liquids? gasses? etc)
) {

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"isContainer\":\"" + this.isContainer + "\",")
os.append("\"isOpen\":" + this.isOpen + ",")
os.append("\"isClosable\":" + this.isClosable)
os.append("}")

return os.toString()
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ class CoolingSourceProperties(var minTemp:Double, var curSetTemp:Option[Double])
curSetTemp = None
}


def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"minTemp\":" + this.minTemp + ",")
os.append("\"curSetTemp\":" + (if (this.curSetTemp.isEmpty) "null" else this.curSetTemp.get))
os.append("}")

return os.toString()
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ trait DeviceProperties {
var isActivated:Boolean = false
var isUsable:Boolean = false
var isBroken:Boolean = false // For devices that are broken (e.g. for environment ablations)

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"isActivable\":" + this.isActivable + ",")
os.append("\"isActivated\":" + this.isActivated + ",")
os.append("\"isUsable\":" + this.isUsable + ",")
os.append("\"isBroken\":" + this.isBroken)
os.append("}")

return os.toString()
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ package scienceworld.properties
trait EdibilityProperties {
var isEdible:Boolean = true
var isPoisonous:Boolean = false

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"isEdible\":" + this.isEdible + ",")
os.append("\"isPoisonous\":" + this.isPoisonous)
os.append("}")

return os.toString()
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import scienceworld.struct.EnvObject
import scienceworld.struct.EnvObject._

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

// A storage class for an electrical connection point (e.g. anode, cathode)
class ElectricalConnectionProperties {
Expand Down Expand Up @@ -56,4 +57,21 @@ class ElectricalConnectionProperties {
this.connectedTo.map(_.getDescription(MODE_CURSORY_DETAIL)).mkString(", ")
}


def toJSON():String = {
val os = new StringBuilder()
os.append("{")

// Connected objects
val connection_json = new ArrayBuffer[String]()
for (obj <- this.connectedTo.toArray.sortBy(_.uuid)) {
connection_json.append("\"" + obj.uuid + "\"")
}

os.append("\"connectedTo\": " + connection_json.mkString("[", ",", "]"))
os.append("}")

return os.toString()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ class HeatSourceProperties(var maxTemp:Double, var curSetTemp:Option[Double]) {
curSetTemp = None
}


def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"maxTemp\":" + this.maxTemp + ",")
os.append("\"curSetTemp\":" + (if (this.curSetTemp.isEmpty) "null" else this.curSetTemp.get))
os.append("}")

return os.toString()
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ class LifeProperties {
// Typical lifespan (in years) -- note, this does not currently affect the simulation, but is used for question answering.
var lifespanTypical:Double = 0.0f

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"lifeformType\": \"" + this.lifeformType + "\",")
os.append("\"minTemp\":" + this.minTemp + ",")
os.append("\"maxTemp\":" + this.maxTemp + ",")
os.append("\"isSickly\":" + this.isSickly + ",")
os.append("\"isDead\":" + this.isDead + ",")
os.append("\"lifespanTypical\":" + this.lifespanTypical)
os.append("}")

return os.toString()
}

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ trait MaterialProperties {
// Friction
var frictionCoefficient:Double = 0.50 // 0 is no friction, 1 is complete friction


def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"substanceName\":\"" + this.substanceName + "\",")
// os.append("\"nameInStateOfMatter\":\"" + this.nameInStateOfMatter + "\",")
os.append("\"color\":\"" + this.color + "\",")
os.append("\"temperatureC\":" + this.temperatureC + ",")
os.append("\"thermalConductivity\":" + this.thermalConductivity + ",")
os.append("\"stateOfMatter\":\"" + this.stateOfMatter + "\",")
os.append("\"boilingPoint\":" + this.boilingPoint + ",")
os.append("\"meltingPoint\":" + this.meltingPoint + ",")
os.append("\"isCombusting\":" + this.isCombusting + ",")
os.append("\"hasCombusted\":" + this.hasCombusted + ",")
os.append("\"combustionTicks\":" + this.combustionTicks + ",")
os.append("\"electricallyConductive\":" + this.electricallyConductive + ",")
os.append("\"frictionCoefficient\":" + this.frictionCoefficient)
os.append("}")

return os.toString()
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,13 @@ package scienceworld.properties

class MoveableProperties(val isMovable:Boolean) {

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"isMovable\":" + this.isMovable)
os.append("}")

return os.toString()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,18 @@ class PortalProperties(var isOpen:Boolean,
val isLockable:Boolean,
val isLocked:Boolean) {

def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"isOpen\":" + this.isOpen + ",")
os.append("\"isOpenable\":" + this.isOpenable + ",")
os.append("\"connectsFrom\": \"" + this.connectsFrom.uuid + "\",")
os.append("\"connectsTo\": \"" + this.connectsTo.uuid + "\",")
os.append("\"isLockable\":" + this.isLockable + ",")
os.append("\"isLocked\":" + this.isLocked)
os.append("}")

return os.toString()
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package scienceworld.runtime.pythonapi

import java.io.{File, FileOutputStream,PrintWriter}

import main.scala.scienceworld.runtime.SimplifierProcessor
import scienceworld.environments.EnvironmentMaker
import scienceworld.goldagent.RunHistory
Expand Down Expand Up @@ -323,6 +325,18 @@ class PythonInterface() {
agentInterface.get.getTaskDescription()
}

def getObjectTree(folderPath:String = ""):String = {
if (agentInterface.isEmpty) return ERROR_MESSAGE_UNINITIALIZED

val objTree = agentInterface.get.universe.toJSON()
if (folderPath == "") return objTree

var pw = new PrintWriter(folderPath + "/objectTree.json");
pw.print(objTree)
pw.close()
return ""
}

/*
* Take action steps and get observations/scores
*/
Expand Down
36 changes: 35 additions & 1 deletion simulator/src/main/scala/scienceworld/struct/EnvObject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,42 @@ class EnvObject(var name:String, var objType:String, includeElectricalTerminals:
os.toString()
}

}
def toJSON():String = {
val os = new StringBuilder()
os.append("{")
os.append("\"uuid\":\"" + this.uuid + "\",")
os.append("\"name\":\"" + this.name + "\",")
os.append("\"type\":\"" + this.objType + "\",")
os.append("\"isDeleted\":" + this.isDeleted + ",")

// Properties
os.append("\"propMaterial\":" + (if (this.propMaterial.isEmpty) "null" else this.propMaterial.get.toJSON()) + ",")
os.append("\"propEdibility\":" + (if (this.propEdibility.isEmpty) "null" else this.propEdibility.get.toJSON()) + ",")
os.append("\"propContainer\":" + (if (this.propContainer.isEmpty) "null" else this.propContainer.get.toJSON()) + ",")
os.append("\"propDevice\":" + (if (this.propDevice.isEmpty) "null" else this.propDevice.get.toJSON()) + ",")
os.append("\"propHeatSource\":" + (if (this.propHeatSource.isEmpty) "null" else this.propHeatSource.get.toJSON()) + ",")
os.append("\"propCoolingSource\":" + (if (this.propCoolingSource.isEmpty) "null" else this.propCoolingSource.get.toJSON()) + ",")

os.append("\"propPortal\":" + (if (this.propPortal.isEmpty) "null" else this.propPortal.get.toJSON()) + ",")
os.append("\"propMoveable\":" + (if (this.propMoveable.isEmpty) "null" else this.propMoveable.get.toJSON()) + ",")
os.append("\"propElectricalConnection\":" + (if (this.propElectricalConnection.isEmpty) "null" else this.propElectricalConnection.get.toJSON()) + ",")
os.append("\"propLife\":" + (if (this.propLife.isEmpty) "null" else this.propLife.get.toJSON()) + ",")

// os.append("\"propChromosomePairs\":" + (if (this.propChromosomePairs.isEmpty) "null" else this.propChromosomePairs.get.toJSON()) + ",")
// os.append("\"propPollination\":" + (if (this.propPollination.isEmpty) "null" else this.propPollination.get.toJSON()) + ",")

// Contents
val contents_json = new ArrayBuffer[String]()
for (obj <- this.getContainedObjects()) {
contents_json.append("\"" + obj.name + "-" + obj.uuid + "\": " + obj.toJSON())
}

os.append("\"contents\": " + contents_json.mkString("{", ",", "}"))
os.append("}")
return os.toString()
}

}

object EnvObject {
val MODE_CURSORY_DETAIL = 0
Expand Down
7 changes: 7 additions & 0 deletions tests/test_scienceworld.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,10 @@ def test_consistent_task_names():
"""Verify that Scala and Python code use the same task names."""
env = ScienceWorldEnv()
assert sorted(env.task_names) == sorted(env.get_task_names())


def test_obj_tree():
env = ScienceWorldEnv("1-1")
env.reset()
obj_tree = env.getObjectTree()
print(obj_tree)

0 comments on commit 4f86d5e

Please sign in to comment.