前回のカードゲームをJavaScriptでつくるでカードを表示させることができるようになったので、今回は素数大富豪をJavaScriptでつくることにします。
動作確認はこちらから ⇒ Web版素数大富豪、別名 素数の出会い系サイト
Contents
HTML部分
まずHTML部分を示します。card.jsの部分は前回JavaScriptで書いたものをそのまま使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>JavaScriptで素数大富豪をつくる</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> #body { background-color: #000000; } #table { width: 800px; height:600px; margin: 0 auto 0; background-color: #008000; } .button { position: absolute; width: 130px; margin-top: 500px; } #button-confirm { margin-left: 50px; } #button-clear { margin-left: 200px; } #button-pass { margin-left: 350px; } #button-start { margin-left: 500px; } .button-composite { position: absolute; margin-top: 550px; } #checkbox-composite-label { margin-left: 50px; color: white; } #button-x { margin-left: 250px; width: 50px; height: 25px; } #button-hat { margin-left: 350px; width: 50px; height: 25px; } #text{ position: absolute; margin-top: 580px; margin-left: 60px; color: white; } #comp-text{ position: absolute; margin-top: 610px; margin-left: 60px; color: white; } </style> </head> <body id = "body"> <div id = "table"> <button id = "button-confirm" class = "button" onclick="Confirm()">確定</button> <button id = "button-clear" class = "button" onclick="ClearPlayerCards()">クリア</button> <button id = "button-pass" class = "button" onclick="">パス</button> <button id = "button-start" class = "button" onclick="GameStart()">ゲームスタート</button> <label id = "checkbox-composite-label" class = "button-composite"><input type="checkbox" id = "checkbox-composite">素因数を指定する</label> <button id = "button-x" class = "button-composite" onclick="InsertX()">×</button> <button id = "button-hat" class = "button-composite" onclick="InsertHat()">^</button> <p id = "text">入力値</p> <p id = "comp-text">コンピュータの手</p> </div> <script src="./card.js"></script> <script src="./game.js"></script> <script> </script> </body> </html> |
初期化の処理
次にgame.jsの部分ですが、
game.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
const CardWidth = 70; const CardHeight = 100; // シャッフルされて山札として置かれているカード let shuffledCards = []; // プレイヤーとコンピュータが持っているカード let playerCards = []; let compCards = []; // プレイヤーとコンピュータが場に出したカード let playerPutCards = []; let compPutCards = []; // プレイヤーとコンピュータが素因数場に出したカード let playerPrimeFactor = []; let compPrimeFactor = []; // プレイヤーとコンピュータが場に出したカードでまだ表示はされないがまだ流されていないもの let inplayPutCards = []; // プレイヤーが出したカードで作られる素数・合成数の文字列と素因数の計算式 let playerPutCardsText1 = ''; let playerPutCardsText2 = ''; // コンピュータが出したカードで作られる素数・合成数の文字列と素因数の計算式 let compPutCardsText = ''; // いまは革命の状態か? let isRevolution = false; let cardCount = -1; // カードを出すときの枚数(-1なら任意) let numberMin = -1; // カードでつくる数の最小値(-1なら任意) // ページが読み込まれたらカードを初期化する let cards = new Cards(document.getElementById('table')); cards.InitCards(); InitBottons(); |
最初はゲームスタートのボタンしか表示されないようにボタンを初期化しておきます。
1 2 3 4 5 6 7 8 9 10 11 |
function InitBottons(){ // ゲームスタートのボタンだけ一番左に表示する document.getElementById('button-start').style.display = 'block'; document.getElementById('button-start').style.marginLeft = '50px'; document.getElementById('button-confirm').style.display = 'none'; document.getElementById('button-clear').style.display = 'none'; document.getElementById('button-pass').style.display = 'none'; document.getElementById('button-x').style.display = 'none'; document.getElementById('button-hat').style.display = 'none'; } |
これはボタンの表示と非表示を切り替えるための関数です。
1 2 3 4 5 6 7 8 9 10 11 12 |
function EnableBottons(isShow){ let display = isShow ? 'block' : 'none'; document.getElementById('button-confirm').style.display = display; document.getElementById('button-clear').style.display = display; document.getElementById('button-pass').style.display = display; document.getElementById('button-start').style.display = display; document.getElementById('button-start').style.marginLeft = '500px'; // ゲームスタートのボタンの位置をInitBottons関数で変更したので元に戻しておく document.getElementById('button-x').style.display = display; document.getElementById('button-hat').style.display = display; } |
ゲーム開始における処理
次にゲーム開始ボタンが押されたときの処理を示します。カードをシャッフルして配る処理をおこなっています。
game.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function GameStart(){ EnableBottons(true); document.getElementById('checkbox-composite').checked = false; isRevolution = false; // 2回目以降は配列内に前回のプレイのデータが残っているのでクリアする shuffledCards = []; playerCards = []; playerPutCards = []; playerPrimeFactor = []; compCards = []; compPutCards = []; compPrimeFactor = []; cardCount = -1; numberMin = -1; playerPutCardsText1 = ''; playerPutCardsText2 = ''; compPutCardsText = ''; // カードをシャッフル cards.ShuffleCards(); // シャッフルされたカードを山札にコピーする cards.Cards.forEach(card => { shuffledCards.push(card); }); // カードを配って表示する DealCards(); ShowCards(); } |
カードを配る処理
カードを配る処理を示します。山札のカードを13枚各プレイヤーの手札へ移動させます。
1 2 3 4 5 6 7 8 9 10 11 |
function DealCards(){ for(let i=0; i<13; i++){ playerCards.push(shuffledCards[i]); } shuffledCards.splice(0, 13); for(let i=0; i<13; i++){ compCards.push(shuffledCards[i]); } shuffledCards.splice(0, 13); } |
カードを表示する処理
各プレイヤーが持っているカードを表示するための処理を示します。カードを番号順に並べて表示させますが、各配列から削除しただけではカードは消えません。非表示にするための処理が必要です。ここでは表示させなければならないカード以外はX座標を負数にすることで見えない場所に移動させて非表示にしています。
最後にShowText関数を実行していますが、これは場と素因数場に出されたカードによってつくられる数と計算式を表示するためのものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
function ShowCards(){ let x = 30; let y = 20; // 下記のいずれでもないカードは見えないところへ移動する shuffledCards.forEach(card => { card.Move(-3000, 0); }); inplayPutCards.forEach(card => { card.Move(-3000, 0); }); // コンピュータが持っているカード compCards.sort((a, b) => (a.Number - b.Number)); for(let i=0; i<compCards.length; i++){ compCards[i].Move(i * 30 + x, y); } // コンピュータが出したカード y += 120; for(let i=0; i<compPutCards.length; i++){ compPutCards[i].Move(i * 30 + x, y); } for(let i=0; i<compPrimeFactor.length; i++){ compPrimeFactor[i].Move(i * 30 + x + 300, y); } // プレイヤーが出したカード y += 120; for(let i=0; i<playerPutCards.length; i++){ playerPutCards[i].Move(i * 30 + x, y); } for(let i=0; i<playerPrimeFactor.length; i++){ playerPrimeFactor[i].Move(i * 30 + x + 300, y); } // プレイヤーが持っているカード y += 120; playerCards.sort((a, b) => (a.Number - b.Number)); for(let i=0; i<playerCards.length; i++){ playerCards[i].Move(i * 30 + x, y); } ShowText(); } |
カードの選択を取り消す処理
プレイヤーがいったん出したけど取り消してやり直したくなる場合があるので、出されたカードをすべて手札に移動する関数をつくりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function ClearPlayerCards(){ for(let i=0; i<playerPutCards.length; i++) playerCards.push(playerPutCards[i]); for(let i=0; i<playerPrimeFactor.length; i++) playerCards.push(playerPrimeFactor[i]); playerPutCards = []; playerPrimeFactor = []; playerPutCardsText1 = ''; playerPutCardsText2 = ''; document.getElementById('checkbox-composite').checked = false; ShowCards(); } |
パス時の処理
プレイヤーがパスをするときに呼び出される関数です。パスをするとコンピュータの手番になるのですが、この部分はまだできていません。これは未完成の関数です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function PlayerPass(){ for(let i=0; i<playerPutCards.length; i++) playerCards.push(playerPutCards[i]); for(let i=0; i<playerPrimeFactor.length; i++) playerCards.push(playerPrimeFactor[i]); playerPutCards = []; playerPrimeFactor = []; playerPutCardsText1 = ''; playerPutCardsText2 = ''; document.getElementById('checkbox-composite').checked = false; ShowCards(); } |
プレイヤーが出す処理
プレイヤーが出すカードはクリックして選択します。クリックされたらOnMouseDown関数を呼び出してカードを出す処理をおこなわせます。処理中などの理由で確定ボタンが表示されていない場合はなにもしません。
1 2 3 4 |
document.onmousedown = function(e){ if(document.getElementById('button-confirm').style.display == 'block') OnMouseDown(e); } |
クリックされたときの処理ですが、プレイヤーのカードがクリックされたとき以外はなにもしません。Y座標が380ピクセルよりも上のときはプレイヤーのカードではないのでなにもしていません。クリックされた要素に class = “card”がない場合やCardクラスのGetObjectFromElement関数でnullが返されたときはカードは選択されていないということなのでなにもしていません。
プレイヤーのカードがクリックされたと見なされたときはチェックボックスの状態で素数としてカードを出そうとしているのか、合成数の素因数が指定されたのかを判断して適切な位置にカードを移動させています。そして最後にShowCards関数を呼び出してカードを表示させています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
function OnMouseDown(e){ if(e.y < 380) return; if(!e.target.classList.contains('card')) return; let card = cards.GetObjectFromElement(e.target); if(card == null) return; let i = playerCards.indexOf(card); if(i == -1) return; // ジョーカーを出したときは数を選択するセレクトボックスを表示する if(card.Suit == Suit.joker){ ShowJokerNumberMessage(card); return; } // カードを移動させる if(!document.getElementById('checkbox-composite').checked){ playerPutCardsText1 += card.Number; playerPutCards.push(card); } else{ playerPutCardsText2 += card.Number; playerPrimeFactor.push(card); } playerCards.splice(i, 1); ShowCards(); } |
ShowText関数はディスプレイ下にプレイヤーが出そうとしているカードで構成される整数と素因数による計算式を表示するためのものです。
1 2 3 4 5 6 |
function ShowText(){ if(playerPutCardsText2 != '') document.getElementById('text').innerHTML = playerPutCardsText1 + ' = ' + playerPutCardsText2; else document.getElementById('text').innerHTML = playerPutCardsText1; } |
ジョーカーを出すときの処理
ジョーカーを出すときは数を選択するためのセレクトボックスを表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
function ShowJokerNumberMessage(card){ let element = CreateMessageElement(340, '#008080', 'ジョーカーを使います。<br>0から13までの数を指定してください。'); let div = document.createElement('div'); div.style.textAlign = 'center'; div.style.color = '#ffffff'; let select = ` <select id="card-num"> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> <option value="13">13</option> </select>`; div.innerHTML = select; element.appendChild(div); let br = document.createElement('br'); element.appendChild(br); let buttons = AppendOkCancelButton(element); EnableBottons(false); buttons['OK'].onclick = function(e){ card.Number = document.getElementById('card-num').value; element.remove(); EnableBottons(true); if(!document.getElementById('checkbox-composite').checked){ playerPutCardsText1 += card.Number; playerPutCards.push(card); } else{ playerPutCardsText2 += card.Number; playerPrimeFactor.push(card); } let array = []; for(let i=0; i<playerCards.length; i++){ if(playerCards[i] != card) array.push(playerCards[i]); } playerCards = array; ShowCards(); console.log('playerCards.length = ' + playerCards.length); } buttons['Cancel'].onclick = function(e){ element.remove(); EnableBottons(true); ShowCards(); } } |
メッセージボックスを表示するための処理
CreateMessageElement関数はメッセージを表示させるための要素を生成するためのものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function CreateMessageElement(width, backcolor, message1, message2){ let element = document.createElement('div'); element.style.width = width + 'px'; element.style.height = '100px'; element.style.backgroundColor = backcolor; element.style.position = 'absolute'; let table = document.getElementById('table'); table.appendChild(element); let p = document.createElement('p'); if(message1.length > 14) p.style.textAlign = 'left'; else p.style.textAlign = 'center'; p.style.color = '#ffffff'; p.style.margin = '20px'; p.innerHTML = message1; element.appendChild(p); if(message2 != undefined){ let p = document.createElement('p'); if(message2.length > 14) p.style.textAlign = 'left'; else p.style.textAlign = 'center'; p.style.color = '#ffffff'; p.style.margin = '20px'; p.innerHTML = message2; element.appendChild(p); } return element; } |
AppendOkCancelButton関数は前述のメーセージを表示するための要素にOKボタンとキャンセルボタンを追加します。また要素の高さを最適化して画面の中央にメーセージを表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function AppendOkCancelButton(parent){ let buttonOK = document.createElement('button'); buttonOK.innerText = 'OK'; buttonOK.style.width = '100px'; parent.appendChild(buttonOK); let buttonCancel = document.createElement('button'); buttonCancel.innerText = 'キャンセル'; buttonCancel.style.width = '100px'; parent.appendChild(buttonCancel); // ボタンを適切な位置に表示させる buttonOK.style.marginLeft = parent.clientWidth/2 - 20 - 100 + 'px'; buttonCancel.style.marginLeft = 40 + 'px'; // メッセージを表示する要素の高さを最適化する let height = buttonOK.offsetTop + buttonOK.offsetHeight + 20; parent.style.height = height + 'px'; // メッセージを中央に表示させる let table = document.getElementById('table'); parent.style.marginLeft = ((table.clientWidth - parent.clientWidth)/2) + 'px'; parent.style.marginTop = (table.clientHeight - parent.clientHeight)/2 + 'px'; let buttons = { OK:buttonOK, Cancel:buttonCancel, } return buttons; } |
「×」と「^」を選択したときの処理
InsertX関数とInsertHat関数は「×」と「^」がクリックされたときに素因数による計算式をつくるためのものです。
1 2 3 4 5 6 7 8 9 10 11 |
function InsertX(){ if(document.getElementById('checkbox-composite').checked) playerPutCardsText2 += ' × '; ShowText(); } function InsertHat(){ if(document.getElementById('checkbox-composite').checked) playerPutCardsText2 += ' ^ '; ShowText(); } |