Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose underlying ObjectTree that represents the state of the game. #70

Merged
merged 4 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Loading