学習の流れを制御したい

学習の流れを制御したい

- Joji Kariya の投稿
返信数: 21
留学生の入学前日本語学習をするコース作成の支援をしています。
学習の流れを制御したいと言うのですが、可能でしょうか。
学習の流れとは、次のようなものです。(図でなくてすみません)
1.教材を読む
2.小テストで学習程度を把握する。
3.(1-2)を繰り返してもらう。
4.小テストで設定水準を達成したら、確認テストを実行できる。
5.確認テストで合格しなかったら、1に戻る。

標準機能だけではできそうにないので、非標準を調べたら、関係しそうなものとしてActivity Locking がありました。詳しく見ていませんが、これだけでできるか、ちょっと疑問です。

Joji Kariya への返信

Re: 学習の流れを制御したい

- Minoru Akiyama の投稿
秋山@eラーニングサービスです

レッスンモジュールなら可能だと思いますが、作るのが結構手間がかかって大変ですね。
Minoru Akiyama への返信

制御と教材提示機能を独立にしたい

- Joji Kariya の投稿
lessonにせよLAMSにせよ、制御と教材提示機能が一体となっています。教師は、提示する教材をPHP,word,flashなどですでに持っており、quizも作成しています。これらを学習セッションとしてまとめたいのです。評価も入れれば、最近耳にするinstructional designになるのかも知れません。
既存のモジュールにはなるべく手を入れたくないのですが、JavaならできるけどPHPではだめですね。NIMEにはmoodleのJava化とLAMSの統合くらいのシステムを作る計画を立てて欲しいですね。
Joji Kariya への返信

v2.0の計画

- Joji Kariya の投稿
v2.0ではConditional activities が計画されていますね。この中ではいくつかの方式が提案試験実装されています。どれも対象となるactivityのソースに手を入れなければならないので、バージョンの互換性の問題がありますね。その中ではCICEIの実装が一番既存activityのコード修正が少なそうです。最近これらの議論が停止しているので、v2.0へ組み込む方式が決まったのでしょうね。開発版moodleを落としてみたけれど、それらしいコードは見つけられませんでした。
どのような実装になっているか分りませんが、私なら、ConditionとGuarded activityに分けます。CICEIのは、そうなっているような気がします。

Joji Kariya への返信

プログラム生成のほうが簡単そうだ

- Joji Kariya の投稿
このような表示の制御を行うには複雑な判定が必要になるので、プログラムを生成して実行するほうが好きだ。GUIで設定したデータに基づいて処理すると複雑なプログラムになりそうだからだ。
1.教材を読む
2.小テストで学習程度を把握する。
3.(1-2)を繰り返してもらう。
4.小テストで設定水準を達成したら、確認テストを実行できる。
5.確認テストで合格しなかったら、1に戻る。
で、教材をresource4、小テストをquiz2、確認テストをquiz3として、次のようなプログラムを書けば良いとする。
#状態の意味
#state1:quiz3に合格したことがある
#state2:quiz3が不合格で、まだresource4を見ていない
#state3:quiz3が不合格で、まだquiz2をやっていない
#表示制御プログラム
#quiz3の最終結果が80未満ならstate3を1とする
state(3).set(1) : quiz(3).last() < 80;
#quiz3の後でquiz2を実行していたらstate3を0とする
state(3).set(0) : quiz(2).time() > quiz(3).time();
#state3が1ならstate2は1とする
state(2).set(1) : state(3) == 1;
#quiz3の後でresource4を見ていたらstate2を0とする
state(2).set(0) : resource(4).time() > quiz(3).time();
#quiz3の最終結果が80以上ならstate1を1とする
state(1).set(1) : quiz(3).last() >= 80;
#resource4は常に表示する
resource(4) : always;
#quiz2は、quiz3をする前かquiz3の後でresource4を見たら表示する
quiz(2) : resource(4).exec() and state(2) != 1 ;
#quiz3は、quiz3をする前かquiz3の後でquiz2に合格すると表示する
quiz(3) : quiz(2).last() >=80 and state(3) != 1;
#certificateは、quiz3に合格すると表示する
certificate(1) : state(1) == 1;
これをphpのプログラムにコンパイルして、呼ばれるたびに評価する。
なお、未定義の値を参照したときはその文の評価をやめる。

表示される活動と実行結果のトレースは次のようになる

実行記録と状態記録 表示する活動 実行した活動と結果
R4 Q2 Q3 S1 S2 S3
0 0 0 0 0 0 -> R4 R4を見る
1 0 0 0 0 0 -> R4 Q2 Q2 得点 40
1 40 0 0 0 0 -> R4 Q2 Q2 得点 80
1 80 0 0 0 0 -> R4 Q2 Q3 Q3 得点 60
1 80 60 0 1 1 -> R4 R4を見る
1 80 60 0 0 1 -> R4 Q2 Q2 得点 50
1 50 60 0 0 0 -> R4 Q2 Q2 得点 90
1 90 60 0 0 0 -> R4 Q2 Q3 Q3 得点 80
1 90 80 1 0 0 -> R4 Q2 Q3 C1 Q3 得点 70
1 90 70 1 1 1 -> R4 C1

もっと良い記述方法もあるだろう。これはコンパイラの作成が容易になるように考えている。流れが複雑な場合はstateの定義と評価順序が難しいので、トレースをして確認することが重要だ。
Joji Kariya への返信

状態中心の記述なら

- Joji Kariya の投稿
動作中心の記述だったので、分りにくいところがあった。状態中心にして、もっとプログラム風にすると、次のように書けるだろう。次にこれから生成されるであろうプログラムの登録と実行をしてみよう。

状態遷移で書いたフロー

0 { // 初期状態で教材だけ提示
show resource(4);
state <- 1;
}
1 { // 教材を見たあとなので、教材と練習問題を提示
!reqource(4).look() -> 0;
resource(4).time() < q(2).time() -> 1;
show resource(4), q(2);
state <- 2;
}
2 { // 練習問題が不合格なら初期状態からやりなおし、
// 合格なら教材、練習問題、確認テストを提示
!q(2).exec() -> 1;
q(2).time() < q(3).time() -> 1;
q(2).last() < 80 -> 0;
show resource(4), q(2), q(3);
state <- 3;
}
3 { // 確認テストが不合格なら初期状態からやりなおし、
// 合格なら、教材、練習問題、合格証を提示
!q(3).exec() -> 2;
q(3).last() < 80 -> 0;
show resource(4), q(2), certificate(1);
state <- 4;
}
4 { // 合格後、練習問題不合格なら教材からやりなおし
q(2).last() < 80 -> 5;
show resource(4), q(2), certificate(1);
}
5 { // 合格後、教材を見てから練習問題をする
resource(4).time() < q(2).time() -> 6;
show resource(4), q(2), certificate(1);
state <- 4;
}
6 { // 合格後、練習問題不合格だったので教材を見る
show resource(4), certificate(1);
state <- 5;
}


Joji Kariya への返信

プログラム例

- Joji Kariya の投稿
定義言語を作成し、phpプログラムへ変換して動作を確認した。使用したサンプルプログラムを添付する。この程度なら教材作成者が作成してくれると期待している。
通常のプログラムと違うのは、実行する機能を提示しても、実行しないかも知れないことだ。従って、提示する文の前に、提示した機能が実行されたか判定して分岐する必要がある。
プログラムがこれで良ければ、ここで提示したときでなければ機能の実行を禁止する方法を見つけることだ。いろいろ教えてもらっているので、何とかなりそうだ。
Joji Kariya への返信

Re: プログラム例

- Timothy Takemoto の投稿

conditional activitiesがあればいいですが、これを使うのは私には難しいですね.
Activity Locking
http://moodle.org/mod/forum/discuss.php?d=46863
http://docs.moodle.org/en/Activity_Locking
のコードに基づいておつくりになるのはいかがでしょうか。

(余談 サーバーの移動しなければなりあません。)

Timothy Takemoto への返信

一応できました

- Joji Kariya の投稿
conditional lockingの話は見ましたが、とても複雑そうなので止めました。
一応できあがって、既存ソースへの修正は
lib/moodlelib.php 7行
mod/resource/view.php 5行
mod/resource/type/file/resource.class.php 1行
mod/quiz/attempt.php 4行
mod/quiz/view.php 3行
だけで済んでいます。従来の使用法には影響しないので、使うサイトに組み込む予定です。来年度から使いたいということなので。

動的制御の対象になるのは、quizとresourceのfileで、表示を禁止しておきます。
動的制御の表示したテキスト中に含まれたときに、一度だけ実行可能になります。
従って、一度実行し、URLを覚えても、直接実行すると禁止されます。
Joji Kariya への返信

セッションで値を扱う方法を教えてください

- Joji Kariya の投稿
動的コンテンツから呼ばれたときだけ実行可能にするために、制御データをセッションデータとして受け渡ししたいのです。
値をセッションデータとして保存する方法、保存されたセッションデータを取り出す方法を教えてください。
Joji Kariya への返信

Re: セッションで値を扱う方法を教えてください

- Tatsuya Shirai の投稿

 編集画面が真っ白になってしまう問題でも触れましたが,optional_param()を使うのも良いかも知れません.これですと,$_POST, $_GET共に統一的に値の受け渡しを行えそうです.あちらこちらのコードで使用されています.

 MDL-6826で,option_param()を使うべきかどうか,少しだけ議論が出ていたようですが,現状,多くのコードで使用されていますので,急に方針が変換されることはないと思います

Joji Kariya への返信

Re: セッションで値を扱う方法を教えてください

- TATSUO MIWA の投稿
私も画面遷移上の制御で、同様の課題にぶち当たりました。

結論として、データを引き継ぐ際のデータ量の大小によって
1 cookieを利用する
2 URLに引数として渡す(optional_paramで受け取る)
を使い分けることがよいのではないかと思います。
以下に実際に私がとった方法を紹介します。(お役に立てなければすいません・・・)

1 Cookieを利用する方法
セッションデータの量が多い場合に使用しました。
この場合、MoodleAPIでは、set_moodle_cookie()という関数があり、cookieを読み込む関数は、get_moodle_cookie()という関数があります。下記の例では、"name=・・・$mizfile=$data"が一つのクッキーとしてブラウザに読み込ませました。クッキーの受け取り側では、文字列の分割などの処理が必要になります。(クッキーの文字列次第では、分割処理は必要ありません。)

cookieの設定側
// クッキーの設置
set_moodle_cookie("name=$mizar->name&intro=$mizar->intro&theorem=$theorem&vardir=$
mizar->vardir&mizfile=$data");

cookieの受け取り側
if($strcookie = get_moodle_cookie()){
$str = strtok($strcookie,'&'); // &でクッキーを分割
$count = 0;
$data = array();
while($str){
$data[$count++] = $str;
$str = strtok('&');
}

for($i=0;$i<$count;$i++){ // = で変数とデータを分割
$mydata[$i] = strstr($data[$i],'=');
$mydata[$i] = str_replace('=','',$mydata[$i]);
}

2 optional_paramを利用する方法
引き渡されるデータ量が小さい場合(整数値や単語など)に利用しました。
これは、遷移先のページで変数名=optional_param('引数',デフォルト値,引数の型)で宣言すれば容易に取得できます。

view.php内
$id = optional_param('id', 0, PARAM_INT) //コースIDを取得


MoodleAPIや、実際の使われ方を検索する際に下記のURLはとても重宝しています。
参考:
Generated Documentation http://phpdocs.moodle.org/
PHPXref 0.7:Moodle1.8 http://xref.moodle.org/nav.html?index.html

Joji Kariya への返信

moodledataのsessionsは使えますか

- Joji Kariya の投稿
学習制御モジュールから、教材提示モジュールを制御するのに、利用者に見えない方式にしたい。また、小テストなどの教材モジュールに、なるべく手を加えなくない。学習制御モジュールは、教材提示モジュールの履歴だけ見れば良いので、直接呼び出す必要はない。
このような状況なので、
moodledata/sessions にセッション情報が書かれているようなので、ここに記録するのが、良さそうに思うのですが、ここは使えないのでしょうか。
Joji Kariya への返信

Re: moodledataのsessionsは使えますか

- TATSUO MIWA の投稿
なかなか難しい制約条件ですね。複雑な

ページ遷移の途中で、中継ページを挟むのはどうですか?
教材提示モジュール -> 中継ページ -> 小テストページ

中継ページ内での処理
1 教材提示モジュールから、内部状態を引数またはCookieで受け取る
2 内部状態に応じて、redirect 関数で 遷移先ページを振り分ける

たとえば次のような感じです。
<?php
require_once('../../config.php');
require_once('./lib.php');

// 内部状態をoptional_param引数として管理ページから受け取る
$state = optional_param('state',PARAM_INT);

// 内部状態に応じてページの遷移先を変える。
switch($state){
case 0:
redirect('mod/quiz/view.php?id=24'); // 状態 0ならquizモジュールへ
break;
case 1:
redirect('mod/lesson/view.php?id=25); // 状態 1ならlesson モジュールへ
break;
}

?>

という感じではどうでしょうか?この方法ですとユーザ側からは白紙のページが数秒見えるだけで既存のモジュールに手を加えることなく、ページの遷移ができるようになります。


TATSUO MIWA への返信

redirect活用の場面

- Joji Kariya の投稿
redirectを使ってみました。
ある状態で次に行うことがひとつに限定されている場合は、リンクを表示するのではなく、すぐに実行に入るのが良いですね。

redirectのときにurlが見えなければ良いのですが、できないでしょうね。
Joji Kariya への返信

だいぶ出来てきました

- Joji Kariya の投稿
システムがだいぶ出来てきました。既存のwebpageの主画面はメニューになっているので、これを動的に表示を変更するようにします。そのためのプログラムを添付します。このプログラムは実際に動作しているものです。
動的ということで、どうしてもプログラムになります。basicの初歩程度のものなので、教材作成者にも使ってもらえるのではないかと思っています。
以前にWebClassで学習過程に沿った教材を作っていた人に見せたら、moodleの評価が変わりました。
Joji Kariya への返信

α版として公開しました

- Joji Kariya の投稿
依頼者に作成したデモを見せたらとても喜んでいたので、現在の状態でα版として公開しました。

dynamicモジュールは、moodleで学習制御をするために開発したモジュールです。
webpageの参照履歴、小テストの成績の情報を元にして、提示するwebpageを選択したり、 動的webpageに制御情報を与えたりして、受講者の学習過程を制御します。
試験的には動くようになったので、α版として公開して意見をいただき、 今後の修正や強化を行おうと思います。
「dynamicモジュール説明書」はforumです。ゲストで読めます。 「dynamic.zip」は、開発している1.8.4+での修正ファイルと新規ファイルです。 解凍してそのまま上書きすればよい筈です。
「java.zip」は、uploadするファイルを生成するプログラムなどを含むユーテリィティです。 解凍するとjarファイルと生成プログラムを動かすバッチファイルが入っています。

dynamicモジュール説明書

dynamic moduleとmoodleの修正分を含むzipファイル

dynamic webpage を作るためのJavaプログラム



Joji Kariya への返信

moduleの公開名を変更しました

- Joji Kariya の投稿
ごめんなさい。
学内での公開でバージョンにより変えてしまいました。
1.8.4用1.9用です。dynamic moduleの修正というより、必要なmoodle本体の修正による違いです。
moodle本体もバージョンが同じだからと言って、まったく変わっていないとは限らないので、あくまでもなるべく修正の参考になるようにと考えてのことです。
修正内容の記述だけなら、バージョンには影響されないと思いますが、直接修正個所が分るほうが良いと思いました。
Joji Kariya への返信

デモサイトの作成

- Joji Kariya の投稿
どんなwebpageになるのか説明するのが困難なのでデモサイトを作成した。
留学生にひらがなを教えるコース(開発途中の段階のもの)の一部のページを動的になるよう変換したものだ。
動かしてみたい人には学生アカウントを発行するので知らせて欲しい。
総合問題に合格すると、それ以上は変化しない。進度状態を記録しているので、最初からやりなおすには、新しいアカウントが必要だ。

実際にやってみた感想として、動的になる(ナビゲーションが入る)とずいぶん感じが違うが、そのためにはプログラムのセンスが必要で、そのトーレドオフがどうかが問題になりそうだ。
もっと簡単なシーケンス的なものでも良ければ、プログラム臭さを減らせるが、実際に要求されるのはどの程度の複雑さなのか知りたいものです。

なお練習問題はhidden topicにあるので、静的ページにリンクはあるが実行できません。


Joji Kariya への返信

目次ペインを使う方式はどうだろうか

- Joji Kariya の投稿
これまで(1)moodleの画面の中にhtmlを生成する方法と(2)既存のメニューページを動的に変換する方式を作成した。(1)でメニューを作るとメニューと教材の表示の切り替えが面倒、(2)は元版のデザインは生きるが、修正がけっこう面倒だし、静的から動的に代わるとデザインが元のままで良いか疑問になる。
そこでpptの目次のように左ペインに動的目次を作り、右ペインで教材を表示する方式にしたら良いのではないかと思う。メニューのデザインに凝ることはできないが、制御と教材を完全に分離できるので修正が楽だ。制御が単純な順序で良ければ、GUIで設計することもできそうだ。(私はGUIを作れないけど)
教材作成者はどのような方式を好むのだろうか?
Joji Kariya への返信

目次を生成してみた

- Joji Kariya の投稿
動的webpageの言語を拡張して目次を生成してみた。
サンプル画面を添付します。
目次で、青字の項目は参照(実行)ができる、赤字の項目は参照(実行)しないと先へ進まない、灰色の項目は参照(実行)ができない、です。
何か操作をしたら上部のnextボタンを押すと次の状態の目次に変わる。
項目の前に-記号がついているのは、畳み込める印です。
この目次は1週間のコースの1日半程度を記述したものです。
1週間のメニューから1日を選び、1日の中からステップを選ぶという前の方式より、何をするかが良く分るように思います。
添付 dynamicIndex.jpg