WEB相談室

Webページ作成に関しての何でも掲示板です。

タイトル:ラジオボタンでクイズを作成

0:[投稿] キーホルダー [MAIL] [URL] [2002/09/16 00:50 ][環境:WIN+IE わからない]

はじめまして。JavaScript初心者です。でも、いきなりハイレベル(?)なことをしたいんです(-_-;)

画像が3秒おきに変化して、その画像に合ったラジオボタンをチェックしてbuttonをクリックすると得点が加算されるゲームを作りたいんです。
どのラジオボタンがチェックされているかどうかを調べるために【document.フォーム名.elements[].checked】を使っているんですが、これだと画像が変わる順番にラジオボタンをチェックしたら得点になってしまうので、クイズになりません(泣)

一応作ったページのリンクを貼っておきます↓
http://members.aol.com/keyholderjr/gazou_kuizu.htm

いろんなjavaのサイトで勉強したつもりなのですが、しょせん独学なので完成にはほど遠い気がして・・・。
どなたかいい方法を教えていただけませんか? よろしくお願いします m(_ _)m

補足ですが、都道府県の形を当てるクイズを作りたいんです!
僕のサイトが【都道府県キーホルダー】をあつかっているので。
僕の情熱を分かっていただける方!是非ともお力をおかしください。
http://members.aol.com/keyholderkey/


1:[回答] Nina [2002/09/17 20:53 ]

画像を変える処理の前にラジオボタンのチェックをしてみては?

function changeImg(){
   checkRNum();
   count++;
   count %= 48;
   document.btn.src = count + ".gif";
}


2:[質問] キーホルダー [MAIL] [URL] [2002/09/17 21:18 ]

Ninaさん☆ありがとうございますm(;∇;)m

そっか! Ninaさんのやり方でいくと、解答ボタンをクリックする必要がなくなるということですね?

でも・・・(-_-;) 
それだと結局画像が変わる順番にラジオボタンをチェックしていけば得点できることになるので・・・。

そこで、
画像のファイル名とラジオボタンの要素の数を一致させて
Math.floor(48*Math.random());
を使おうとも考えたのですが、
これだと全都道府県(48の画像)を出すことができませんよね?

すいません。なんとしてもランダムにかつ、全都道府県が出現するようにしたいんです!!
何かいい方法をお知りですか?

よろしくお願いします。


3:[回答] Nina [2002/09/17 22:56 ]


ラジオボタンの順番と地図の画像名が一致してるのなら
(例えば北海道が0.gifならラジオボタンの0番目は北海道)

if(document.myFORM.elements[count].checked == true){
   keisan = keisan + 1;
   document.TestForm.Msg.value = keisan;
}

これならラジオボタン全部みる必要はなくなるかと?
どぉ?


4:[質問] キーホルダー [MAIL] [URL] [2002/09/18 00:44 ]

だいぶ形になってきたと思います♪

↓変更を加えました。一度遊んでもらえますか?
http://members.aol.com/keyholderjr/gazou_kuizu.htm

Math.floor(47*Math.random())を使って画像がランダムに変わり、さらにそれに合ったラジオボタンをチェックされると得点できるようになりました!

でも・・・同じ都道府県が出てしまいます(:_;)

47都道府県を全部答えるのは時間もかかるし、
画像が10回変わったらタイマーを止めるようなスクリプトも一応書きましたが、(それならだぶる確率も減ると思って)

やっぱり47都道府県をだぶることなくランダムに出現させたいのです(熱望)

この問題を一発で解決できるような関数ってないのでしょうか??


5:[回答] gun [2002/09/18 11:30 ]

JAVAスクリプトに実装されてないならば、
自分で下みたいに書き加えてランダムな値を得られるように
しなければダメだと思われます。
(スマートなやり方は知りません。。。)
------
var MaxCount=47;
var arr=new Array();
function ran() {
 var temp=Math.floor(Math.random() * MaxCount) + 1;
 while(arr[temp]) {
  temp=Math.floor(Math.random() * MaxCount) + 1;
 }
 arr[temp]=true;
 return(temp);
}
------


6:[回答] gun [2002/09/18 11:35 ]

あらら。
やり直しです。

var MaxCount=47;
var arr=new Array();
function ran() {
var temp=Math.floor(Math.random() * MaxCount) + 1;
while(arr[temp]) {
 temp=Math.floor(Math.random() * MaxCount) + 1;
}
arr[temp]=true;
return(temp);
}


7:[回答] 給料泥棒 [2002/09/18 12:43 ]

 全然勉強にならない回答ですが、こんな感じで
いかがでしょう?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META name="GENERATOR" content="メモ帳(w">
<META http-equiv="Content-Style-Type" content="text/css">
<title>〜都道府県の形当てクイズ〜</title>
<script language="JavaScript">
<!--
//画像を置くディレクトリ
var strImgDir="http://members.aol.com/keyholderjr/";
//都道府県の数(画像の枚数・配列の大きさ)
var intTiikiMax=47;
//画像の縦・横のサイズ
var intImgTate=90;
var intImgYoko=85;
//画像の入れ替え間隔(秒)
var intHyouji=5;

var aimgGazou=new Array(intTiikiMax);
var aintTiiki=new Array(intTiikiMax);
var blnGameStart=false;
var intIma=0;
var intSeikai=0;
var intImgCount=0;
var intGoukei=0;
var intKankaku=1000;
var objTimeKasan=setTimeout("",1);

//画像先読み and 非対応ブラウザ回避
function subSakiyomi(){

if(!document.images)
{
 alert('あなたのブラウザでは遊べません m(_ _)m');
 history.back();
}
else
{
 for(var i=0;i<intTiikiMax;i++)
 {
   aimgGazou[i]=new Image(intImgYoko,intImgTate);
   aimgGazou[i].src=strImgDir+(i+1)+".gif";
   aintTiiki[i]=i;
 }
 subIrekae();
}
}

//問題内容を入れ替える
function subIrekae(){

var tintTemp=0;
var tintRansuu=0;

for (var i=intTiikiMax-1;i>0;i--)
{
 tintRansuu=Math.floor((i-1)*Math.random());
 tintNarabekae=aintTiiki[i];
 aintTiiki[i]=aintTiiki[tintRansuu];
 aintTiiki[tintRansuu]=tintNarabekae;
}
}

subSakiyomi();

//ゲーム開始・終了ボタン
function subStartButton(){

if(blnGameStart==false)
{
 subTimeKasan();
 document.forms["myFORM"].elements["Kaisi"].value="終了";
 document.images["btn"].src=aimgGazou[aintTiiki[intIma]].src;
 blnGameStart=true;
}
else
{
 clearTimeout(objTimeKasan);
 if(confirm("終了しますか?")==true)
 {
  alert("あなたは"+intGoukei+"問中、"+intSeikai+"問正解しました。");
  intSeikai=0;
  intIma=0;
  intImgCount=0;
  intGoukei=0;
  document.forms["myFORM"].elements["Kaisi"].value="開始";
  document.forms["myFORM"].elements["Msg"].value="";
  document.forms["myFORM"].elements["Tim"].value="";
  subIrekae();
  blnGameStart=false;
 }
 else
 {
  objTimeKasan=setTimeout("subTimeKasan()",intKankaku);
 }
}
}

//時間をカウント
function subTimeKasan(){

clearTimeout(objTimeKasan);
if(intImgCount>=intHyouji-1)
{
 subImgHenkou();
}
else
{
 document.forms["myFORM"].elements["Tim"].value=(intHyouji-intImgCount-1);
}
intImgCount=(++intImgCount)%intHyouji;
objTimeKasan=setTimeout("subTimeKasan()",intKankaku);
}

//画像変更・解答判定
function subImgHenkou(){

if (document.forms["myFORM"].elements["ans"][aintTiiki[intIma]].checked)
{
 intSeikai++;
 document.forms["myFORM"].elements["Tim"].value="正解";
}
else
{
 document.forms["myFORM"].elements["Tim"].value="不正解";
}
intGoukei++;
document.forms["myFORM"].elements["Msg"].value=intSeikai+"/"+intGoukei;
intIma=(++intIma)%intTiikiMax;
document.images["btn"].src=aimgGazou[aintTiiki[intIma]].src;
}

// -->
</script>
</head>
<body>
<TABLE border="1" height="159">
 <TBODY>
   <TR>
     <TD align="center">都道府県を選択してください</TD>
   </TR>
   <TR>
     <TD align="center" height="127"><IMG src="./0.gif" name="btn"></TD>
   </TR>
 </TBODY>
</TABLE>
<HR>
<FORM name="myFORM">
<TABLE border="1" bgcolor="#ff00ff">
 <TBODY>
   <TR>
     <TD bgcolor="#ffffff"><INPUT type="radio" name="ans" value="1" checked>北海道</TD>
     <TD bgcolor="#ffffff"><INPUT type="radio" name="ans" value="2">青森</TD>
(中略)
     <TD bgcolor="#ffffff"><INPUT type="radio" name="ans" value="46">鹿児島</TD>
     <TD bgcolor="#ffffff"><INPUT type="radio" name="ans" value="47">沖縄</TD>
     <TD bgcolor="#ffffff" align="center">
<INPUT TYPE="button" name="Kaisi" value="開始" onClick='subStartButton()'></TD>
   </TR>
 </TBODY>
</TABLE>
<BR>
<INPUT TYPE="text" NAME="Msg" size="10">
<INPUT TYPE="text" NAME="Tim" size="10">
</FORM>
</body>
</HTML>

 ラジオボタンの名前は都合により「name="ans"」に変更しました。
いちおう問題は重ならないように47問出ますが、48問目は1問目と
同じ問題、49問目は2問目同じ問題…とループします。(手抜き(^^;)
ボタンを押して終了し、再度始めれば、ちゃんと別の問題に変わり
ますので、ご勘弁を。

……変数名の付け方で正体がバレるかな(^^;。


8:[回答] Nina [2002/09/18 14:01 ]

1〜47をダブり無くランダムでほしいってことですね。
それなら今まで出た数字と今の数字がダブってないか調べていくしかないかと
後は、配列を用意して先頭から順に乱数を格納しておいて順に取り出していくとかかな?

var MaxCnt = 47;
var Chizu = new Array(MaxCnt-1);

function GetRand(){
   var i, j;

   //  配列の初期化
   for(i=0; i<MaxCnt; i++){
       Chizu[i] = "";
   }

   //  1〜47の数字を配列にランダムに格納
   for(j=1; j<=MaxCnt; j++){
       for(;;){
           i = Math.floor(Math.random() * MaxCnt);
           if(Chizu[i]==""){
               Chizu[i] = j;
               break;
           }
       }
   }

}

(スマートじゃないけど^^;)
これで配列を0から順に読み出してくれればランダムになるかと。

クイズを始める前と47問終わる度に関数を呼び出す必要はあるけどね。


9:[回答] ma-to [2002/09/19 00:55 ]


多重データの回避

あらかじめ与えてやらなければならないのはインターバルの 3000 だけだ。データとしての html から取得出来る物までわざわざ与えるのもどうかと思う。そのインターバルでさえ、例えば
    <p>3 秒毎に画像が変わります
とかなんとかの説明文が文書にあれば、そこから取得できる。インターバルをフォーム部品で選択可能にしておくと、n3 でも取得できるだろう。
同時更新は出来ないまたはしんどいから多重データは避けなければならない。


イベント属性

    <body onload=
とかなんとか。 html のイベント属性は紛れもない装飾だと思うから書くべきではないと考える。スクリプトで、
    onload=..;
とすれば済むことだ。
余談。こうすることで思わぬ利点がある。
    <img onmouseover="alert(123);" ..>
としても n4 では何も起こりません、というアホな質問をその昔しばしば目にしたものだ。これへの回答は必ず、
    <a href="#" onmouseover="alert(123);"><img ..></a>
であったりする。見ていて不思議な思いをした人は私だけではないだろう。こういうのもスクリプト側で、
    その画像オブジェクト.onmouseover=new Function("alert(123);");
で解決する。いわゆる「タグをいじること」は避けられる。


配列要素のシャッフル

例えばここでの47個 (48個?) の配列要素をシャッフルする場合。その場合の数は
    47! = 47*46*45* .. *2*1
として得られると日本の学校では15歳前後で習う。考え方そのものは算数で、樹形図を書けば数えられます、と習う。この 47! 個の並べ替え、つまり樹形図の経路数の中から無作為に1つを得ることを考える。
樹形図の一番左側には縦に1から47までが並ぶ。ここから無作為に1つを選び、右に進む。そこには先ほど選んだ1つを除いた46個の数字が縦に並ぶ。そこから1つ数字を無作為に選んで右に進む。これを繰り返すと結果的に樹形図の中から経路を無作為に1つ選ぶことになる。
これを具体的に書くと以下になる。
/*
ただし、この掲示板で同じものを過去に書いた記憶があるが、少し訂正している。
アイデアをどこから拝借したのかはいまだに思い出せないが、
http://www.din.or.jp/~ohzaki/perl.htm#ArrayRandom
に似たようなものがある。少なくとも配列操作と正規表現に関してはどう見ても Perl の猿真似だから、そちらの有用なリソースを調べて拝借する方がスマートである場合が少なくない。
*/
    Math.int_random=new Function("integer",
        "return Math.floor(Math.random()*integer);"
    );

    Array.prototype.shuffle=new Function(
        "var i=++this.length;"+
        "while(i--)"+
            "this.push(this.splice(Math.int_random(i),1)[0]);"+
        "this.length--;"+
        "return this;"
    );

IE では 5.5 からようやく使えるようになった Array.prototype.push と Array.prototype.splice は、
http://www.webreference.com/dhtml/column33/13.html
を拝借して対応すれば良いと思う。


10:[回答] キーホルダー [MAIL] [URL] [2002/09/19 01:10 ]

gunさん☆給料泥棒さん☆Ninaさん☆
回答ありがとうございます。

ひとまず給料泥棒さんのスクリプトをコピー&ペーストして、
ちょこっと変更してアップしてみました。

http://members.aol.com/keyholderjr/gazou_kuizu02-1.htm

そこで給料泥棒さんに質問なんですが、
その1。
var intHyouji=5; のところを変更するだけで、解答時間を変えることができるんですか? もし3秒なら5を3にするんですよね?
ただ、1秒にすると上手く動作しない気がするんですけど・・・
いや、そんな時間には設定しないから気にしなくていいですよね(-_-;)

その2。
画像先読み:subSakiyomi()ではページが読まれたときに47都道府県の画像を読んでくれているんですよね?

もしネットの転送速度が遅いときに次の画像が間に合わなくなることを防ぐためですよね?

当たってますよね?(もしかして僕の勘違い??)
それはクリアしなければならない壁だなぁと考えていたので、すごく助かりました。ありがとうございます。

もしかしてそのスクリプトのおかげで、どんなに解答時間を早く設定しても画像表示が遅れるということはないのでしょうか?

その3。
今現時点で僕は、
あのクイズを挑戦してくれた人の点数を僕のメールアドレス宛てに送るようにして、それをランキング形式でアップしていこうかなと考えているんです。
名前と点数だけでいいのですが(あ、コメントくらいほしいかも・・・)その結果の得点は解答者が変更できないようにしたいのです。不正する人がいるかどうかはわかりませんが(;^_^A

そんなフォームは作れそうかなぁと楽観的に考えているのですが、ただ、それをどう呼び出すかがよくわかりません。

たとえば
47都道府県を全て答え終わったらクイズ終了として、

A=画像が変化した回数をカウントした変数
if(A>47) subStartButton();

という感じで書けばいいのかなぁと考えたのですが、
給料泥棒さんのスクリプトのどこへ挿入したらいいのかわかりません(:_;)

でももしこれでうまくいくなら、
「47回も答えるのだりぃ〜」と思って途中でやめてしまう人用に、10回だけとか20回だけとか、回数を減らして挑戦させることができると思っているんです。

どうですか?
僕の考えてるスクリプトではまずいですか?
挿入するだけじゃ僕の希望は実現できませんかね?


正直言うと全部が自動でランキングされるのが一番なのですが・・・、そこまでは今の僕の知識では不可能な気がするので。
そうゆうのってやっぱり難しいんですよね?
CGI(?)とかになってしまうんですよね?


あともうちょっと!! かなり完成に近づいてきた気がします♪
僕も、教わってばかりではなく自分で考えて生きたいと思っているので、どうかあともう少しだけお力添えをm(;∇;)m


11:[回答] キーホルダー [MAIL] [URL] [2002/09/19 01:28 ]

ma-toさん☆ご指摘ありがとうございます。
イベント属性の話。
なるほど、ためになりました。タグは極力いじらない方がいいのですね。

配列要素のシャッフルの話。
数学的な話は分かりましたが、具体的に書いていただいたスクリプトは・・・難しい(-_-;)うっ


12:[回答] 給料泥棒 [2002/09/19 13:35 ]

 まずは謝罪と修正のお願いから……。

var aimgGazou=new Array(intTiikiMax);
var aintTiiki=new Array(intTiikiMax);

 どちらも1つ分余計に配列を確保してしまっており、正しくは
「intTiikiMax-1」です。この場合はそのままでも問題なく
動くのですが、for(i in[配列名])みたいに配列全体を拾うと
不穏な動きをするかもしれません。Ninaさんの書き込みを
見るまで気づきませんでした(^^;。

 また、subIrekae()の中にある

var tintTemp=0;

は使われておらず、正しい変数名は「tintNarabekae」です。
あるいは、実際に使われている

tintNarabekae=aintTiiki[i];
aintTiiki[tintRansuu]=tintNarabekae;

を「tintTemp」に入れ替えても同じで、とにかく変数名の
不一致がミスです。

 どうもすみませんでした m(_ _)m

>その1
 おっしゃる通り「intHyouji」で解答できる時間(表示時間)を
決めています。短い時間を設定した場合の不具合は、まぁ仕様と
いうことでご勘弁ください……(^^;。

 ma-toさんも少し触れてらっしゃいますが、例えば、セレクト
ボックスに「3秒、5秒、7秒」など、いくつか選択肢を用意し、
開始時に読み取ってこの変数に代入すれば難易度の調整も
できそうですね。

>その2
 確かに「キャッシュ」ではなく、「先読み」を行ってます。
「最初の読み込みで一気に画像を取り込めば、画像の変更を
行ってもサーバー側にも訪問者側にも負荷がかからず、もし
ネットワークを切断しても正しく画像が変更される」。これが
目的であり、ネットワークの遅延の影響もありません。

>その3
 画像が変化した回数をカウントする変数は 「intGoukei」
ですので、subImgHenkou()の最後の部分に分岐を追加すれば、
一定回数で終了することが可能だと思います。この分岐に
変数を用いれば、任意の回数で終了もできて好都合でしょう。
例)
//どこまで答えたら終了するか
var intDokomade=47;

function subImgHenkou(){
(中略)
if(intGoukei>=intDokomade) 終了の処理
}
※プラスマイナス1問くらいの誤差が出る気がするので、
 等号の有無などの微調整はお願いします(^^;。


>ランキング
 このままの形でランキング型のゲームとして運営するのは、
やめておいた方がよろしいかと思います。きっと、ある程度
時間が経過するとランキング上位に満点の人しかいなくなり、
差がつかなくなって面白味が薄まります。

 あと、JavaScriptで点数を設定しても、ある程度の知識と
ツールがあれば不正は簡単に行うことが可能ですので注意が
必要です。

 もし、どうしてもランキングを行いたいなら、

・1秒間隔で行っているものを0.1秒間隔に変更
・解答までにかかった時間を計測
・早く答えれば高得点、連続正解でボーナス点を追加

などの差別化の工夫が必要だと思います。その上で、
「NewGameWeb」
http://game.gr.jp/
のような、ランキング機能を借りられるサイトを利用
するのが楽でしょうね。


13:[回答] キーホルダー [MAIL] [URL] [2002/09/20 00:50 ]

>その3 について。

あれ?? 給料泥棒さんの言うとおりにスクリプトを書いたら、
intDokomade=10で10回で終わる動作に入るようにできたのですが・・・「○問中、○問正解」というメッセージボックスの『OK』をクリックしたらまたまたカウントが始まってしまいます・・・。

if(intGoukei>=intDokomade) subStartButton();
としたら開始(終了)ボタンをクリックしたことになり、終了できると考えていたんですが・・。(blnGameStart=true が false になるので)

でも結局それじゃあ駄目だったので、横着せずにコピー&ペーストで(十分横着?)

document.images["btn"].src=aimgGazou[aintTiiki[intIma]].src; ←subImgHenkou の最後の部分
if(intGoukei>=intDokomade){
clearTimeout(objTimeKasan);
 alert("あなたは"+intGoukei+"個の都道府県中、"+intSeikai+"個正解しました。");
 intSeikai=0;
 intIma=0;
 intImgCount=0;
 intGoukei=0;
 document.forms["myFORM"].elements["Kaisi"].value="開始";
 document.forms["myFORM"].elements["Msg"].value="";
 document.forms["myFORM"].elements["Tim"].value="";
 subIrekae();
 blnGameStart=false;
}

としたのですが、やっぱりカウントがとまりません。
なぜなんでしょう(?_?)いろいろ試してみたのですが、お手上げです。すいません。

http://members.aol.com/keyholderjr/gazou_kuizu02-1.htm

>ランキング について

そうですよね。確かに時間がたつにつれて全問正解する人がいっぱい出てきて、ランキングは意味をなさなくなると思います(笑)
でもまぁせっかく全47都道府県を答えることができたのなら、
名前とコメントくらいは残せるようにした方が楽しいかなぁ と考えたからなので、ランキングというよりクリアできた人を載せる形にしようかなとも考えています。
だって僕が全問解けないんですもん(´▽`)

その送信フォームなんですが、自力で作ってみました(本からですが)
これも・・・なにかと問題が多いかもしれませんね。
いろいろ指摘されてしまうかも(不安)

http://members.aol.com/keyholderjr/sousin_form.htm

変数に格納された値をページを超えて使うことはできるのでしょうか?
定められた問題数をちゃんと答えきった人にだけ送信フォームを出そうと思っているので、クイズのページとフォームのページは別にしようかなと考えているのですが、解答得点をページをまたいで参照することはできるのでしょうか?
できないのなら・・・やばっどうしよ(×_×)


14:[回答] 給料泥棒 [2002/09/20 07:30 ]

今回も謝罪と修正のお願いから……。

 前回例として提示した

if(intGoukei>=intDokomade)終了処理

を入れる場所が正しくありませんでしたので、
カウントは止まりません(^^;。正しく動かすため、
subImgHenkou()の中身ではなく、subTimeKasan()
の中身を以下のように書き換えてください。

function subTimeKasan(){
(中略)
if(intGoukei>=intDokomade)
{
 subStartButton();
}
else
{
 intImgCount=(++intImgCount)%intHyouji;
 objTimeKasan=setTimeout("subTimeKasan()",intKankaku);
}
}

確認もせずに適当なことを書いてしまって、
すみませんでした m(_ _)m

>送信フォーム
 残念ながら、これについては適切な回答が思いつきません。
ただ、mailto:〜という方法では、標準のメールソフトが
起動してしまい、いろいろ問題が出てくると思います。

 例えば、ゲーム部分にメール送信用のCGIを組み合わせて

・前述の if(intGoukei>=intDokomade) 部分から、
 隠しフォームに点数を代入(=問題を答えきった)
・名前、コメントを記入してもらう
・内容を送信してもらう(同時に点数を初期化)

という方法もあります。


 大変身勝手なお願いではありますが、もし以上の回答で
「クイズを作成したい」という当初の目的が果たせている
のであれば、これで私からの回答は終了ということに
させてください。これ以上続けると、一対一のやりとりが
繰り返されてしまう気がするので……。

 それでは、完成目指して頑張ってください m(_ _)m


15:[完了] キーホルダー [MAIL] [URL] [2002/09/20 21:18 ]

いえいえ、本当に助かりました。ありがとうございました。
すごく丁寧に書いていただき、感謝の言葉がみつかりません。

必ず完成させてアップするので、いつか僕のHPを覗いてみてください。
それでは!がんばります☆ 

アドバイスをくださった皆さん、ありがとうございました

回答(必須): 状態:

お名前(必須):

e-mail:

URL:




[戻る]

ChaichanPAPA's World