Composite Classes
Composite classes are ways of wrapping common, useful tools into a single package. They typically handle 2 jobs:
Logic: Such as handling random number generation, packaging data, defining user interactions
Graphics: Creating visuals by combining primitives into one complete draw call.
Composites are designed to be extended by the user, so that they can customise exactly what they need without having to start from scratch.
Gridworld
The gridworld class offers a collection of utilities for creating a 2-dimensional grid that can be populated by images, shapes, text, or any other Psychex object. It contains methods for accessing individual cells by index or coords, and allows the experimenter to easily build in user-control by keyboard or mouse-click.
- class Gridworld(x, y, w, h, nRows, nCols, align="CORNER", kwargs={})
Gridworld class that defines a 2-D matrix of pRectangle objects.
- Arguments:
x (
number()
) – The x-coordinate of the anchor point, specified by the value of aligny (
number()
) – The y-coordinate of the anchor point, specified by the value of alignw (
number()
) – The width of the gridh (
number()
) – The height of the gridnRows (
number()
) – The number of rows in the grid as an integernCols (
number()
) – The number of columns of the grid as an integeralign (
string()
) – Specifies where the anchor point of the grid is. If “CORNER”, the (x, y) specified will be in the top-left corner of the grid. If “CENTER”, the (x, y) will be the center. Default is “CORNER”.kwargs={} (
object()
) – A dict-object containing additional keyword args
- Gridworld.getWidth()
Returns the width value originally supplied to the constructor.
- Returns:
width
- Return type:
number
- Gridworld.getHeight()
Returns the height value originally supplied to the constructor.
- Returns:
height
- Return type:
number
- Gridworld.setWidth(w)
Update the width of the grid. If called, must be followed by calling drawOutline to update.
- Arguments:
w (
number()
) – The new width of the grid
- Gridworld.setHeight(h)
Update the height of the grid. If called, must be followed by calling drawOutline to update.
- Arguments:
h (
number()
) – The new height of the grid
- Gridworld.drawOutline()
Takes the provided x, y, w, h, nRows, nCols, and constructs a grid of pRectangle objects. Each of these objects is stored in an array called
cells
. Each cell is an object containing an index, ix, the coords coords, and a reference to the pRectangle object, obj. The array can be indexed directly, or a reference directly to the pRectangle can be obtained from getCell. Each of these can be acted upon like normal pRectangles, and methods such as update or onClick can be applied.- Returns:
this
- Gridworld.getCell(id)
Returns a reference to a cell’s pRectangle object. This object contains all normal pRectangle attributes, as well as copies of the ix and coords gridworld properties. The cell can be referenced by either grid index (ix) (0 -> (nRows*nCols - 1)), or by coords ([0, 0] -> [nRows-1, nCols-1]). Indexing always begins at 0.
- Arguments:
id (
number/Array()
) – A unique identifier for the cell, either the grid index, or grid coords. Indexing begins at 0.
- Returns:
cell reference
- Return type:
Object
- Gridworld.updateCell(id, props)
Update the aesthetic properties of a cell (eg. backgroundColor, borderWidth, etc.)
- Arguments:
id (
number/Array()
) – A unique identifier for the cell, either the grid index or grid coords. Indexing begins at 0.props – A dict-object containing the usual allowed aesthetics properties for a pRectangle
- Returns:
A ref to the edited cell
- Return type:
Object
- Gridworld.indexToCoords(ix)
Convert grid index to the equivalent coordinates using the values of nRows and nCols provided to the constructor.
- Arguments:
ix (
number()
) – A grid index (0 -> (nRows*nCols -1)) to be converted to coords.
- Returns:
The equivalent coords
- Return type:
Array
- Gridworld.coordsToIndex(coords)
Convert grid coordinates to the equivalent grid index using the values of nRows and nCols provoded to the constructor
- Arguments:
coords (
Array()
) – An array of coordinates ([0, 0] -> [nRows-1, nCols-1]) to be converted to the equivalent index.
- Returns:
The equivalent grid cell index
- Return type:
number
- Gridworld.toggleClickable()
NB: Not directly equivalent to calling
toggleClickable()
on a primitive - this runstoggleClickable()
on every cell in the grid iteratively, adding them all to clickables. Useful as a precursor for applying a single onClick to every cell.
- Gridworld.onCellClick(id, callback)
Wrapper for attaching a click listener to a single cell by providing its grid index or grid coords.
Warning
This method runs
toggleClickable
automatically, so you don’t need to run it beforehand! If you do, the two calls will cancel eachother out.- Arguments:
id (
number/Array()
) – A unique identifier for the cell, either the grid index or grid coords.callback (
function()
) – A callback that will run when the particular cell is clicked.
- Returns:
A reference to the clicked-on cell.
- Return type:
Object
- Gridworld.addOverlay(name, cellId, overlayObj)
There are 2 layers in the gridworld visuals: the base pRectangle layer, and the overlay layer. Overlays are objects placed on top of the base grid, and are typically the stimuli presented to the participant. These can be any kind of psychex object - or, a custom object created from scratch if you wish to create a new object using p5.js draw calls.
- Arguments:
name (
string()
) – A unique name for the overlay. This can be useful for referencing it later, for instance if using an image that represents a player token, and naming it “player”.cellId (
number/Array()
) – The id of the cell onto which the object is overlaid. Objects are placed within cells so that they’re automatically aligned.overlayObj (
object()
) – A reference to the object being overlayed. This can be a pre-defined object, or a new object can be created in the function call. This would typically be another psychex object, such as pImage or pCircle for example.
- Gridworld.updateOverlay(id, updateParams)
Update the aesthetics for the specified overlay. Similar to calling
update
on the object, but offers a wrapper that handles index/coords as input.- Arguments:
id (
number/Array/string()
) – A unique identifier for the overlay, either the name provided on instantiation, or grid index or grid coords of the cell containing the overlay.updateParams (
Object()
) – A dict-object of aesthetics to apply to the overlay. Must map the typical values for that object type.
- Returns:
A reference to the edited overlay
- Return type:
Object
- Gridworld.getOverlay(id)
Get a reference to a specific overlay from its id, either the name provided on instantiation, or the index/coords of the cell containing the overlay.
- Arguments:
id (
number/Array/string()
) – A unique identifier for the overlay, either the name provided on instantiation, or grid index or grid coords of the cell containing the overlay.
- Returns:
A reference to the edited overlay
- Return type:
Object
- Gridworld.clearAllOverlays()
Remove all existing overlays from the grid, and delete all references to them.
- Gridworld.removeOverlay(id)
Remove a single overlay, or all overlays from a single cell, depending on input provided.
- Arguments:
id (
number/Array/string()
) – A unique identifier for the overlay, either the name provided on instantiation, or grid index or grid coords of the cell containing the overlay.
- Gridworld.handleMovement(mode, preMovementCallback = () => {}, postMovementCallback = () => {})
Handle user-interactions with the gridworld. Wraps functionality for player movement with keyboard arrow-keys, or with the ‘w-a-s-d’ keys. Also includes options for mouse-click interactions. This method takes in 2 callbacks: the first may be applied pre-movement, such as for handling logic as to whether or not this movement is allowed (e.g. if building a maze, there may be obstacles/wall boundaries to consider, etc.). The second is a postMovement callback, applied if and only if the preMovementCallback runs successfully and returns true. This might handle logic for after the player has moved, or after any other user interaction. Both callbacks contain default empty functions, meaning if a pre-movement function isn’t needed, the user may simply pass a single callback in which will be used upon specification.
- Arguments:
mode (
string()
) – The interaction-mode to be applied. One of either “arrows” (for arrow-keys), “wasd” (for w-a-s-d keys), or “click” (for mouse-clicks.)preMovementCallback (
function()
) – The first callback run on player interaction. Must return true for the second callback to proceed. Default() => {}
.postMovementCallback (
function()
) – The second callback run after successful calling of the first. Default() => {}
.
- Gridworld.checkBounds(pos, k)
Utility for automatically checking gridworld outer boundaries when building a world that the player moves through. Contains key-mappings of the arrow and w-a-s-d keys and returns a boolean for if the proposed movement is within or out of bounds.
- Arguments:
pos (
Array()
) – The current position (eg. at time t), to be compared with the proposed new position, after movement (eg. at time t+1). Must be grid coords - indices can be converted usingindexToCoords()
.k (
string()
) – The key-code of the pressed key. Accepts “ArrowLeft”, “ArrowRight”, “ArrowUp”, “ArrowDown”, “w”, “a”, “s”, “d”. Each of these is mapped to the vector-equivalent of the movement.
- Returns:
A dict containing 2 values: allowed a boolean for an allowed movement (true) or not, and pos the coordinates of the new position after the movement, regardless of it allowed or not.
- Return type:
Object
- Gridworld.draw()
The draw call that renders all the pRectangles in the grid and all overlays.
N-Arm Bandit
The N-Arm bandit class facilitates an extensible version of a generic bandit task.
For an example of usage, see Tutorial: N-Arm Bandit Task.
- class NArmBandit(x, y, nArms=2, probabilities="uniform")
The basis for an N-Arm bandit task. This class is designed to be extended to add custom functionality, and other Psychex objects as graphics for interaction. Probabilities are sampled from a uniform distribution between 0 and 1 by default, but can be overwritten, or specific probabilities per arm specified.
- Arguments:
x (
number()
) – The horizontal position allowing the developer to have a ref point during extensiony (
number()
) – The vertical position allowing the developer to have a ref point during extensionnArms (
number()
) – Number of arms in the tasknRows (
number()
) – The number of rows in the grid as an integer (default = 2)probabilities (
any()
) – Probability type, or an array of probabilities per arm (default = “uniform”)
- NArmBandit.setNArms(n)
Set the number of arms
- Arguments:
n (
number()
) – The number of arms in the task
- Returns:
this
- Return type:
object
- NArmBandit.getNArms()
Get the number of arms in the task.
- Returns:
the number of arms
- Return type:
number
- NArmBandit.setProbabilities()
Set the arm probabilities, either as a string code or as an array of probability values
- Arguments:
p (
any()
) – probability as string or array of numbers, one value per arm if array used
- Returns:
this
- Return type:
object
- NArmBandit.getProbabilities()
Get the arm probabilities
- Returns:
arm probability values
- Return type:
Array[number]
- NArmBandit.pullArm()
Pull the arm related to the given index in this.probabilities. E.g. to pull arm 0, do pullArm(0), related to this.probabilities[0]
- Arguments:
index (
number()
) – The arm index defined by this.probabilities. NB: indexing begins at 0.
- Returns:
the outcome of the arm, either true for ‘successful pull’, else false
- Return type:
boolean