# Scripting API
# Actions
The player actions object is represented by the global object a
. The player actions object is used to assign choices to players and record experiment data.
# Methods
# add(Vertex player, Map choices)
# add(Vertex player, Closure init, Map choices)
# Parameters
Parameter | Type | Default | Description |
---|---|---|---|
player | Vertex | The vertex, player, in the graph who is making this choice | |
init optional | Closure | A closure that is run when this choice or choices are displayed | |
choices | Map<Choice> | A map matching the Choice interface |
# Example
// Add the choices to cooperate or defect to each player in the graph
g.V.each { v->
a.add(v,
[name: "Cooperate",
result: {
v.cooperation = 1
v.score -= coc * v.neighbors.count()
v.neighbors.each { n->
n.score += po
}
}],
[name: "Defect",
result: {
v.cooperation = -1
}]
)
}
# a.addEvent(String eventName, Map data)
Record an event in the experiment data not associated with a player action.
Parameter | Type | Default | Description |
---|---|---|---|
eventName | String | A string identifying the event in the data | |
data | Map | A map with one or more key-value pairs where the keys and values are both (max 255 character) strings |
# Example
// Record the experiment's initial parameters in the data
a.addEvent("GameParameters",
["coc":coc,
"po":po,
"initScore":initScore,
"nRounds":nRounds]
)
# a.empty()
Remove all assigned player actions
# a.remove(Vertex v)
# a.remove(String playerId)
Remove all player actions assigned to vertex v
or player with the matching id.
Parameter | Type | Default | Description |
---|---|---|---|
v | Vertex | A vertex as returned by g.getVertex(id) | |
playerId | String | A player id |
# a.setDropPlayers(Boolean dropPlayers)
Whether or not to drop players that aren't interacting with the game within the configured amount of time (set by setIdleTime
)
Parameter | Type | Default | Description |
---|---|---|---|
dropPlayers | Boolean | True means players will be dropped |
# a.setDropPlayerClosure(Closure dropPlayerClosure)
Configure behavior when a player is inactive and will be dropped.
Parameter | Type | Default | Description |
---|---|---|---|
dropPlayerClosure | Closure | {} | Do something with the player when they are dropped. |
# a.setDropPlayers(Boolean dropPlayers)
Whether or not to drop players that aren't interacting with the game within the configured amount of time (set by setIdleTime
)
Parameter | Type | Default | Description |
---|---|---|---|
dropPlayers | Boolean | false | Whether or not the players will be dropped. |
# a.setDropTime(Long dropTime)
How long to wait before "dropping" the player. Starts counting when they are inactive.
Parameter | Type | Default | Description |
---|---|---|---|
dropTime | Long | Time to wait before dropping a player |
# a.setIdleTime(Long idleTime)
How long to wait before "firing" the player.
Parameter | Type | Default | Description |
---|---|---|---|
idleTime | Long | How long to wait before showing the idle timer. |
# a.size(): Integer
Size of the actions queue.
# a.turnAIOff()
Turn all AI off.
# a.turnAIOn()
Turn all AI on.
# Content fetcher
The content object is represented by the global object c
. The content object is used to retrieve html entered using the Content dialog.
# Methods
# c.get(String contentId[, optional: fill_0, fill_1, ...])
# c.getTranslated(String contentId, String languageCode[, optional: fill_0, fill_1, ...])
Parameter | Type | Default | Description |
---|---|---|---|
contentId | String | Matches the name of the tab in the Content dialog | |
languageCode | String | The matching code in the translations panel | |
fill_n | Object | Values to use for interpolation |
# Example
Given content within a "Tutorial" tab with the following HTML value:
<p>
Each round you may make the choice to contribute {0} points for
each player you are connected with to award them {1} points.
</p>
// Display tutorial text to each client
// Fill in the coc and po parameters in the content
g.V.each { v->
v.text = c.get("Tutorial", coc, po)
}
If the coc parameter is set to 50 and the po parameter is set to 100 the following text would be displayed:
Each round you may make the choice to contribute 50 points for each player you are connected with to award them 100 points.
# c.setDefaultLanguage(String language)
Set which language will be used when c.get(name)
is called. Doesn't affect c.getTranslated(name, language)
Parameter | Type | Default | Description |
---|---|---|---|
languageCode | String | A valid language code or name |
# c.interpolate(String content, Object[] parameters)
If provided, each value will replace {n}
in the content where n
is an integer starting from 0 that matches the position of the fill parameter.
Parameter | Type | Default | Description |
---|---|---|---|
content | String | A string with content to interpolate. Works the same way the get and getTranslated methods work. | |
parameters | Object[] | One or more values to replace {n} with. |
# Returns
String
# Graph
In scripts, the graph is represented by the global object, g
. The graph is an in-memory Blueprints TinkerGraph (opens new window) and all methods as described in the JavaDoc (opens new window) are available. The most commonly used methods and properties of the g
object, including those added by breadboard, are listed below.
See graph algorithms for additional graph methods.
# Properties
# g.V
The collection of vertices in the graph
# Example
// iterate through the vertices and assign each a score of 100
g.V.each { v->
v.score = 100
}
# g.E
The collection of edges in the graph
# Methods
# g.addAI(a, n, [behavior])
Parameter | Type | Default | Description |
---|---|---|---|
a | PlayerActions | The PlayerAction object, must be a | |
n | Integer | Number of AI players to add to the graph with random behavior, by default | |
behavior optional | Closure | A closure that is run when the AI player has a choice to make |
# Example
def aiBehavior = { ai->
// Sanity check to make sure the AI actually has choices to make
if (ai.getProperty("choices")) {
// A random delay is a good idea to make the AI
// appear more human and to avoid potential race conditions
def randomDelay = 1000 + r.nextInt(3000)
new Timer().runAfter(randomDelay) {
def choices = ai.getProperty("choices")
// Choose a random choice
def choice = choices[r.nextInt(choices.size())]
a.choose(choice.uid)
}
}
}
// Add 20 AI players using the defined behavior
g.addAI(a, 20, aiBehavior)
# g.addVertices(n)
Parameter | Type | Default | Description |
---|---|---|---|
n | Integer | Number of vertices to add to the graph |
# g.empty()
This method removes all edges and vertices from the graph. Note: This does not drop players from the game. A removed vertex will be re-added to the graph when a player refreshes their browser window (this will cause the onJoinStep to be run again).
# g.getEdge(Vertex v1, Vertex v2)
This method returns an Edge as identified by the two connected vertices or null if no edge exists between the vertices.
Parameter | Type | Default | Description |
---|---|---|---|
v1 | Vertex | A vertex as returned by g.getVertex | |
v2 | Vertex | A vertex as returned by g.getVertex |
# Returns
Edge
# g.getVertex(String id)
This method returns a vertex as identified by the provided ID or null if no vertex exists.
Parameter | Type | Default | Description |
---|---|---|---|
id | String | The unique ID identifying the vertex in the graph |
# Returns
Vertex
# g.hasEdge(Player v1, Player v2)
This method returns true
if there is an edge that connects the vertices provided or false
otherwise.
Parameter | Type | Default | Description |
---|---|---|---|
v1 | Vertex | A vertex as returned by g.getVertex | |
v2 | Vertex | A vertex as returned by g.getVertex |
# Returns
Boolean
# g.removeEdges()
# g.removeEdges(Vertex v)
If a vertex, v
is provided, this method removes the edges connected to the given vertex; otherwise, this method removes all edges in the graph.
Parameter | Type | Default | Description |
---|---|---|---|
v | Vertex | A vertex as returned by g.getVertex |
# g.removeVertices()
This method removes all vertices in the graph. Note: This method does not handle dropping players from a game (see g.empty()
).
# g.getSubmitForm(Vertex player, String bonus)
# g.getSubmitForm(Vertex player, String bonus, String reason, Boolean sandbox, Boolean comments)
This utility method returns a submit form that can be displayed to AMT workers at the completion of their task.
Parameter | Type | Default | Description |
---|---|---|---|
player | Vertex | A vertex as returned by g.getVertex | |
bonus | String | The amount of the bonus, in US Dollars, to be applied to the player. Should be set to 0 if no bonus is awarded | |
reason optional | String | "completed" | A text tag to keep track of why the player is submitting the task (e.g. dropped/too_many_players/failed_test) |
sandbox optional | Boolean | false | If true, it will create a form that will submit to the AMT sandbox, useful for testing |
comments optional | Boolean | false | If true, it will add a text area for free text comments by the participants. These comments can be viewed by logging into the AMT Requester account and downloading the data. |
# Example
// The FinishedStep is run when the game has been completed
finishStep = stepFactory.createStep()
finishStep.run = {
g.V.each { v->
v.text = "<h2>Thank you for participating in this task.</h2>"
v.text += "<p>Please submit the assignment below.</p>"
v.text += g.getSubmitForm(v, v.score)
}
}
# g.addTimer(Map params)
# g.addTimer(Integer time, String name, String timerText, String direction, String type, String currencyAmount, Closure result, Vertex player, String appearance)
Add a timer to a player that they can see as a progress bar while playing. If "player" is omitted then it will be assigned to all players.
Parameter | Type | Default | Description |
---|---|---|---|
time | Integer | How long the timer will last | |
name | String | The unique key for this timer. Multiple timers for the same player should have different names. | |
timerText | String | Text to show to the player on the timer. | |
direction | "up" , "down" | "down" | Which way the timer should count. |
type | "time" , "currency" , "percent" | "time" | Should the timer value show up as a time, currency or percentage. |
currencyAmount | String | "0" | A string representing an amount of currency. Required when type is currency. |
result | Closure | A closure that will be called when the timer expires | |
player | Vertex | The player to assign this timer to | |
appearance | "error", "warn", "success", "info" | "info" | Which style to use for this timer. |
params | Map | A map where all of the other properties are optional. |
# Returns
# Example
def timer = g.addTimer([
name: "first", // Timer key
player: g.getVertex("one"),
time: 30 * 1000,
appearance: "success", // Timer will appear green
result: {
println "timer complete"
}
])
# Events
# Methods
# events.on(String name, Closure handler)
Respond to an event with this name.
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The name used to define this event. All events emitted with this name will call the handler. | |
handler | Closure | A closure that is called with parameters matching the data passed when the event was emitted. |
# events.off(String name)
Remove all of the handlers for this event.
# events.off(String name, Closure handler)
Remove a specific handler for this event.
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The name used to define the event we want to stop listening to | |
handler | Closure | A reference to the closure that was passed to events.on |
# events.emit(String name, Object... payload)
Emit an event with this name and pass any data to each of the event handlers.
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The name used to define the event we want to stop listening to | |
payload | Object | One or more pieces of data to pass to each listener for this event. |
# Edge
Once an edge is retrieved from the graph either by using the g.getEdge(v1, v2)
method or by iterating through the edges in the graph you can get/set custom properties of the edge or access the following defined properties and methods. In these examples, we have assigned an edge to the variable e
.
# Properties
# e.bothV
A collection consisting of both vertices connected to the edge
# e.inV
The head vertex connected to the edge
# e.outV
The tail vertex connected to the edge
# e.randV
This property returns a random vertex connected to the edge
# Methods
# e.private(Vertex v, Map keyValueMap)
This method sets one or more properties of the edge that are visible only to one of the two vertices connected to the edge. These private properties override a public property of the same name.
Parameter | Type | Default | Description |
---|---|---|---|
v | Vertex | The vertex to whom the private property is visible | |
keyValueMap | Map | A key, value map of private properties to add to the edge |
# Example
g.E.each { edge->
edge.private(edge.getVertex(Direction.IN), ["foo":"bar"])
}
line[foo="bar"] {
stroke: red;
}
# Vertex
Once a vertex is retrieved from the graph either by using the g.getVertex(pid)
method or by iterating through the vertices in the graph you can get/set custom properties or access the following defined properties. In these examples, we have assigned ther vertex to the variable v
.
# Properties
# v.bothE
The collection of edges connected to the vertex
# v.neighbors
The collection of vertices who are connected by edges to the vertex
# Example
// Add 100 points to the score of each vertex connected to the player
v.neighbors.each { n->
n.score += 100
}
# v.private
A map of properties that are visible only to the owning vertex. These properties override public properties of the same name.
# Example
// Set the public property isSpy equal to false for all vertices
g.V.each { v->
v.isSpy = false
}
// pick a random vertex
def spy = g.V.shuffle.next()
// set the private isSpy property of the vertex to true
spy.private.isSpy = true
# Methods
# v.on(String name, Closure handler)
Listen for events from this player node.
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The name to use for this event | |
handler | Closure | A closure to handle received messages. The first argument is the Vertex that received the message, the second is whatever data was sent with the message. |
# Example
player.on("tick", { Vertex v, Object data ->
println v.id, data
})
# v.send(String name, Object[] ...data)
Send an ephemeral message directly to this player node with the specified name.
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The name to use for this event | |
data | Object[] | One or more pieces of data to send. Can be any serializable data type |
# Example
// Send a random Double
player.send("random", r.nextDouble())
// Send a random Integer
player.send("random", r.nextInt(100))
// Send a string
player.send("random", "not random")
// Send a map
player.send("random", [ data: "message here " ])
# Random
This is an instance of java.util.Random that can be accessed using the global variable r
# Methods
In addition to the methods describe below, all methods listed here (opens new window) are available
# r.nextInt(n)
Returns a pseudorandom integer value between 0 and n-1
# r.nextDouble()
Returns a pseudorandom double value between 0.0 and 1.0
# BBTimer
A Breadboard extension of the default Timer class in Groovy. Should be used anywhere a Timer would normally be used.
def timer = new BBTimer()
timer.scheduleAtFixedRate({
// Do something every second
}, 0, 1000)
# SharedTimer
A timer that is assigned to one or more players. Removes the need to create duplicate timers for each player.
// Assign a timer to all players in the game
def timer = new SharedTimer([
time: 1000,
players: g.V.toList()
])
timer.start()
# Constructor
If both player
and players
options are omitted, it will be assigned to all players in the graph.
# new SharedTimer(Integer duration)
# new SharedTimer(SharedTimerOpts opts)
Parameter | Type | Default | Description |
---|---|---|---|
duration | Integer | How long the timer should run for in milliseconds | |
opts | SharedTimerOpts | A map with options for this timer |
# Methods
# SharedTimer.addTime(Integer duration)
Add time to an existing timer
Parameter | Type | Default | Description |
---|---|---|---|
delta | Integer | The number of milliseconds to add to the timer |
# SharedTimer.addPlayer(Vertex player)
Add a single player to this timer
Parameter | Type | Default | Description |
---|---|---|---|
player | Vertex | The player to add to this timer |
# SharedTimer.addPlayers(List<Vertex> players)
Add multiple players at once
Parameter | Type | Default | Description |
---|---|---|---|
players | List<Vertex> | The players to add to this timer |
# SharedTimer.cancel()
Cancel the timer early and remove it from each player
# SharedTimer.onDone(Closure cb)
Register a closure to be called when the timer has ended
Parameter | Type | Default | Description |
---|---|---|---|
cb | Closure | Closure without arguments |
# SharedTimer.pause()
Pause the timer
# SharedTimer.removePlayer(Vertex player)
Remove a single player from the timer.
Parameter | Type | Default | Description |
---|---|---|---|
player | Vertex | The player to remove |
# SharedTimer.restart()
Restart the timer as though it just started
# SharedTimer.resume()
Resume a paused timer
# SharedTimer.setDuration(Integer duration)
Set the duration for this timer
Parameter | Type | Default | Description |
---|---|---|---|
duration | Integer | The new timer duration in milliseconds |
# SharedTimer.tick(Integer delta)
This updates the timer for each player attached to this timer.
Parameter | Type | Default | Description |
---|---|---|---|
delta | Integer | The number of milliseconds to increase the timer by. |
# Interfaces
# SharedTimerOpts
A Map with the following key/value pairs
Parameter | Type | Default | Description |
---|---|---|---|
time | duration | Integer | Timer time in seconds | |
name | String | The unique key to use for this timer | |
player optional | Vertex | A player to add to this timer | |
players optional | List<Vertex> | g.V.toList() | A list of players to add to this timer |
lazy optional | Boolean | false | Start the timer when the first player is added |
result optional | Closure | Call this closure when the timer expires | |
timerText optional | String | The timer label to display | |
updateRate optional | Integer | 1000 | How often in milliseconds this timer should update |
type optional | String | "time" | Valid options are "time" and "currency" |
direction optional | String | "down" | Valid options are "up" or "down" |
currencyAmount optional | Float | Initial currency for the timer | |
appearance optional | String | The color to use to display the timer | |
content optional | ContentMap | A content map to use for fetching the timer label content |
# ContentMap
A Map with the following key/value pairs. content
or contentKey
are required.
Parameter | Type | Default | Description |
---|---|---|---|
content | String | The content to show | |
contentKey | String | The name of the content to show from the Content dialog | |
fills optional | List<String> | [] | The fills to use when displaying the content |
# Choice
A Map with the following key/value pairs
Parameter | Type | Default | Description |
---|---|---|---|
name | String | The label placed on the button | |
result | Closure | A closure that is run when the player clicks this button | |
event optional | Event | The event to record in the experiment data if this choice is made. Matches the Event interface | |
class optional | string | A HTML class to apply to the button, allows for styling with CSS |
# Event
A Map with the following key/value pairs
Parameter | Type | Default | Description |
---|---|---|---|
name | String | A string identifying the event in the data | |
data | Map | [] | A Map with one or more key-value pairs where the keys and values are both (max 255 character) strings |