HTML+CSS+JavaScript でシンプルな三目並べゲームを作成する

HTML+CSS+JavaScript でシンプルな三目並べゲームを作成する

デモアドレス

HTMLの実装

まず、head セクションに、後で作成する CSS ファイルと JavaScript ファイルを含めます。また、ItimというGoogleフォントも追加しました。

<link rel="スタイルシート" href="style.css" rel="外部nofollow" >
<link rel="preconnect" href="https://fonts.gstatic.com" rel="外部nofollow" >
<link href="https://fonts.googleapis.com/css2?family=Itim&display=swap" rel="外部nofollow" rel="スタイルシート">
<script src="index.js"></script>

HTML の本文はかなりシンプルになります。最後に、メイン タグを使用して、クラスの背景を適用します。メインラッパー内には 5 つのセクションがあります。

最初のセクションには見出し h1 のみが含まれます。

2 番目のセクションには、現在誰の番であるかが表示されます。ディスプレイには、現在のユーザーに応じて X または O のいずれかを含むスパンが表示されます。このスパンにクラスを適用してテキストに色を付けます。

3番目の部分はゲームボードを保持する部分です。コンテナ クラスがあるので、タイルを正しく配置できます。このセクションには、ボード内でタイルとして機能する 9 つの div があります。

第4部では、最終的なコンテスト結果を発表する役割を担います。デフォルトでは空なので、JavaScript からその内容を変更します。

最後のセクションでは、再起動ボタンを含むコントロールを保存します。

<メインクラス="背景">
        <セクションクラス="タイトル">
            <h1>三目並べ</h1>
        </セクション>
        <セクションクラス="display">
            プレイヤー <span class="display-player playerX">X</span> のターン</section>
        <セクションクラス="コンテナ">
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
        </セクション>
        <section class="display announcementr hide"></section>
        <セクションクラス="コントロール">
            <button id="reset">再起動</button>
        </セクション>
    </メイン>

CSSを追加

CSS のすべての行を詳しく説明することはしませんが、ソース コードで完全なコードを確認できます。

まず、style.css ファイルを作成し、ブラウザで定義された余白とパディングを削除し、ドキュメント全体の HTML に含めた Google フォントを設定します。

* {
    パディング: 0;
    マージン: 0;
    フォントファミリー: 'Itim'、筆記体;
}

次に追加する必要がある重要なことは、ボードのスタイルです。ボードを作成するには CSS グリッドを使用します。列と行に 33% のスペースを 3 回割り当てることで、コンテナーを 2 つに分割できます。 max-width とmargin: 0 auto;を設定してコンテナーを中央に配置します。

。容器 {
    マージン: 0 自動;
    表示: グリッド;
    グリッドテンプレート列: 33% 33% 33%;
    グリッドテンプレート行: 33% 33% 33%;
    最大幅: 300px;
}

次に、ボード内のタイルのスタイルを追加します。小さな白い境界線を適用し、最小の幅と高さを 100 ピクセルに設定します。 Flexbox を利用して、 justify-contentalign-items到center配置します。大きなフォント サイズを設定し、 cursor: pointerを適用して、フィールドがクリック可能であることをユーザーに知らせます。

.タイル{
    境界線: 1px 白の実線;
    最小幅: 100px;
    最小高さ: 100px;
    ディスプレイ: フレックス;
    コンテンツの中央揃え: 中央;
    アイテムの位置を中央揃えにします。
    フォントサイズ: 50px;
    カーソル: ポインタ;
}

2 人のプレーヤーを区別しやすくするために、2 つの異なる色を使用しました。これを実現するために、2 つのユーティリティ クラスを作成します。プレイヤーXの色は緑、プレイヤーOの色は青です。

.playerX {
    色: #09C372;
}

.playerO {
    色: #498AFB;
}

Javascript部分の実装

<head>に JavaScript ファイルを含めています。ブラウザが HTML 本文を解析する前にスクリプトが読み込まれるため、これが必要です。この関数ですべてをラップしたくない場合は、スクリプト タグに defer を追加するか、スクリプト タグを body に移動してください。

window.addEventListener('DOMContentLoaded', () => {

});

まず、DOM ノードへの参照を保存します。 document.querySelectorAll() を使用します。配列が必要ですが、この関数は NodeList を返すため、Array.from() を使用する必要があります。また、プレーヤー ディスプレイ、リセット ボタン、アナウンサーへの参照も取得します。

const tiles = Array.from(document.querySelectorAll('.tile'));
const playerDisplay = document.querySelector('.display-player');
const resetButton = document.querySelector('#reset');
アナウンサー = document.querySelector('.announcer');

次に、ゲームを制御するために必要なグローバル変数を追加します。 9 つの空の文字列の配列を使用してボードを初期化します。これにより、ボード上の各タイルの XabdO 値が保存されます。現在のターンでアクティブなプレイヤーのフラグを保持する currentPlayer を用意します。 isGameActive 変数は、誰かが勝つかゲームが引き分けで終わるまで true のままになります。このような場合は、残りのタイルがリセットされるまで非アクティブになるように false に設定します。ゲームの終了状態を表す定数が 3 つあります。これらの定数はタイプミスを避けるために使用します。

board = ['', '', '', '', '', '', '', '', '', '', ''] とします。
現在のプレイヤーを 'X' にします。
isGameActive を true にします。

定数 PLAYERX_WON = 'PLAYERX_WON';
定数 PLAYERO_WON = 'PLAYERO_WON';
定数TIE = 'TIE';

次のステップでは、ボード上のすべての勝利位置を保存します。各サブ配列には、ゲームに勝つことができる 3 つの位置のインデックスを格納します。したがって、この [0, 1, 2] は、最初の水平線がプレイヤーによって占有されている場合を表します。この配列を使用して、勝者がいるかどうかを決定します。

/*
   ボード内のインデックス
   [0] [1] [2]
   [3] [4] [5]
   [6] [7] [8]
*/

const 勝利条件 = [
   [0, 1, 2],
   [3, 4, 5],
   [6, 7, 8],
   [0, 3, 6],
   [1, 4, 7],
   [2, 5, 8],
   [0, 4, 8],
   [2、4、6]
];

ここで、いくつかのユーティリティ関数を記述します。 isValidAction 関数では、ユーザーが有効なアクションを実行するかどうかを判断します。タイルの内部テキストが XorO の場合、操作が無効であるため false を返します。それ以外の場合はタイルが空であるため、操作は有効です。

const isValidAction = (タイル) => {
    if (tile.innerText === 'X' || tile.innerText === 'O'){
        false を返します。
    }

    true を返します。
};

次のユーティリティ関数は非常に単純になります。この関数では、インデックスをパラメータとして受け取り、ボード配列内の対応する要素を現在のプレーヤーのシンボルに設定します。

const updateBoard = (インデックス) => {
   ボード[インデックス] = currentPlayer;
}

プレーヤーの変更を処理するための小さな関数を作成します。この関数では、まず playerDisplay から値を取得します。文字列テンプレートリテラル player${currentPlayer} は、現在のプレーヤーに応じて playerX または playerO のいずれかになります。次に、三項式を使用して現在のプレーヤーの値を変更します。 X の場合は O、そうでない場合は X になります。プレーヤーの値を変更したので、playerDisplay の innerText を更新し、新しいプレーヤー クラスを適用する必要があります。

定数changePlayer = () => {
    playerDisplay.classList.remove(`player${currentPlayer}`);
    currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
    プレーヤーディスプレイ内のテキストを現在のプレーヤーに表示します。
    playerDisplay.classList.add(`player${currentPlayer}`);
}

ここで、最終的なゲーム結果を発表するアナウンス関数を記述します。終了ゲームタイプを受け取り、その結果に応じてアナウンサー DOM ノードの innerText を更新します。最後の行では、アナウンサーはゲームが終了するまでデフォルトで非表示になっているため、hidden クラスを削除する必要があります。

const アナウンス = (型) => {
    スイッチ(タイプ){
       PLAYERO_WONの場合:
            announcementr.innerHTML = 'プレイヤー <span class="playerO">O</span> が勝利しました';
            壊す;
       PLAYERX_WONの場合:
            announcementr.innerHTML = 'プレイヤー <span class="playerX">X</span> が勝利しました';
            壊す;
       ケース TIE:
            announcementr.innerText = '同点';
        }
    アナウンサー.classList.remove('hide');
};

次に、このプロジェクトの最も興味深い部分の 1 つである結果の評価について説明します。まず、roundWon 変数を作成し、それを false に初期化します。次に、winConditions 配列を反復処理し、ボード上の各勝利条件を確認します。たとえば、2 回目の反復では、board3、boa​​rd4、board5 の値をチェックします。

また、いくつかの最適化も行います。フィールドのいずれかが空の場合は、勝利条件に空のタイルが含まれていると勝利できないため、続行を呼び出して次の反復にスキップします。すべてのフィールドが等しい場合は勝者がいるので、roundWon を true に設定し、for ループを終了します。これ以上の反復は計算の無駄になるためです。

ループの後、roundWon 変数の値をチェックし、true の場合は勝者を宣言し、ゲームを非アクティブに設定します。勝者がいない場合は、ボード上に空のタイルがあるかどうかを確認します。勝者も空のタイルもない場合は、引き分けを宣言します。

関数handleResultValidation() {
  roundWon を false にします。
  (i = 0; i <= 7; i++ とします) {
    定数 winCondition = 勝利条件[i];
    定数a = ボード[winCondition[0]];
    定数 b = ボード[winCondition[1]];
    定数 c = ボード[winCondition[2]];
    もし (a === "" || b === "" || c === "") {
      続く;
    }
    (a === b && b === c) の場合 {
      ラウンド勝利 = true;
      壊す;
    }
  }

  if (ラウンド勝利) {
    アナウンス(currentPlayer === "X" ? PLAYERX_WON : PLAYERO_WON);
    isGameActive = false;
    戻る;
  }

  if (!board.includes("")) announcement(TIE);
}

次に、ユーザーのアクションを処理します。この関数は、タイルおよびインデックスをパラメーターとして受け取ります。ユーザーがタイルをクリックすると、この関数が呼び出されます。まず、それが有効なアクションであるかどうかを確認する必要があります。また、ゲームが現在アクティブであるかどうかも確認します。両方が true の場合、タイルの innerText を現在のプレーヤーのシンボルで更新し、対応するクラスを追加して、ボード配列を更新します。すべてが更新されたので、ゲームが終了したかどうかを確認する必要があるため、handleResultValidation() を呼び出します。最後に、changePlayer メソッドを呼び出して、他のプレイヤーにターンを渡す必要があります。

const userAction = (タイル、インデックス) => {
  if (isValidAction(tile) && isGameActive) {
    tile.innerText = 現在のプレーヤー;
    tile.classList.add(`player${currentPlayer}`);
    ボードを更新します(インデックス);
    結果検証を処理します。
    プレイヤーを変更します。
  }
};

ゲームが正しく動作するためには、タイルにイベント リスナーを追加する必要があります。これを実現するには、タイルの配列をループし、各タイルにイベント リスナーを追加します。 (パフォーマンスを向上させるには、コンテナーにイベント リスナーを追加し、イベント バブリングを使用して親のタイルのクリックをキャプチャすることもできますが、初心者にとってはこの方が理解しやすいと思います。)

tiles.forEach( (タイル, インデックス) => {
    tile.addEventListener('click', () => userAction(tile, index));
});

欠けている機能は 1 つだけです。それは、ゲームをリセットすることです。これを実行するには、resetBoard 関数を記述します。この関数では、ボード X を 9 つの空の文字列で構成し、ゲームをアクティブに設定し、アナウンサーを削除して、プレーヤーを元に戻します (定義により、X は常に開始します)。

最後に、タイルを反復処理して innerText を空の文字列に戻し、タイルからプレーヤー固有のクラスを削除します。

const リセットボード = () => {
    ボード = ['', '', '', '', '', '', '', '', '', '', ''];
    ゲームがアクティブかどうか
    アナウンサー.classList.add('非表示');

    (現在のプレイヤー === 'O') の場合 {
        プレイヤーを変更します。
    }

    タイル.forEach(タイル => {
        タイル.innerText = '';
        tile.classList.remove('playerX');
        tile.classList.remove('playerO');
    });
}

ここで、この関数をリセット ボタンのクリック イベント ハンドラーとして登録する必要があります。

resetButton.addEventListener('click', resetBoard);

これで完了です。友達と一緒に楽しく遊べる、完全に機能する Tic Tac Toe ゲームが完成しました。

以上が、HTML+CSS+JavaScript を使用したシンプルな三目並べゲームの作成の詳細です。HTML+CSS+JavaScript の詳細については、123WORDPRESS.COM の他の関連記事をご覧ください。

以下もご興味があるかもしれません:
  • HTML+CSS+JavaScript でガールフレンド版のスクラッチ カードを作成します (一度見ればすぐに覚えられます)
  • HTML+CSS+JS でキャンバスがマウスの小さな円に追従する特殊効果のソースコードを実現
  • Python 入門ゲーム tic-tac-toe のサンプルコード
  • C言語に基づく三目並べゲームの実装

<<:  リストループスクロールを実現するための HTML+CSS+JavaScript サンプルコード

>>:  rpm を使用して指定されたバージョンの docker (1.12.6) をインストールする詳細な手順

推薦する

Vue は PDF.js を統合して PDF プレビューを実装し、透かしを追加する手順を実行します。

目次成果を達成する利用可能なプラグインの紹介ニーズに応じてプラグインを選択するプラグインのインストー...

Vue3 の父子値転送に関する簡単な説明

目次父から息子へ: 1. 親コンポーネントのサブコンポーネントタグに、サブコンポーネントに渡されるデ...

MySQL 5.7.25 のインストールと設定方法のグラフィックチュートリアル

MySQL インストール ファイルには、msi 形式と zip 形式の 2 種類があります。クリック...

JavaScript ステートメントの一般的な for ループの詳細な説明

JavaScript には、for、for in、for of、forEach ループなど、多くのル...

wgetはウェブサイト全体(サブディレクトリ全体)または特定のディレクトリをダウンロードします

wgetコマンドを使用して、親ディレクトリの下のサブディレクトリ全体をダウンロードします。親ディレク...

easycomモードでUNI-APPコンポーネントを呼び出す際に習得する必要がある実践的なスキル

この記事は議論の出発点となることを目的としています。詳細なドキュメントと easycom の仕様につ...

Mysql 5.7.19 無料インストール版 (64 ビット) の設定方法に関する詳細なチュートリアル

公式サイトから mysql-5.7.19-winx64 をダウンロードします。これはシステムの 64...

DockerはRedisを起動し、パスワードを設定します

RedisはRedisバージョン5のapline(Alps)イメージを使用します。これは小さくて高速...

MySQL タイムブラインドインジェクションの 5 つの遅延方法

MySQL タイム ブラインド インジェクションの 5 つの遅延方法 (PWNHUB の予期しない解...

イメージのアップロードとダウンロードに docker をプロキシするためのプライベート ライブラリとして nexus を使用する

1. Nexusの設定1. Dockerプロキシを作成する外部ネットワーク ウェアハウスからローカル...

MySQL 8.0.12 インストール グラフィック チュートリアル

MySQL8.0.12 インストールチュートリアルをみんなで共有します。 1. インストール1.イン...

MySQLのトランザクション管理操作の詳細な説明

この記事では、MySQL のトランザクション管理操作について説明します。ご参考までに、詳細は以下の通...

nginx+php実行リクエストの動作原理の詳細な説明

PHPの仕組みまず、よく耳にするcgi、php-cgi、fastcgi、php-fpmの関係を理解し...

JavaScript における clientWidth、offsetWidth、scrollWidth の違い

1. コンセプトこれらはすべて Element の属性であり、要素の幅を示します。 Element....

Linux システムの最適化 (カーネルの最適化) に関するいくつかの提案

スワップを無効にするサーバーがデータベース サービスまたはメッセージ ミドルウェア サービスを実行し...