3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScript じゃんけんゲームを作成

Last updated at Posted at 2021-06-01

JavaScriptを学んだので、じゃんけんゲームを作成してみました。
もし、初学者の方がいましたら、参考にして頂けますと幸いです。

#完成図
###画面遷移時

###10回じゃんけんした後

#参考サイト

#特徴

  • 10回行い、勝ち数、負け数、勝率を計算
  • ボタンを押下する度に、相手の手がランダムに決定される
    • 結果によって表示されるコメントが変わる
      • 勝ちの場合:『あなたの勝ちです』と表示、勝ちカウント+1
      • 負けの場合:『あなたの負けです』と表示、負けカウント+1
      • 引き分け:『あいこです』と表示
  • 10回に到達後
    • グー,チョキ,パーボタンが非活性になる
    • アラート表示させ、勝ち越し、負け越し、引き分けか表示
    • 更新ボタン表示させる

#関数について

  • gameCountReplace()
    • 試合数を計算する関数
  • alert()
    • 最終的な結果をアラートで表示させるための関数
  • resetClick()
    • ボタン作成、reload()関数呼び出し関数
  • inactive()
    • ボタンを非活性にする関数
  • winRateCalc()
    • 勝率を計算する関数
  • onClick()
    • グー、チョキ、パーのどれかを押下したときに処理される関数

HTML

index.html
(省略)
<body>
  <div id="main">
    <div id="container">
      <h1>じゃんけん</h1>
      <p class="text">試合数:
        <span id="gameCount">0</span>
      </p>

      <div class="btn">
        <button id="rock" value="0">グー</button>
        <button id="scissors" value="1">チョキ</button>
        <button id="paper" value="2">パー</button>
      </div>

      <div id="battle">
        <p id="myHand">自分の出した手:まだ出していません</p>
        <p id="enemyHand">相手の出した手:まだ出していません</p>
        <h2 id="result"></h2>
      </div>

      <div id="resultTable">
        <dl>
          <dt class="text">勝ち数</dt>
          <dt class="text">負け数</dt>
          <dt class="text">勝率</dt>
        </dl>
        <dl>
          <dd id="winCount"></dd>
          <dd id="loseCount"></dd>
          <dd id="winRate"></dd>
        </dl>
      </div>

      <div id="reset"></div>

    </div>
  </div>
  <script src="./main.js"></script>
</body>

#JavaScript

main.js
'use strict';

(() => {
  const hands = ['グー', 'チョキ', 'パー'];
  const resultText = ['『あなたの勝ちです』', '『あなたの負けです』', '『あいこです』'];

  // 値を取得する
  const count = document.getElementById('gameCount');
  let countResult = count.innerHTML; 
  const rock = document.getElementById('rock');
  const scissors = document.getElementById('scissors');
  const paper = document.getElementById('paper');
  const myHandType = document.getElementById('myHand');
  const enemyHandType = document.getElementById('enemyHand');
  const result = document.getElementById('result');
  const reset = document.getElementById('reset');
  const winCount = document.getElementById('winCount')
  const loseCount = document.getElementById('loseCount')
  const winRate = document.getElementById('winRate');

  //試合数、勝ち数、負け数
  let gameCount = 0;
  let winResult = 0;
  let loseResult = 0;

  //試合数書き換え
  const gameCountReplace = (gameCount) => {              
    countResult = countResult.replace(countResult, gameCount);
    count.textContent = countResult;
  }

  const alert = (winResult, loseResult) => {
    if (winResult > loseResult) {
      window.alert('勝ち越しました!');
    } else if (winResult < loseResult) {
      window.alert('負け越しました!');
    } else {
      window.alert('引き分けでした!');
    }
  }

  //リセットボタン表示とreload()関数呼び出し
  const resetClick = () => {
    //ボタン要素作成
    const resetBtn = document.createElement('input');
    resetBtn.type = 'button';
    resetBtn.value = '更新';
    reset.appendChild(resetBtn); //親要素(reset)の子要素にボタンを配置する

    resetBtn.addEventListener('click', () => { //更新ボタンを押下後、画面リロードする
      location.reload(); 
    })
  }

  //10回到達したらボタンを非活性にする
  const inactive = () => {
    rock.disabled = true;
    scissors.disabled = true;
    paper.disabled = true;
  }

  //勝率計算
  const winRateCalc = (gameCount, winCount) => {
    const winRateResult = (winCount / gameCount) * 100;
    winRate.textContent = `${winRateResult}%`;
  }

  //ボタン押下関数
  const onClick = (event) => {
    const myHand = Number(event.target.value); //取得するvalue値はstring型のため、Number型に変換
    const enemyHand = Math.floor(Math.random() * hands.length);

    myHandType.textContent = `自分の出した手:${hands[myHand]}`;
    enemyHandType.textContent = `相手の出した手:${hands[enemyHand]}`;

    //勝敗判定
    const handResult = (myHand - enemyHand + 3) % hands.length;

    if (handResult === 2) {
      result.textContent = resultText[0];
      gameCount++;
      winResult++;
      gameCountReplace(gameCount);

    } else if (handResult === 1) {
      result.textContent = resultText[1];
      gameCount++;
      loseResult++;
      gameCountReplace(gameCount);

    } else {
      result.textContent = resultText[2];
    }

    if (gameCount === 10) { //試合数が10回に到達したら実行される処理
      winCount.textContent = `${winResult}回`;
      loseCount.textContent = `${loseResult}回`;
      winRateCalc(gameCount, winResult);
      alert(winResult,loseResult)
      inactive();
      resetClick();
    }
  }

  // クリックした時の挙動はどのボタンも同じなので、関数を共通化
  rock.addEventListener('click', onClick);
  scissors.addEventListener('click', onClick);
  paper.addEventListener('click', onClick);

})();

#CSS

style.css
#main {
  width: 500px;
  margin: 0 auto;
}

#container {
  text-align: center;
}

.btn {
  margin: 20px;
  padding: 10px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
}

button,
input[type="button"] {
  width: 30%;
  border: none;
  border-radius: 5px;
  color: #fff;
  padding: 8px 16px;
  font-size: 16px;
}

button#rock {
  background-color: #dc143c;
  border-bottom: solid 4px #8b0000;
}

button#scissors {
  background-color: #ffd700;
  border-bottom: solid 4px #b8860b;
}

button#paper {
  background-color: #4676d7;
  border-bottom: solid 4px #191970;
}

#rock:disabled,
#scissors:disabled,
#paper:disabled {
  background-color: #808080;
  border-bottom: none;
}

input[type="button"] {
  background-color: #b0c4de;
  border-bottom: solid 4px #708090;
  width: 40%;
  padding: 10px;
  font-size: 30px;
}

button:active,
input[type="button"]:active {
  -webkit-transform: translateY(4px);
  transform: translateY(4px); /*下に動く*/
  border-bottom: none; /*線を消す*/
}

#battle {
  border: 1px solid #ccc;
  padding: 10px;
}

#myHand,
#enemyHand {
  font-size: 20px;
}

#resultTable {
  border: 1px solid #ccc;
  margin: 15px 0;
}

dl {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  border-bottom: 1px solid #ccc;
  font-size: 20px;
}

dl:last-child {
  border-bottom: none;
}

dd {
  text-align: center;
  font-size: 20px;
}

学んだこと

  • ○.disabled = trueとすることで、非活性状態にできること
  • event.target.valueで押下したボタンのvalue値を取得することが可能
  • replace()関数の使い方(文字の書き換え)
  • JavaScriptで処理した値を画面上に表示させるために、textContentinnerHTMLを活用できること
    • textContent:htmlのタグを文字としてそのまま出力
    • innerHTML:htmlのタグを解釈して出力
  • 関数の呼び出すタイミングとか、なんとなく掴めた気がする。
  • じゃんけんの勝敗処理で、下記のように書くことで、判定処理が簡潔に済むことを知れた
const handResult = (myHand - enemyHand + 3) % hands.length;

メモ(適当)

  • 初期状態として、JS上でまだ出していませんの箇所だけ変えるというようにしたかった。しかし今回は、再描画という形をとっている。
    • 1回目は、一部だけ変更はできたのだが、2回目以降は値が変更しなかった。
      • 原因
        • 最初は、replace('まだ出していません', xxx)としていた。
          • 1回目は画面に「まだ出していません」が表示されているため、replace()関数が実行される。
          • 2回目以降は「まだ出していません」が書き換わっているため、replace()関数が実行されなかった

※ちょっと頑張ればこの処理できそうじゃんとか思いますが、面倒だったので、辞めました。また、機会があればこの辺の処理を修正したいと思います。

まとめ

  • 自分でコードを考えて、作成したので、ロジック的な部分の向上に繋がった。また、何より作成したものが、すぐに画面に反映されるのは、楽しかったし、フロント言語の醍醐味だなと感じた。
  • 今回のアプリは、基礎文法でしか使っていないので、オブジェクト指向や非同期通信あたりも今後学んでいきたい。
    • 徐々に慣れてきたら、Vue.js,Node.jsなどのFWにも挑戦していきたいと考えている。
  • 今後のステップアップのために、これ作ると良いよ、これ作ったよ的なものがあれば教えて欲しいです。
3
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?