Hello Chris,
My name is Shirin Taghian, and I am a research assistant in Dr. Kohitij Kar’s lab. We previously contacted you for help in designing a drawing task where monkeys would connect two dots by drawing a line between them. Your assistance was invaluable, and we have been successfully using that task.
Currently, we are looking to modify the task, and I would greatly appreciate your guidance. Specifically, I Preformatted text aim to make the following updates:
- Introduce multiple trials in the task.
- Randomize the positions of the dots in each trial.
- Provide a reward after each line drawn.
I have written some code that successfully randomizes the dot positions and incorporates the reward system. However, when I attempt to implement a protocol for handling multiple trials, the program gets stuck and does not work as expected.
Could you please help me debug this issue or advise how I can modify the code to make it work? I am happy to share the current version of the code for your review.
Thank you very much for your time and assistance!
//
// Mouse input device. This enables testing on a Mac using the mouse pointer as
// a substitute for touch input.
//
var pointer_x = 0 // Pointer X coordinate
var pointer_y = 0 // Pointer Y coordinate
mouse_input (
mouse_position_x = pointer_x
mouse_position_y = pointer_y
autostart = true
)
//
// Variables
//
%define dot_count = 5 // Number of dots
var dot_size = 2.0 // Size of dots
var dot_positions_x = [0] * dot_count // X positions of dots
var dot_positions_y = [0] * dot_count // Y positions of dots
var pointer_on_dot = [false] * dot_count // Tracks whether pointer is on a dot
var current_dot_index = -1 // Index of current dot
var previous_dot_index = -1 // Index of previous dot
var next_line_index = 0 // Tracks the next line to draw
var line_begin = [[0, 0]] * (dot_count - 1) // Start points of lines
var line_end = [[0, 0]] * (dot_count - 1) // End points of lines
var reward_duration_ms = 50 // Reward duration
var pump_control_line = false // Reward pump control
var loop_index = 0 // Helper variable for loops
var min_distance = 5.0 // Minimum distance between dots
var is_valid_line = false // Flag for valid line drawing
// Helper variables
var unique = 0
var check_index = 0
var distance = 0.0
var retry_count = 0 // Declare retry_count globally
var too_close = 0 // Declare too_close globally
//
// Stimuli: Dots
//
stimulus_group dots {
range_replicator (
variable = rr_index
from = 0
to = dot_count - 1
step = 1
) {
circular_fixation_point dot$rr_index (
trigger_width = dot_size
trigger_watch_x = pointer_x
trigger_watch_y = pointer_y
trigger_flag = pointer_on_dot[$rr_index]
x_size = dot_size
x_position = dot_positions_x[$rr_index]
y_position = dot_positions_y[$rr_index]
)
}
}
//
// Stimuli: Lines
//
stimulus_group lines {
range_replicator (
variable = rr_index
from = 0
to = dot_count - 2
step = 1
) {
rectangle line$rr_index (
color = 0, 0, 0
x_size = max(0.1, sqrt(pow(line_end[$rr_index][0] - line_begin[$rr_index][0], 2) +
pow(line_end[$rr_index][1] - line_begin[$rr_index][1], 2)))
y_size = 0.2
x_position = (line_begin[$rr_index][0] +
line_end[$rr_index][0]) / 2
y_position = (line_begin[$rr_index][1] +
line_end[$rr_index][1]) / 2
rotation = atan2(line_end[$rr_index][1] - line_begin[$rr_index][1],
line_end[$rr_index][0] - line_begin[$rr_index][0]) * (180 / pi())
)
}
}
//
// Protocol: Line Drawing Task
//
protocol 'Line Drawing Task' {
block 'Main Block' {
trial 'New Trial' {
task 'Line Drawing Task' {
state 'Initialize Trial' {
report('Initializing trial')
loop_index = 0
next_line_index = 0
current_dot_index = -1
previous_dot_index = -1
goto('Randomize Dot Positions')
}
state 'Randomize Dot Positions' {
report('Randomizing dot positions')
loop_index = 0
retry_count = 0 // Declare outside the while loop
too_close = 0 // Declare outside the while loop
while (loop_index < dot_count) {
unique = 0
retry_count = 0 // Reset retry count for each dot
while ((unique == 0) && (retry_count < 100)) {
dot_positions_x[loop_index] = rand(-10, 10)
dot_positions_y[loop_index] = rand(-10, 10)
unique = 1
check_index = 0
too_close = 0 // Reset too_close flag
while (check_index < loop_index) {
distance = sqrt(pow(dot_positions_x[loop_index] - dot_positions_x[check_index], 2) +
pow(dot_positions_y[loop_index] - dot_positions_y[check_index], 2))
if (distance < min_distance) {
too_close = 1
unique = 0
check_index = loop_index // Exit the inner loop
}
check_index = check_index + 1
}
retry_count = retry_count + 1
}
if (retry_count >= 100) {
report('Warning: Could not find unique position for dot $loop_index')
}
loop_index = loop_index + 1
}
goto('Queue Dots')
}
state 'Queue Dots' {
report('Queuing dots for display')
loop_index = 0
while (loop_index < dot_count) {
queue_stimulus(dots[loop_index])
loop_index = loop_index + 1
}
update_display()
goto('Interact with Dots')
}
state 'Interact with Dots' {
report('Waiting for user interaction with dots')
start_timer(
timer = InteractionTimer
duration = 10s
)
transition (
target = 'Draw Line'
when = pointer_on_dot[0] or pointer_on_dot[1] or pointer_on_dot[2] or pointer_on_dot[3] or pointer_on_dot[4]
)
timer_expired(
target = 'Dequeue Dots'
timer = InteractionTimer
)
}
state 'Draw Line' {
report('Drawing line')
previous_dot_index = current_dot_index
// Update current dot index based on pointer
if (pointer_on_dot[0]) {
current_dot_index = 0
}
if (pointer_on_dot[1]) {
current_dot_index = 1
}
if (pointer_on_dot[2]) {
current_dot_index = 2
}
if (pointer_on_dot[3]) {
current_dot_index = 3
}
if (pointer_on_dot[4]) {
current_dot_index = 4
}
is_valid_line = previous_dot_index != -1 and previous_dot_index != current_dot_index and next_line_index < dot_count - 1
if (is_valid_line) {
line_begin[next_line_index] = [dot_positions_x[previous_dot_index], dot_positions_y[previous_dot_index]]
line_end[next_line_index] = [dot_positions_x[current_dot_index], dot_positions_y[current_dot_index]]
report('Line Begin: [$line_begin[$next_line_index][0], $line_begin[$next_line_index][1]]')
report('Line End: [$line_end[$next_line_index][0], $line_end[$next_line_index][1]]')
live_queue_stimulus(lines[next_line_index])
send_stimulus_to_back(lines[next_line_index])
update_display()
pump_control_line = true
wait (reward_duration_ms / 1000.0) // Reward duration
pump_control_line = false
report('Line drawn and reward given')
next_line_index = next_line_index + 1
}
else {
report('Invalid line - not drawn')
}
goto('Interact with Dots')
}
state 'Dequeue Dots' {
report('Removing dots from display')
loop_index = 0
while (loop_index < dot_count) {
dequeue_stimulus(dots[loop_index])
loop_index = loop_index + 1
}
update_display()
goto('Initialize Trial')
}
}
}
}
}