目的

記憶実験では学習からテストまでに一定の遅延時間を設けることが非常に多いです。しかし,何もしないで座ってもらうという手続きでは,学習した刺激のリハーサルが可能なため,テスト成績に影響がでてしまいます。そのため,学習後に妨害課題として別課題を行ってもらい,時間の経過を待つという手続きが必要です。典型的には妨害課題には計算課題が用いられるので作成してみましょう。簡単に作れると思いきや,意外と計算課題の作成は手間がかかります。必要なパーツは計算課題だけですが,計算課題を一定時間繰り返す(ループ)するように構成する必要があるためです。

計算課題の作成

今回は,1桁の3つの数字の足し算の式を呈示し.その正誤を判断するという課題を作成します。例えば,「1 + 1 + 1 = 4」と式を呈示し,この式が正しいか誤っているかをマウスでクリックして回答してもらうというものです。以下のページの下部にあるテンプレートをダウンロードしてください。その中のmain.jsに以下のコードを書いていきましょう。

jsPsychの導入(+ テンプレート)

まず,はじめに足し算の部分を作成します。足し算では,1桁の数字を3つ,ランダムな値で生成する必要があります。そこで,以下のコードによって,3つのランダムな数字とその合計を生成します。mathNumbesという配列に3つのランダムな数字を入れていきます。Math.floor(Math.random() * 9 + 1)によって,1〜9のいずれかの数字をランダムに生成します。Math.random()は0〜1の範囲でランダムな値を小数として生成する関数なので,この関数で生成された値に9をかけることで0〜8の値ができます。最小値が0だと足し算の問題には合わないので,最後に1を足すことで,1〜9の値が生成できます。ただし,このままだと小数点以下の値も表示されてしまうため(例えば,2.1221など),Math.floor()によって小数点以下を切り捨てた整数にしています(例えば,2.1221 → 2)。そして,このランダムな数字の生成をforループで3回繰り返してします(forループについてはここでは解説しません)。また,これらの値を足した答えとなるmathCorrectも同時に作成しておきます。

let mathCorrect = 0;
let mathNumbers = [];
for (let i = 0; i < 3; i++){
	mathNumbers[i] = Math.floor(Math.random() * 9 + 1);
	mathCorrect = mathCorrect + mathNumbers[i];
};

続いて,刺激として呈示するために,これらの値を使って足し算の式を作り,文字列にします。String()で変数を文字型に変換しています。

mathProblem = String (mathNumbers[0]) + ' + ' + String (mathNumbers[1]) + ' + ' + String (mathNumbers[2]) + ' = ' + String(mathCorrect);

では,これらを用いて,計算課題の試行を作成してみます。今回は,マウスで反応してもらう試行のため,html-button-responseを指定しています。

let mathCorrect = 0;
let mathNumbers = [];
for (let i = 0; i < 3; i++){
	mathNumbers[i] = Math.floor(Math.random() * 9 + 1);
	mathCorrect = mathCorrect + mathNumbers[i];
};
mathProblem = String (mathNumbers[0]) + ' + ' + String (mathNumbers[1]) + ' + ' + String (mathNumbers[2]) + ' = ' + String(mathCorrect);
const mathTrial = {
	type: 'html-button-response',
	stimulus: mathProblem,
	choices:['誤り','正しい'],
  prompt:'<p>計算結果が正しいかどうかを判断してください</p>'
}

これで計算式の呈示,正誤判断のボタンを呈示からなる試行を作成できました。しかし,今回は計算課題を繰り返す挙動を組み込む必要があります。そこで,まず,試行開始時に計算式を作成し,作成した計算式を刺激に割り当てるように修正します。on_startに記述することで試行開始時に実行されます。on_start内にtrial.stimulusを記述すると,trial.stimulusで指定した刺激に置き換えることができるので,仮としてstimulus: '1 + 1 + 1 = 1 'という計算式を置いておき,試行開始時にon_startに記述した処理を行い,仮の計算式をランダムに生成した計算式に置き換えます。

const mathTrial = {
	type: 'html-button-response',
	stimulus: '1 + 1 + 1 = 1 ',
	choices:['誤り','正しい'],
	prompt:'<p>計算結果が正しいかどうかを判断してください</p>',
	//試行開始時に正しい計算式または誤った計算式を生成する
	on_start: function(trial){
		let mathCorrect = 0;
		let mathNumbers = [];
		for (let i = 0; i < 3; i++){
			mathNumbers[i] = Math.floor(Math.random() * 9 + 1);
			mathCorrect = mathCorrect + mathNumbers[i];
		}
	//刺激を差し替える
	trial.stimulus = String (mathNumbers[0]) + ' + ' + String (mathNumbers[1]) + ' + ' + String (mathNumbers[2]) + ' = ' + String(mathCorrect);
	}
}

これでランダムに正しい計算式が呈示されるという試行ができました。しかし,今回は計算式の正誤判断なので,誤った計算式を呈示する場合も必要です。今回は誤った計算式を正しい答えにランダムな数字を足したものとして作成します。

//答えが誤りの計算式
const mathTrial = {
	type: 'html-button-response',
	stimulus: '1 + 1 + 1 = 1 ',
	choices:['誤り','正しい'],
	prompt:'<p>計算結果が正しいかどうかを判断してください</p>',
	//試行開始時に正しい計算式または誤った計算式を生成する
	on_start: function(trial){
		const mathCorrect = 0;
		const mathNumbers = [];
		for (let i = 0; i < 3; i++){
			mathNumbers[i] = Math.floor(Math.random() * 9 + 1);
			mathCorrect = mathCorrect + mathNumbers[i];
		}
	//刺激を差し替える
	trial.stimulus = String (mathNumbers[0]) + ' + ' + String (mathNumbers[1]) + ' + ' + String (mathNumbers[2]) + ' = ' + String(mathCorrect + Math.floor(Math.random() * 9 + 1));
	}
}

さらに,実験では,試行ごとに正しい計算式か誤った計算式をランダムに呈示したいので,試行開始時に生成する計算式を正しい計算式か誤った計算式かのいずれかにランダムに決定するようにします。条件分岐用の変数(mathBranch)を用意し,そこにランダムに0か1のどちらかを割り当てます。もし,0であれば(if (mathBranch == 0)),正しい計算式を生成し,それ以外の場合(else)は誤った計算式を生成するようにします。どちらかの式になるかの確率は50%です。

const mathTrial = {
    type: 'html-button-response',
    stimulus: '1 + 1 + 1 = 1 ',
    choices: ['誤り', '正しい'],
    prompt: '<p>計算結果が正しいかどうかを判断してください</p>',
    //試行開始時に正しい計算式または誤った計算式を生成する
    on_start: function (trial) {
        let mathCorrect = 0;
        let mathNumbers = [];
        for (let i = 0; i < 3; i++) {
            mathNumbers[i] = Math.floor(Math.random() * 9 + 1);
            mathCorrect = mathCorrect + mathNumbers[i];
        }

        let mathBranch = Math.floor(Math.random() * 2);

        //正しい計算式を出す
        if (mathBranch == 0) {
            trial.stimulus = String(mathNumbers[0]) + ' + ' + String(mathNumbers[1]) + ' + ' + String(mathNumbers[2]) + ' = ' + String(mathCorrect);
        }
        //誤った計算式を出す
        else {
            trial.stimulus = String(mathNumbers[0]) + ' + ' + String(mathNumbers[1]) + ' + ' + String(mathNumbers[2]) + ' = ' + String(mathCorrect + Math.floor(Math.random() * 9 + 1));
        }
    }
};

次に,試行の繰り返し(ループ)を実装します。jsPsychではループはloop_functionによって可能です。以下のように書くことで計算課題の経過時間がmathDuration以下の場合(例では60秒)は,計算課題がループします。  まず,timelineとしてループしたい一連の試行を指定します。ここではmathTrialだけです。続いて,loop_functionにて,ループを継続する条件をしてします。今回は,計算課題の経過時間が一定の値以内では繰り返すという処理を行いますが,そのためには計算課題の経過時間を取得する必要があります。そこで,計算課題の開始時の時刻を取得し,計算を1問が終わる度に時刻を取得し,「開始時刻 - 現在時刻」と計算で経過時間を得ます。まず,開始時間を取得するために,プラグインのcall-functionを用いて,時刻を取得します。以下のように,getStartTimeというjsPsychの試行を作成します。この試行は呼び出される度にDate.now()で現在時刻を取得し,startTimeに格納します。計算課題に入る前にこの試行を実行することで,開始時刻を取得します。このcall-functionプラグインは,任意のコードを任意の位置で動かすためのプラグインになります。

//開始時間取得
let startTime;

const getStartTime = {
    type: 'call-function',
    func: function()
    {
        startTime = Date.now();
    }
};