留学生の入学前日本語学習をするコース作成の支援をしています。
学習の流れを制御したいと言うのですが、可能でしょうか。
学習の流れとは、次のようなものです。(図でなくてすみません)
1.教材を読む
2.小テストで学習程度を把握する。
3.(1-2)を繰り返してもらう。
4.小テストで設定水準を達成したら、確認テストを実行できる。
5.確認テストで合格しなかったら、1に戻る。
標準機能だけではできそうにないので、非標準を調べたら、関係しそうなものとしてActivity Locking がありました。詳しく見ていませんが、これだけでできるか、ちょっと疑問です。
v2.0ではConditional activities が計画されていますね。この中ではいくつかの方式が提案試験実装されています。どれも対象となるactivityのソースに手を入れなければならないので、バージョンの互換性の問題がありますね。その中ではCICEIの実装が一番既存activityのコード修正が少なそうです。最近これらの議論が停止しているので、v2.0へ組み込む方式が決まったのでしょうね。開発版moodleを落としてみたけれど、それらしいコードは見つけられませんでした。
どのような実装になっているか分りませんが、私なら、ConditionとGuarded activityに分けます。CICEIのは、そうなっているような気がします。
どのような実装になっているか分りませんが、私なら、ConditionとGuarded activityに分けます。CICEIのは、そうなっているような気がします。
このような表示の制御を行うには複雑な判定が必要になるので、プログラムを生成して実行するほうが好きだ。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の定義と評価順序が難しいので、トレースをして確認することが重要だ。
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の定義と評価順序が難しいので、トレースをして確認することが重要だ。
動作中心の記述だったので、分りにくいところがあった。状態中心にして、もっとプログラム風にすると、次のように書けるだろう。次にこれから生成されるであろうプログラムの登録と実行をしてみよう。
状態遷移で書いたフロー
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;
}
状態遷移で書いたフロー
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;
}
conditional activitiesがあればいいですが、これを使うのは私には難しいですね.
Activity Locking
http://moodle.org/mod/forum/discuss.php?d=46863
http://docs.moodle.org/en/Activity_Locking
のコードに基づいておつくりになるのはいかがでしょうか。
(余談 サーバーの移動しなければなりあません。)
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を覚えても、直接実行すると禁止されます。
一応できあがって、既存ソースへの修正は
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を覚えても、直接実行すると禁止されます。
http://moodle.org/mod/forum/discuss.php?d=87834
で途中から私が割り込んで書いている方法(具体的なコードはその次の白井先生のもの参照)はどうでしょうか。
で途中から私が割り込んで書いている方法(具体的なコードはその次の白井先生のもの参照)はどうでしょうか。
編集画面が真っ白になってしまう問題でも触れましたが,optional_param()を使うのも良いかも知れません.これですと,$_POST, $_GET共に統一的に値の受け渡しを行えそうです.あちらこちらのコードで使用されています.
MDL-6826で,option_param()を使うべきかどうか,少しだけ議論が出ていたようですが,現状,多くのコードで使用されていますので,急に方針が変換されることはないと思います
私も画面遷移上の制御で、同様の課題にぶち当たりました。
結論として、データを引き継ぐ際のデータ量の大小によって
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
結論として、データを引き継ぐ際のデータ量の大小によって
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
なかなか難しい制約条件ですね。
ページ遷移の途中で、中継ページを挟むのはどうですか?
教材提示モジュール -> 中継ページ -> 小テストページ
中継ページ内での処理
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;
}
?>
という感じではどうでしょうか?この方法ですとユーザ側からは白紙のページが数秒見えるだけで既存のモジュールに手を加えることなく、ページの遷移ができるようになります。
ページ遷移の途中で、中継ページを挟むのはどうですか?
教材提示モジュール -> 中継ページ -> 小テストページ
中継ページ内での処理
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;
}
?>
という感じではどうでしょうか?この方法ですとユーザ側からは白紙のページが数秒見えるだけで既存のモジュールに手を加えることなく、ページの遷移ができるようになります。
システムがだいぶ出来てきました。既存のwebpageの主画面はメニューになっているので、これを動的に表示を変更するようにします。そのためのプログラムを添付します。このプログラムは実際に動作しているものです。
動的ということで、どうしてもプログラムになります。basicの初歩程度のものなので、教材作成者にも使ってもらえるのではないかと思っています。
以前にWebClassで学習過程に沿った教材を作っていた人に見せたら、moodleの評価が変わりました。
動的ということで、どうしてもプログラムになります。basicの初歩程度のものなので、教材作成者にも使ってもらえるのではないかと思っています。
以前にWebClassで学習過程に沿った教材を作っていた人に見せたら、moodleの評価が変わりました。
依頼者に作成したデモを見せたらとても喜んでいたので、現在の状態でα版として公開しました。
dynamicモジュールは、moodleで学習制御をするために開発したモジュールです。
webpageの参照履歴、小テストの成績の情報を元にして、提示するwebpageを選択したり、 動的webpageに制御情報を与えたりして、受講者の学習過程を制御します。
試験的には動くようになったので、α版として公開して意見をいただき、 今後の修正や強化を行おうと思います。
「dynamicモジュール説明書」はforumです。ゲストで読めます。 「dynamic.zip」は、開発している1.8.4+での修正ファイルと新規ファイルです。 解凍してそのまま上書きすればよい筈です。
「java.zip」は、uploadするファイルを生成するプログラムなどを含むユーテリィティです。 解凍するとjarファイルと生成プログラムを動かすバッチファイルが入っています。
dynamicモジュールは、moodleで学習制御をするために開発したモジュールです。
webpageの参照履歴、小テストの成績の情報を元にして、提示するwebpageを選択したり、 動的webpageに制御情報を与えたりして、受講者の学習過程を制御します。
試験的には動くようになったので、α版として公開して意見をいただき、 今後の修正や強化を行おうと思います。
「dynamicモジュール説明書」はforumです。ゲストで読めます。 「dynamic.zip」は、開発している1.8.4+での修正ファイルと新規ファイルです。 解凍してそのまま上書きすればよい筈です。
「java.zip」は、uploadするファイルを生成するプログラムなどを含むユーテリィティです。 解凍するとjarファイルと生成プログラムを動かすバッチファイルが入っています。
dynamicモジュール説明書
dynamic moduleとmoodleの修正分を含むzipファイル
dynamic webpage を作るためのJavaプログラム
どんなwebpageになるのか説明するのが困難なのでデモサイトを作成した。
留学生にひらがなを教えるコース(開発途中の段階のもの)の一部のページを動的になるよう変換したものだ。
動かしてみたい人には学生アカウントを発行するので知らせて欲しい。
総合問題に合格すると、それ以上は変化しない。進度状態を記録しているので、最初からやりなおすには、新しいアカウントが必要だ。
実際にやってみた感想として、動的になる(ナビゲーションが入る)とずいぶん感じが違うが、そのためにはプログラムのセンスが必要で、そのトーレドオフがどうかが問題になりそうだ。
もっと簡単なシーケンス的なものでも良ければ、プログラム臭さを減らせるが、実際に要求されるのはどの程度の複雑さなのか知りたいものです。
なお練習問題はhidden topicにあるので、静的ページにリンクはあるが実行できません。
留学生にひらがなを教えるコース(開発途中の段階のもの)の一部のページを動的になるよう変換したものだ。
動かしてみたい人には学生アカウントを発行するので知らせて欲しい。
総合問題に合格すると、それ以上は変化しない。進度状態を記録しているので、最初からやりなおすには、新しいアカウントが必要だ。
実際にやってみた感想として、動的になる(ナビゲーションが入る)とずいぶん感じが違うが、そのためにはプログラムのセンスが必要で、そのトーレドオフがどうかが問題になりそうだ。
もっと簡単なシーケンス的なものでも良ければ、プログラム臭さを減らせるが、実際に要求されるのはどの程度の複雑さなのか知りたいものです。
なお練習問題はhidden topicにあるので、静的ページにリンクはあるが実行できません。
これまで(1)moodleの画面の中にhtmlを生成する方法と(2)既存のメニューページを動的に変換する方式を作成した。(1)でメニューを作るとメニューと教材の表示の切り替えが面倒、(2)は元版のデザインは生きるが、修正がけっこう面倒だし、静的から動的に代わるとデザインが元のままで良いか疑問になる。
そこでpptの目次のように左ペインに動的目次を作り、右ペインで教材を表示する方式にしたら良いのではないかと思う。メニューのデザインに凝ることはできないが、制御と教材を完全に分離できるので修正が楽だ。制御が単純な順序で良ければ、GUIで設計することもできそうだ。(私はGUIを作れないけど)
教材作成者はどのような方式を好むのだろうか?
そこでpptの目次のように左ペインに動的目次を作り、右ペインで教材を表示する方式にしたら良いのではないかと思う。メニューのデザインに凝ることはできないが、制御と教材を完全に分離できるので修正が楽だ。制御が単純な順序で良ければ、GUIで設計することもできそうだ。(私はGUIを作れないけど)
教材作成者はどのような方式を好むのだろうか?