/*************************************************************
* test.js.php
*
* Sets up the experiment and contains all the logic for the
* progression of the experiment. The main javascript file that
* powers this experiment.
*
* Author: Willy Xiao
* Last Modified: _______
*
* Adapted from : Yuechen Zhao
*
* © Copyright 2013 Intelligent and Interactive Systems
* Group, Harvard University.
* For questions about this file and permission to use
* the code, contact us at info@labinthewild.org
*************************************************************/
// for php_gettext
var basic =
{
//** EXPERIMENT VARIABLES, CONSTANTS, AND CONFIGURATIONS **//
test_name : "basic",
index : null,
// expment variables and data collected
expment :
{
// phases of the test
phases : new Array
(
{
type : "practice",
instructions :
"
Instructions for the Practice Trial for Basic Test
Remember, this is only for practice. Your results will be discarded.
You will see a slide of anywhere between 1 - 6 symbols flash on your screen. Memorize the set of symbols (you need not remember their order).
Then, you will see a another image like the one shown below.
Decide whether or not the symbol was part of the previous set and move your mouse to either the [check] or the [x] to indicate Yes or No.
Remember, your goal is to answer correctly as quickly as possible. You may find it useful to press 1 on your keyboard for Yes and 0 for No to increase your speed. Note : If you choose to use your mouse instead of your keyboard, you will have to recenter it after each trial on the red target: Press next when you're ready to begin the practice. ",
numTrials : 1,
},
{
type : "trial",
instructions :
"
Great Job! :)
Now for the real deal. It'll be the same as the practice you just took, but with 20 trials.
When you're ready, press next to begin the test.
",
numTrials : 1,
}
),
// an array to hold all of the trials, will be populated by setup
trials : [
[], []
],
// array for the results of the non-practice trials
results : [
[], []
],
},
// variables needed to proceed with test
vars :
{
// chain of functions
ch : null,
// current phase of test 0-indexed
phase : 0,
// some counts used later in the test
total_num_symbols : 0,
total_num_phases : 0,
},
config :
{
// the symbols that will be shown or tested
symbols : "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(''),
// keyboard input codes for one and zero (normal numbers and numpad)
true_codes : new Array(49, 97),
false_codes : new Array(48, 96),
min_stims : 1,
max_stims : 6,
stimDuration : 1000,
itiDuration : 500,
waitDuration : 500,
feedbackDuration : 1000,
},
//** SETUP (including initializations) AND PRELOADING ITEMS CALLED BY INDEX **//
setup : function(test_index)
{
console.log(this.test_name + " is setting up...");
/* INITIALIZATIONS */
// initializing a number of different variables
this.vars.total_num_symbols = this.config.symbols.length;
this.vars.total_num_phases = this.expment.phases.length;
/* SETUP-PROPER */
// alias for phases
var phases = this.expment.phases;
// populate the different phases of the trials
for(n in phases)
{
// first get the instructions
this.expment.trials[n] = [{type : "inst", html : phases[n].instructions}];
var type = phases[n].type;
var total_in_set = this.vars.total_num_symbols;
// var total_set_str = this.config.symbols.toString();
for(var i = 0; i < phases[n].numTrials; i++)
{
// some necessary components to record and for starting the set
var trial_num = i;
var response_required = this.isPosResponse();
var total_in_stim = getRandomInt(this.config.min_stims, this.config.max_stims);
var stim_set = this.getRandomSet(total_in_stim);
// var stim_set_str = stim_set.toString();
var probe = this.getProbe(response_required, stim_set);
// put this on to the end of the experiment
this.expment.trials[n].push(
{
of_test : basic.test_name,
type : type,
trial_num : trial_num,
response_required : response_required,
stim_set : stim_set,
stim_time : this.config.stimDuration,
wait_time : this.config.waitDuration,
total_in_stim : total_in_stim,
probe : probe,
total_in_set : total_in_set
});
}
}
console.log(this.test_name + " is done setting up!");
},
preload_arr :[],
preload_helper : function ()
{
console.log(this.test_name + " is preloading...");
// alias
var trials = this.expment.trials;
// load in the html for the different stims
for(phase in trials)
{
for(n in trials[phase])
{
var current_trial = trials[phase][n];
if (current_trial.type != "inst")
{
var stim_html = "";
for(i in current_trial.stim_set){stim_html += current_trial.stim_set[i] + " ";}
stim_html += "
";
$("#stims").append(stim_html);
var probe_html = "";
probe_html += current_trial.probe;
probe_html += "
";
$("#probes").prepend(probe_html);
}
}
}
console.log(this.test_name + " is done preloading!");
return;
},
//** PRELOADING HELPER FUNCTIONS **//
// determines whether a positive or negative response should be required
isPosResponse : function ()
{
return (getRandomInt(0,1) == 1);
},
// gets a random set from this.config.symbols of length "num"
getRandomSet : function(num)
{
var return_set = new Array();
var index;
do
{
index = getRandomInt(0, (this.vars.total_num_symbols - 1));
if (!arrayContains(return_set, this.config.symbols[index]))
{
return_set.push(this.config.symbols[index]);
}
}
while(return_set.length < num)
return return_set;
},
// gets a probe to test the individual. if response_required, then will return something in the set
// otherwise will return something outside of the set
getProbe : function(pos_response_required, set)
{
if (pos_response_required)
{
var randomIndex = getRandomInt(0, (set.length - 1));
return set[randomIndex];
}
else
{
var symbol = "";
do
{
var randomIndex = getRandomInt(0, (this.vars.total_num_symbols - 1));
symbol = this.config.symbols[randomIndex];
}
while (arrayContains(set, symbol));
return symbol;
}
},
//** CHAIN OF FUNCTIONS TO RUN DURING TRIALS, CALLED BY nextTrial IN pages.js.php **//
// must uses test_name.method rather than this.method
nextTrialChain : function (trial)
{
return new Array
(
function ()
{
hideNextButton();
showSlide("empty");
$("#stims").children().hide();
$("#probes").children().hide();
$("#response").show();
$("#" + trial.of_test + trial.type + trial.trial_num).show();
$("#" + trial.of_test + trial.type + trial.trial_num + "response").show();
$$$("heading").innerHTML = "" + (basic.vars.phase == 0 ? "Practice" : "Part " + basic.vars.phase + "/" + globals.tests.length) + "
";
$$$("progress").innerHTML = "" + "Progress: " + (trial.trial_num + 1) + " / " + basic.expment.phases[basic.vars.phase].numTrials;
},
this.config.itiDuration,
function ()
{
showSlide("stims");
},
this.config.stimDuration,
function()
{
showSlide("empty");
},
this.config.waitDuration,
function ()
{
// function used to record responses - called by handlers
var record_response = function(pos_response, type_of_response)
{
input.rt = (new Date()) - rt_start;
input.response = pos_response;
input.type = type_of_response;
remove_my_listeners();
basic.processResponse(input, trial);
}
// handlers for input from user
var yes_handler = function(e) {record_response(true, "mouse")};
var no_handler = function(e) {record_response(false, "mouse")};
var keyboard_handler = function(e)
{
var in_pos = arrayContains(basic.config.true_codes, e.keyCode);
var in_neg = arrayContains(basic.config.false_codes, e.keyCode);
if (in_pos || in_neg)
record_response(in_pos, "keyboard");
}
// bind the handlers
$("#yes_response").bind("mouseover", yes_handler);
$("#no_response").bind("mouseover", no_handler);
$(document).bind("keydown", keyboard_handler);
// a function used to remove handlers after events are triggered
var remove_my_listeners = function()
{
$(document).unbind("keydown", keyboard_handler);
$("#yes_response").unbind('mouseover', yes_handler);
$("#no_response").unbind('mouseover', no_handler);
}
showSlide("probes");
var rt_start = new Date();
var input = {};
}
);
},
// processes response
processResponse : function(input, trial)
{
// if there's a chain of timeouts, clear them all
if(this.vars.ch)
clearChain(this.vars.ch);
$("#response").hide();
var feedback_html = (trial.response_required == input.response ?
"" + 'Correct!' + "
" + (input.rt / 1000.0) + " seconds
" :
"" + 'Incorrect!' + "
")
$("#feedback").html(feedback_html);
$("#feedback").show();
var result = trial;
result.rt = input.rt;
result.input_response = input.response;
result.input_type = input.type;
this.expment.results[this.vars.phase].push(result);
var mouse_handler = function(e)
{
$("#mouse_center").hide();
$("#mouse_center").children("img").unbind('mouseover', mouse_handler);
nextTrial(basic);
};
setTimeout(function()
{
$("#feedback").hide();
$("#feedback").empty();
if (input.type == 'mouse')
{
$("#mouse_center").show();
$("#mouse_center").children("img").bind('mouseover', mouse_handler);
}
else
{
nextTrial(basic);
}
}, basic.config.feedbackDuration);
},
//** FINISHING ITEMS FOR WHEN EXPERIMENT IS DONE **//
submit : function()
{
/*$.ajax({
type: 'POST',
url: 'includes/data.php',
data: {
participant_id: vars.participant_id,
participant_country: vars.participant_country,
results: JSON.stringify(expment.results)
}
}).done( function (data) {
filter_high();
calculate();
results();
});*/
console.log(this.expment.results);
this.results_html = "" + this.expment.results + "
";
},
// will hold the html for the results later
results_html : "little bobby!
",
}