ランダムに3桁の数字を作成しヒントを元にその数を当てるゲーム。
うちの学校でちょっと流行っていたので作成してみました。
<script type="text/javascript" charset="Shift_JIS">
/* 変数宣言 */
var ReOut=""; //HitとBlowの出力
var Ransu; //乱数を入れる配列変数
var HitTarget; //3桁の数値の答え
var Input; //入力された数値
var Hit; //Hitの数
var Blow; //Blowの数
var InputNumber; //入力された数値から一文字抜き出す
var InputNumberSe; //3桁の数値の答えから一文字抜き出す(Blow用)
var HitNumber; //3桁の数値の答えから一文字抜き出す(Hit用)
LuckyNumber(); //関数LuckyNumber()の実行
/* 答えの数値を作成する関数 */
function LuckyNumber(){
Ransu=new Array(3); //答えを入れる配列を宣言
for(Q=0;Q<3;Q++) //乱数作成のループ
{
Ransu[Q]=Math.floor(Math.random() * 10)+""; //乱数を作成
//↓同じ数値がないか、0があるか判断
if(Ransu[Q] == "0" || Ransu[Q] == Ransu[Q-1] || Ransu[Q] == Ransu[Q-2]){
Q--; //ループを再び繰り返す
}
}
HitTarget=Ransu[0]+Ransu[1]+Ransu[2]; //変数HitTarget に作成した3つの乱数をいれる
}
/* Inputの入力チェックをする関数 */
function NumberInput(){
Input=document.form1.formInput.value;
if(Input == "" || Input.match(/\D/i)){ //Inputが空か、または数字意外が入っているか判断
alert("数値を入力してください");
document.form1.formInput.value="";
}else if(Input.length != 3){ //Inputに3文字入っているか判断
lert("数値を3つ入力してください");
document.form1.formInput.value="";
}else if(Input.indexOf("0") != -1){ //Inputに0が入っているか判断
alert("0を入力しないで下さい");
document.form1.formInput.value="";
}else if(Input.match(/1{2,}|2{2,}|3{2,}|4{2,}|5{2,}|6{2,}|7{2,}|8{2,}|9{2,}/)){
alert("同じ数値を入力しないで下さい"); //↑同じ数値があるかを判断
document.form1.formInput.value="";
}else{
Jikkou(); //どの条件にも引っかからなければ実行
}
}
/* Inputと答えの数値を比較する関数 */
function Jikkou(){
Hit=0; //変数Hitを0に戻す(設定)
Blow=0; //変数Blowを0に戻す(設定)
for(i=0;i<3;i++) //Hitをだすループ
{
HitNumber=HitTarget.charAt(i); //変数HitNumberに答えの数値から一文字抜き出して入れる
InputNumber=Input.charAt(i) //変数InputNumberにInputから一文字抜き出して入れる
if(HitNumber == InputNumber){ //HitNumberとInputNumberが同じか判断 (Hitの判断)
Hit++; //Hitに 1 を足す
continue; //ループをスキップ
}
for(i2=0;i2<3;i2++) //Blowをだすループ
{
InputNumberSe=Input.charAt(i2); //変数InputNumberSeにInputから一文字抜き出して入れる
if(HitNumber == InputNumberSe){ //HitNumberとInputNumberSeが同じか判断 (Blowの判断)
Blow++; //Blowに 1 をたす
}
}
}
ReOut=(Input+" ["+Hit+"Hit "+Blow+"Blow]\n")+ReOut; //変数ReOutに入力した数値とHitとBlowをいれる
document.form1.formReOut.value=ReOut; //変数ReOutを出力
document.form1.formInput.value=""; //Input のフォームを空にする
if(Hit == 3){ //3Hitしたか判断
alert("3Hit"); //3Hitをアラームに出力
LuckyNumber(); //次のゲームのために新しい答え作成
ReOut=""; //次のゲームのためにReOutを空にする
}
}
function AllReset(){ //ゲームをリセットする関数
LuckyNumber(); //新しい答えを作成
ReOut=""; //ReOutを空にする
document.form1.formReOut.value=""; //出力フォームを空にする
}
</script>
<form name="form1">
<p>
入力<input type="text" size="3" name="formInput" value="" /> //Inputフォーム
<input type="button" name="formStart" value="Input" onClick="NumberInput()" /> //関数NumberInput()を実行
<input type="button" value="Reset" onClick="AllReset()" /> //リセットをかける
</p>
<textarea name="formReOut" cols="17" rows="15"></textarea> //出力フォーム
</form>
プログラムを見る限りややこしそうですね。 そんなに複雑なことをやっていないので理解は出来てもらえると思います。
というわけでいつものとおりプログラムの整理をしましょう。
コレが簡単なプログラムの流れです。
次はもう少し細かいプログラムの流れを。
これがすべてのプログラムの流れです。 これらをプログラム化すると上のような長めのプログラムの出来上がりな分けです。
答えの3桁の数字は乱数を使って作成します。 乱数はMathメソッドの中のMath.random()を使います。
今回使うのは0以上10以下の整数なので Math.random() に10をかけます。 コレだけだと*.***になるので小数点以下を切り捨てなければなりません。 そこで使うのがMath.floor()です、これを使って少数点以下を切り捨てます。
それが下のようになります。
Math.floor(Math.random() * 10)
これで0以上10以下の整数の出来上がりです。
この作業を3回繰り返して毎回違う3桁の数字を作成します。 これを行うには単純に for文 を使います。
これらの数値を格納するには変数ではなく配列を使用します。
今回の場合は配列を使った方が余計な変数を使わずにすむし、操作しやすいためです。
今回はRansu
という配列を作成します。
Ransu[Q]=Math.floor(Math.random() * 10)+"";
というようにRansu[x]の中に数値を入れていきます、Qは for文 で増えていく数値です。
このゲームのルール上ゾロ目がないことと0がないことが必須となります。
そのため同じ数が出た場合はもう一度その桁だけを作り直します。
一番最後についている+""
は文字列に変換するためについています。
それを行っているのが下の if文 とその処理です。
if(Ransu[Q] == "0" || Ransu[Q] == Ransu[Q-1] || Ransu[Q] == Ransu[Q-2]){
Q--;
};
Ransu[Q] == Ransu[Q-1]
、
Ransu[Q] == Ransu[Q-2]
というのは今作った数字と前回作った数と前々回作った数値が同じなのかを判断しています。
もし同じならもう一回ループさせるためにQ--;
をしてループ回数を一回増やしています。
HitTarget=Ransu[0]+Ransu[1]+Ransu[2];
これで作成した数値を全て合わせて3桁の数値にしています。
数値を文字列に変換したのは作成された数値を文字列に変換してないとただの数値の足し算になってしまうからです。
数値等を文字列に変換するにはString(xxx)
がありますが
わざわざこれを使わなくとも+""
を使うと簡単に文字列に返還できるのです。
A=(123+"")+(456+"");
A=String(123)+String(456);
上の2つは全く同じことです。Aには「123456」が入ります。
同じように数値に変化するのもあります、Number(xxx)
という数値変換する命令がありますが
-0
とすることで数値に変換が出来ます。
A=A=("123"-0)+("456"-0);
A=Number(123)+Number(456);
上の2つは同じ事をしており、Aには 579 が入ります。
最初の入力チェックではフォーム内が空でないか、フォームに数字以外の文字が入っていないかをチェックしています。
それが Input == "" || Input.match(/\D/i)
です。
if(Input.match(/\D/i))
は、正規表現というものです。これで数値以外の文字が入っているかを判断します。
正規表現についてはボクもまだよく理解していないので他のサイトを回ってください(^_^;)。 正規表現検索
if(Input.length != 3)
でフォーム内に3文字入っているかを判断します。
Input.lengthというのはInput
の文字数を返します。(***.length参照)
if(Input.indexOf("0") != -1)
フォーム内に0が入力されているかを判断しています。
if(Input.match(/1{2,}|2{2,}|3{2,}|4{2,}|5{2,}|6{2,}|7{2,}|8{2,}|9{2,}/))
で、同じ数値が入力されていないかを判断します、コレも正規表現です。
たぶんこんな使い方をしなくとももっとスマートな正規表現があるでしょうけど、未熟者であるため分かりません(・・;)
これらの条件に引っかからなければ次の 「3.HitかBlowの判断」 へいけるのです。
まずは答えの数値からと入力された数値から一文字ずつ抜き出して両者を判断します。 抜き出すには charAt(x) を使います。
HitNumber=HitTarget.charAt(i);
答えから i 番目の数値を抜き出します。
InputNumber=Input.charAt(i)
入力さら数値から i 番目の数値を抜き出します。
※i 番目の数値というのは for文 で増えていく変数。
この二つが同じということは数値も同じで場所も同じということになり Hit になります。
つまり if(HitNumber == InputNumber)
です。
ここで行う処理は Hit している数を格納しておく 変数Hit にプラス1をすることです。
次に Hit しているのでこの数値での Blow はありえないのでコレ以下の処理を時間短縮のためスキップします。
それが continue
です。
次は Blow の判断です。 Blow は場所が違って一致している場合なので入力された文字から次の文字(前の文字)を抜き出して判断します。 この処理を行うためループは入れ子になっています。
InputNumberSe=Input.charAt(i2)
入力さら数値から i2 番目の数値を抜き出します。
※i 番目の数値というのは for文 で増えていく変数。
Hit と同じように if(HitNumber == InputNumberSe)
で両者を判断します。
そして Hit のときと同じように HitNumber
と InputNumberSe
を判断します。
これだと場所も同じで数値も同じ場合もありえますが Hit していればが外側のループのHitの判断で
引っかかっているので Hit にカウントはされません。なので場所は違うが数字があっている場合になるのです。
ReOut=(Input+" ["+Hit+"Hit "+Blow+"Blow]\n")+ReOut;
で入力された文字、Hit数、Blow数を 変数ReOut へ書き込みます。
最後に+ReOut
がついているのはログを出力していくためです。
この中に\n
というのが入っていますがコレは改行コードです。
これを使うことで改行を行うことが出来ます。
document.form1.formReOut.value=ReOut;
入力された文字等が入った 変数ReOut を出力フォームへ出力します。
document.form1.formReOut.value=ReOut;
次入力しやすいように入力フォームを空にしておきます。
if(Hit == 3)
最後に 3Hit した場合の処理を行います。
といっても単純に警告アラームで 3Hit と表示するだけですが・・・
見た目ではここだけの処理ですが裏では別の処理を行います。
LuckyNumber();
次のゲームのために再び新しい答えを作成しておきます。
ReOut="";
これも同じように次のゲームのために今までの入っていた入力されていた数値等の情報を消します。
ゲームが途中で中断できないのは悲しいのでリセット機能をつけましょう。
リセットは単純に全ての変数を初期化するだけです。やっている処理 3Hit と全く同じです。 違うのは出力フォーム内を空にすることだけです。空にしないとリセットした感じがしないからね(笑
コレの関数化したのが function AllReset()
です。
コレで解説終わりです。 かなり疲れました、やっぱ長いプログラムの解説はしんどいですわ。
だいたいこんな長いプログラムの解説を読む人がいるか不明。 やっぱ長いプログラムの解説は止めましょうかね・・・
今回はちょっと解説の仕方を変えてみました。 最初から要点だけをリンクして飛ばすようにしてみました。 これが好評ならばこの解説の仕方を続けていく予定です。
いろいろ機能とついていますが具体的な違いは
3ゲームや5ゲームをいかに早く、いかに少ない間違いで終えれるかを競っても面白いかと。
自分の最短記録は
[3回 0無し TotalTime 56秒 TotalMiss15回]
[5回 0無し TotalTime152秒 TotalMiss31回]
でした。
記録を更新したり早い記録が出たりしたら掲示板にでも記録報告してください。
コンピューターがランダム(ゾロ目と0はなし)に決めた数値をヒント(HitとBlow)をもとに当てるゲーム。
Hitは場所も数値も一致している場合。1Hitなら一箇所、数値も場所も一致している。
Blowは場所は違うが数値は一致している場合。1Blowは一箇所、数値が一致している。
数値と場所の関係を推理して、 いかに早く少ないミスで終わらせるかがこのゲームの目的。
[264]が答えだとする。
[123]を入れると 0Hit 1Blow と表示される。
[456]を入れると 0Hit 2Blow 。
この時点で数値は3つ出てきたため、[789]の可能性はない。
[123]からひとつ、[456]からふたつづ抜き出しいけばいいのだ。
[265]と入れて 2Hit 0Blow、なので(2と6)(2と5)(6と5)の組み合わせがあっている
[254]と入れる 2Hit 0Blow、この時点で 2 は確実にHitしていることが分かる。
[246]と入れる 1Hit 2Blow、3つの数値が出てきたので後は並び替えるだけ。
2 は場所は確定しているので 4 と 6 を入れ替える。
[264]と入れて 3Hit 0Blow となりコレでゲーム終了である。