LoginSignup
4
3

More than 3 years have passed since last update.

[Javascript] マルバツゲームを写経してみた

Posted at

今回、JSの学習のため、マルバツゲームをを写経してみたので
全コードをアップしておきます(自分用の備考録)。

参考(写経)元

マルバツゲームを作ってみよう
※アロー関数で記述したり、コードのまとめ方を変更したりしていますが、ほぼ同じ内容です

Javascript

app.js
// 各種定義
let flag = false;
let counter = 9;
let winningLine = null;
const squares = document.querySelectorAll('.square');
const squaresArray = [].slice.call(squares); // IE11対策
const messages = document.querySelectorAll('.message-list li');
const messagesArray = [].slice.call(messages); // IE11対策
const resetBtn = document.querySelector('#reset-btn');


// メッセージの切り替え関数
const setMessage = (id) => {
    messagesArray.forEach((message) => {
        if (message.id === id) {
            message.classList.remove('js-hidden');
        } else {
            message.classList.add('js-hidden');
        }
    });
}


// 勝利判定のパターン関数
const filterById = (targetArray, idArray) => {
    return targetArray.filter((e) => {
        return (e.id === idArray[0] || e.id === idArray[1] || e.id === idArray[2]);
    });
}
// 勝利判定パターン
const line1 = filterById(squaresArray, ['1-1', '1-2', '1-3']);
const line2 = filterById(squaresArray, ['2-1', '2-2', '2-3']);
const line3 = filterById(squaresArray, ['3-1', '3-2', '3-3']);
const line4 = filterById(squaresArray, ['1-1', '2-1', '3-1']);
const line5 = filterById(squaresArray, ['1-2', '2-2', '3-2']);
const line6 = filterById(squaresArray, ['1-3', '2-3', '3-3']);
const line7 = filterById(squaresArray, ['1-1', '2-2', '3-3']);
const line8 = filterById(squaresArray, ['1-3', '2-2', '3-1']);
const lineArray = [line1, line2, line3, line4, line5, line6, line7, line8];
// 勝利判定関数
const isWinner = (symbol) => {
    // some: 1つでも条件を満たしていればTrueを返す
    const result = lineArray.some((line) => {
        // every: 全て条件を満たしていればTrueを返す
        const subResult = line.every((square) => {
            if (symbol === 'maru') {
                return square.classList.contains('js-maru-checked');
            } else 
            if (symbol === 'batsu') {
                return square.classList.contains('js-batsu-checked');
            }
        });

        if (subResult) { winningLine = line }

        return subResult;
    });
    return result;
}


// ゲーム終了時の関数
const gameOver = () => {
    // 全てのマスをクリック不可にする
    squaresArray.forEach((square) => {
        square.classList.add('js-unclickable');
    });

    // 勝った時のマス目をハイライトする
    if (winningLine) {
        winningLine.forEach((square) => {
            square.classList.add('js-highLight');
        });
    }

    // リセットボタン表示
    resetBtn.classList.remove('js-hidden');
}


// ゲームの初期化の関数
const initGame = () => {
    flag = false;
    counter = 9;
    winningLine = null;
    squaresArray.forEach((square) => {
        square.classList.remove('js-maru-checked');
        square.classList.remove('js-batsu-checked');
        square.classList.remove('js-unclickable');
        square.classList.remove('js-highLight');
    });
    setMessage('batsu-turn');
    resetBtn.classList.add('js-hidden');
}
resetBtn.addEventListener('click', function() {
    initGame();
});


// マスをクリックした時のイベント発火
squaresArray.forEach((square) => {
    square.addEventListener('click', () => {
        if (flag === true) {
            square.classList.add('js-maru-checked');
            square.classList.add('js-unclickable');

            if (isWinner('maru')) {
                setMessage('maru-win');
                gameOver();
                return;
            }

            setMessage('batsu-turn');
            flag = false;

        } else {
            square.classList.add('js-batsu-checked');
            square.classList.add('js-unclickable');

            if (isWinner('batsu')) {
                setMessage('batsu-win');
                gameOver();
                return;
            }

            setMessage('maru-turn');
            flag = true;
        }

        counter--;
        // 引き分け判定
        if (counter === 0) {
            setMessage('draw');
            gameOver();
        }
    });
});

HTML

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>[Sample]○×ゲーム</title>
    <link href="app.css" rel="stylesheet" />
  </head>
  <body>
    <div class="wrapper">
      <div class="game-container">
        <a href="https://www.hypertextcandy.com/tic-tac-toe-1" target="_blank">参考: URL</a>
        <div class="message-container">
          <ul class="message-list">
            <li id="maru-turn" class="js-hidden">
              <span class="maru"></span>の番
            </li>
            <li id="batsu-turn">
              <span class="batsu">×</span>の番
            </li>
            <li id="maru-win" class="js-hidden">
              <span class="maru"></span>の勝ち!
            </li>
            <li id="batsu-win" class="js-hidden">
              <span class="batsu">×</span>の勝ち!
            </li>
            <li id="draw" class="js-hidden">
              引き分け
            </li>
          </ul>
        </div>

        <div class="squares-container">
          <div class="squares-box">
            <!-- 1行め -->
            <div id="1-1" class="square"></div>
            <div id="1-2" class="square"></div>
            <div id="1-3" class="square"></div>
            <!-- 2行め -->
            <div id="2-1" class="square"></div>
            <div id="2-2" class="square"></div>
            <div id="2-3" class="square"></div>
            <!-- 3行め -->
            <div id="3-1" class="square"></div>
            <div id="3-2" class="square"></div>
            <div id="3-3" class="square"></div>
          </div>
        </div>

        <div class="btn-container">
          <div class="js-hidden" id="reset-btn">
            <span class="btn btn-reset">もう一回遊ぶ</span>
          </div>
        </div>

      </div>
    </div>
    <script src="app.js"></script>
  </body>
</html>

CSS

app.css
html {
  box-sizing: border-box;
  font-size: 16px;
}
*, *::before, *::after {
  box-sizing: border-box;
}
li {
  list-style: none;
}
body {
  margin: 0;
  line-height: normal;
}
h1 {
  margin: 20px 0;
  font-size: 2rem;
  font-weight: bold;
}
.wrapper {
  max-width: 1024px;
  margin: 0 auto;
  padding: 0 10px;
  text-align: center;
}
.game-container {
  padding: 60px 0;
}
.message-container {
  margin-bottom: 20px;
  font-size: 1.25rem;
  font-weight: bold;
}
.batsu {
  color: #00b0f0;
}
.maru {
  color: #ff0000;
}
.js-hidden {
  display: none;
}
.squares-container {
  margin: 0 auto;
  width: 202px;
}
.squares-box {
  width: 202px;
  height: 202px;
  display: flex;
  flex-wrap: wrap;
  border: solid 2px #333;
}
.square {
  position: relative;
  width: calc(198px / 3);
  height: calc(198px / 3);
  border: solid 2px #333;
}
.js-maru-checked::before {
  content: '';
  width: 50px;
  height: 50px;
  border: solid 8px #ff0000;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.js-batsu-checked::before {
  content: '';
  width: 50px;
  height: 8px;
  margin: auto;
  background-color: #00b0f0;
  border-radius: 4px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(45deg);
}
.js-batsu-checked::after {
  content: '';
  width: 8px;
  height: 50px;
  margin: auto;
  background-color: #00b0f0;
  border-radius: 4px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(45deg);
}
.btn-container {
  padding-top: 40px;
}
.btn {
  display: inline-block;
  width: 150px;
  padding: 10px 20px;
  border-radius: 5px;
  cursor: pointer;
}
.btn-reset {
  color: #fff;
  background-color: #ffc000;
  font-weight: bold;
}
.btn-reset:hover {
  background-color: #ffd347;
  transition-duration: 0.4s;
}

/* JS連動 */
.js-unclickable {
  pointer-events: none;
}
.js-highLight {
  background-color: #fff2cc;
}
4
3
0

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
4
3