三山くずしゲーム

三山くずしゲーム を実行します。

三山くずしゲームの説明

  1. 三山くずしゲームのルールです。
  2. ゲームを面白くする。
  3. 人間側のプレイはマウスのクリックで行います。
  4. ゲームはパラメータを設定して自分自身を再起コールすることで進めます。
    JavaScript では、次々とページを切り替えながら(遷移しながら)ゲームを進める方法が良く使われます。
  5. パラメータは連想配列で受け取るのが常識ですが、今回はプログラムの都合で配列で受け取ります。
    それに伴い、パラメータの順番を「手番, 山1の数, 山2の数, 山3の数 」の順に並べます。
  6. ゲームらしくなるように効果音を使用しています。

プログラムの説明

  1. 三山くずしゲームを実行する miyama.html ファイルです。
    主要な関数は Javascript File に記述して script src="miyama.js" で組み込みます。
    miyama.html では <body> から Init() 関数に続いて Play() 関数を呼ぶだけです。
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <script src="miyama.js" type="text/javascript"></script>
    </head>
    
    <body>
    <script type="text/javascript">
    Init();
    Play();
    </script>
    
    </body>
    </html>
    
  2. miyama.js で定義されている Init() 関数です。
    最初の呼び出しでゲームのルールを表示します。
    二回目以降は渡されたパラメータを配列 P[] に格納します。
    パラメータは「手番, 山1の数, 山2の数, 山3の数 」の順に渡されます。
    開始ボタンのクリックでゲーム開始です。
    function Init()
    {
        P = new Array();
        if (window.location.search.length<3)
        {   // 最初の呼び出し
            saisei('start.mp3');
            document.write("<h2>三山くずしゲーム</b></h2>");
            document.write("あなたと私が交互に石を取り除きます<br>");
            document.write("一つの山から幾らでも取り除くことが出来ます<br>");
            document.write("最後の一個を取らされた方が負けです<br>");
            document.write("取り除く石をクリックして下さい<br>");
            document.write("あなたに続いて私がプレイした山が表示されます<br><br>");
            document.write('<form action="miyama.html" method="get">');
            document.write('<input type="hidden" name="P0" value=0>');
            document.write('<input type="submit" value="開始">');
            document.write('</form>');
            return;
        }
        // パラメータを取得する
        var query = window.location.search.substring(1);
        var parameters = query.split('&');
        for(i=0; i<parameters.length; i++)
        {
            var element = parameters[i].split('=');
            var paramName = decodeURIComponent(element[0]);
            var paramValue = decodeURIComponent(element[1]);
            P[i] = parseInt(paramValue);
        }
    }
    
  3. miyama.js で定義されているゲームプレイをする Play() 関数です。
    パラメータの配列 P[0] がゼロのときは山に石を設定してゲームを開始します。
    P[0] が1のときはプレイヤーの手番です。
    P[0] が-1のときはコンピューターの手番です。
    プレイヤーは山の石のクリックすると、それ以降の石が取り除かれます。
    コンピューターは Think() 関数で打つ手を決めます。
    スマホでは、戻るボタンをクリックしても一度に game_index.html に戻れません?
    そこでゲームを終了する画像を追加して、クリックで Click2() 関数を呼び出します。
    function Play()
    {
        if (P[0] == 0)
        {   // 山に石を設定
            P[0] = 1;
            P[1] = Math.floor(Math.random()*15)+1;
            P[2] = Math.floor(Math.random()*15)+1;
            P[3] = Math.floor(Math.random()*15)+1;
        }
        if (P[0] == 1)
        {   // プレイヤーがプレイする(石のクリックで次のステージ)
            document.write("1の山("+P[1]+")<br>");
            Disp(P[1],0);
            document.write("2の山("+P[2]+")<br>");
            Disp(P[2],20);
            document.write("3の山("+P[3]+")<br>");
            Disp(P[3],40);
            document.write('<br><img src="jewel2.gif"onClick=Click2()> ');
        }
        if (P[0] == -1)
        {   // コンピュータがプレイする
            rc = Think();
            switch(rc)
            {   case -1:    //コンピュータの勝ち
                    saisei('win.mp3');
                    document.write('わたしの勝ちです\(^o^)/<br>');
                    document.write('<form action="miyama.html" method="get">');
                    document.write('<input type="hidden" name="P0" value=0><br>');
                    document.write('<input type="submit" value="確認">');
                    document.write('</form>');
                    break;
                case 1:     //コンピュータの負け
                    saisei('lose.mp3');
                    document.write('あなたの勝ちです(^_^;)');
                    document.write('<form action="miyama.html" method="get">');
                    document.write('<input type="hidden" name="P0" value=0><br>');
                    document.write('<input type="submit" value="確認">');
                    document.write('</form>');
                    break;
                default:    //プレイの確認
                    document.write("1の山<br>");
                    Stone(P[1]);
                    document.write("2の山<br>");
                    Stone(P[2]);
                    document.write("3の山<br>");
                    Stone(P[3]);
                    document.write('<form action="miyama.html" method="get">');
                    document.write('<input type="hidden" name="P0" value=1>');
                    document.write('<input type="hidden" name="P1" value=',P[1],'>');
                    document.write('<input type="hidden" name="P2" value=',P[2],'>');
                    document.write('<input type="hidden" name="P3" value=',P[3],'><br>');
                    document.write('<input type="submit" value="私のプレイを確認">');
                    document.write('</form>');
                    break;
            }
        }
    }
    
  4. コンピューターが打つ手を決める Think() 関数です。
    コンピューターの手番で山に石が無ければコンピューターの勝ちです。
    コンピューターの手番で山に石が一個のときはコンピューターの負けです。
    ソースコードを解析して必勝の手を探して下さい。
    コンピューターは一割の確率で、わざと必勝の手を逃します。
    function Think()
    {
        var     n1;         //石が残っている山の数
        var     n2;         //石が一個だけの山の数
        var     mx;         //石が一番多い山の番号
        var     flag;       //山に石を設定済みフラグ
        n1 = 0;
        n2 = 0;
        mx = 0;
        flag = 0;
        for(i=1; i<4; i++)
        {   if (P[i]>0)
            {   n1++;
                if (P[i]==1)    n2++;
                if (P[i]>P[mx]) mx= i;
            }
        }
        switch(n1)
        {   case 0:     //三個の山が空(コンピュータの勝ち)
                return -1;
            case 1:     //石が残っている山は一個
                if (n2==1)  return 1;   //最後の石(コンピュータの負け)
                P[mx]= 1;               //一個を残して全て取り除く
                flag = 1;
                break;
            case 2:     //石が残っている山は二個
                if (n2==1)
                {   P[mx]= 0;           //最後の一個を残す
                    flag = 1;
                }
                break;
            case 3:     //石が残っている山は三個 
                if (n2==2)
                {   P[mx]= 1;           //1,1,1 に設定
                    flag = 1;
                }
                break;
        }
        if (flag == 1)  return 0;    
        var w = P[1]^P[2]^P[3];
        for(i=1; i<4; i++)
        {   n= P[i]^w;
            if (n<P[i]) break;
        }
        // 乱数で取る
        if (i>3 || Math.random()<0.1)
        {   var num= Math.floor(Math.random()*P[mx]+1);
            P[mx]-= num;
            return 0;
        }
        P[i]= n;
        return 0;    
    }
    
  5. 山の石を単に描画する Stone() 関数です。
    function Stone(n)
    {
        for(i=0; i<n; i++)
        {   document.write('<img src="jewel.gif"> ');
            if (i%5==4)    document.write("<br>");
        }
        document.write("<br>");
    }
    
  6. 山の石を描画して、クリックを受け付ける Disp() 関数です。
    function Disp(n,id)
    {
        for(i=0; i<n; i++)
        {
            document.write('<img src="jewel.gif"onClick=Click(',id+i,')> ');
            if (i%5==4)    document.write("<br>");
        }
        document.write("<br>");
    }
    
  7. マウスクリックで取り除く石を決める Click() 関数です。
    function Click(id)
    {
        var y = Math.floor(id/20)+1;
        var n = id%20;
        P[y] = n;
        location.href = "miyama.html?P0=-1" + "&P1=" + P[1] + "&P2=" + P[2] + "&P3=" + P[3];
    }
    
  8. ゲーム終了画像のクリックで呼び出される Click2() 関数です。
    game_index.html を呼び出します。
    function Click2()
    {
        location.href = "game_index.html";
    }