三目並べのゲームを作成します。 ステージ:プレーヤーが勝ったかどうかを確認します

注意! これはレッスンの試用版ですが、その資料は完全ではない可能性があります。

学生としてログイン

学生としてサインインして、学校のコンテンツにアクセスします

1C構成の作成:「Tic-tac-toe」パート1/3の記述

遊びながら学ぶので、最初のプロジェクトは
子供の頃のゲームでおなじみの「三目並べ」。

ゲームは1C、会計、貿易と何の関係があるのでしょうか? ほとんどなし。 しかし、徐々に始める必要があり、時間の経過とともに倉庫の自動化に到達します。 とりあえず、小さなことから始めましょう。

Tic-Tac-Toeゲームのプログラミングを開始する前に、考えてみましょう。

フォームに要素があり、そのうちの1つがボタンであることはすでにわかっています。 ボタンはコマンドを実行することができ、同時に、フォーム上での表示(タイトルなど)を制御できるプロパティを備えています。

たとえば、ボタンを使用して、9つのホットスポット(「O」と「X」の形式で碑文を表示しながら、クリックしてアクションを修正するセル)を含むフィールドを作成できます。 これにふさわしい以上のボタンを押してください。

何が必要ですか? 明らかに、私たちは自分の動きを覚えて、コンピューターの動きを覚えておく必要があります。 ボタンのタイトルも変更する必要があります。クリックすると、ボタンのタイトルは常に「O」になり、コンピューターが移動すると「X」になります。

まず、ゲームを作成する新しいデータベースを作成する必要があります。 やってみましょう。

ステップ1:空のベースを作成する

空のTic-Tac-Toeデータベースを作成しましょう。

詳細な手順

走りましょうコンピューターで利用可能な情報ベースのリストを開くための1Cショートカット。 レッスンの試用版を読んでいます。完全なレッスンがあります。 新しいデータベースを作成する必要があるので、[ 追加":

インフォベースを追加するためのウィンドウが開きます。このウィンドウで、最初のアイテムを選択する必要があります。 情報基盤の構築[次へ]ボタンをクリックします。

次のウィンドウで、2番目の項目「 新しい構成を開発するための構成なしでインフォベースを作成する...もう一度[次へ]ボタンをクリックします。

次のウィンドウで、新しいベースの名前を入力するように求められます。その下に、ベースのリストに表示されます。 「」と入力しましょう ○×ゲーム[次へ]ボタンをクリックします。

次のウィンドウで、データベースが保存される空のフォルダーへのパスを指定する必要があります。 この場合、フォルダを作成しました " ○×ゲームドライブDの「Bases1C」フォルダ内の「」:

次のウィンドウで、すべてのデフォルト設定をそのままにして、[ 準備":

少し間を置いた後、データベースが作成され、リストに追加されます。 データベースの操作には、主に2つのモードがあります。 1C:エンタープライズConfigurator:

Configuratorモードでは、ベースを構成してプログラムします。1C:Enterpriseモードでは、ベースの内容を確認します。

ステップ2:コンフィギュレーターを開きます

ボタンを押してみよう Configurator"コンフィギュレーターモードに入るには:

ステップ3:構成ツリーを開く

メニューコマンド「 構成"->"構成を開く":

構成のさまざまなセクションを含む構成ツリーが目の前に開きました。 まだ何も作成していないため、これらのセクションはこれまでのところ空です。

ステップ4:処理を追加する

ゲームのロジックを配置するために、「処理」セクションを使用します。 を押しましょう 右クリックセクション " 処理「追加」コマンドを選択します。

新しい処理を作成するためのウィンドウを開く前に。 名前を入力してください ○×ゲーム"。同義語はそれ自体で置き換えられます。これは、処理をデータベースに保存するのに十分です(まだ空です)。[閉じる]ボタンを押します。

ステップ5:最初にプログラムをデバッグする

ユーザーモードから何が起こったかを確認できます( 1C:エンタープライズ)。 configuratorから直接アクセスするには、メニューコマンド「 デバッグ"->"デバッグを開始します":

データベースに変更を加えたため、この変更を受け入れることに同意するかどうかを尋ねられます。 この質問は、開発プロセスで常に私たちに尋ねられます。 同意を得て回答します(ボタン「 はい"):

データベースは1C:Enterpriseモードで起動されました。 レッスンの試用版を読んでいます。完全なレッスンがあります。 しかし、私たちが見ることができるように、彼女と一緒に働くことはまだ難しいです-単に選択するものは何もありません。 処理はすでに作成されており、理論的には黄色のパネルに表示されるはずなので、奇妙です。

三目並べで打ち負かされないボットの書き方、またはミニマックスルールの紹介

何百もの三目並べのゲームの後、あなたは疑問に思った可能性があります:最適なアルゴリズムは何ですか? しかし、あなたがここにいるなら、あなたはおそらくこのゲームの実装を書き込もうとしたでしょう。 さらに進んで、三目並べで打ち負かすことのできないボットを作成します。 「なぜ?」というあなたの質問を予想して、私たちは答えます:アルゴリズムのおかげで。

プロチェスプレーヤーのように、このアルゴリズムは、勝利、敗北、引き分けのいずれであっても、ゲームの最後に到達するまで、数歩先の対戦相手のアクションを計算します。 この最終状態になると、AIは勝つために正のスコア(この場合は+10)、負けのために負のスコア(-10)、引き分けのためにニュートラルスコア(0)を与えます。

同時に、アルゴリズムはプレーヤーの動きに対して同様の計算を実行します。 AIが移動した場合はスコアが最も高い移動を選択し、プレーヤーが移動した場合はスコアが最も低い移動を選択します。 この戦略を使用して、ミニマックスは敗北を回避します。

このゲームをプレイしてみてください。

ミニマックスアルゴリズムは、次のような再帰関数として最も簡単に説明されます。

  1. 終了状態が見つかった場合は値を返します(+ 10、0、-10)、
  2. フィールド上のすべての空のセルを通過し、
  3. それらのそれぞれに対してミニマックス関数を呼び出します(再帰)、
  4. 受信した値を評価します
  5. 最良のものを返します。

再帰に慣れていない場合は、ハーバードCS50コースのこの講義をご覧ください。

ミニマックスがどのように機能するかを理解するために、その実装を記述し、その動作をモデル化しましょう。 これについては、次の2つのセクションで扱います。

ミニマックスの実装

ゲームが終了したときの状況を検討します(下の写真を参照)。 minimaxは考えられるすべてのゲーム状態を通過するため(そして数十万の状態があります)、エンドゲームを検討するのは理にかなっています。このようにして、再帰関数呼び出しの数を減らす必要があります(合計9つ)。

AIに十字架で遊んでもらいましょう。男はゼロで。

フィールドでの作業を簡素化するために、セルの内容と等しい値を持つ9つの要素の配列として宣言しましょう。 上の図のように、十字とゼロで埋めて、origBoardと呼びましょう。

Var origBoard = ["O"、1、 "X"、 "X"、4、 "X"、6、 "O"、 "O"];

次に、変数aiPlayerとhuPlayerを宣言し、それぞれ値「X」と「O」を割り当てます。

さらに、勝ちの組み合わせを探し、検索が成功した場合にtrueを返す関数と、使用可能なセルのインデックスを格納する関数が必要です。

/ *初期ボード状態O | | X --------- X | | X --------- | O | O * / var origBoard = [“ O”、1、” X”、” X”、4、” X”、6、” O”、” O”]; //人間の変数huPlayer =“ O”; // AI var aiPlayer = "X"; //ボード上の空のセルのインデックスのリストを返しますfunctionemptyIndi​​ces(board)(return board.filter(s => s!= "O" && s!= "X");)//勝ちの組み合わせ。アカウントインデックス関数winning(board、player)(if((board == player && board == player && board == player)||(board == player && board == player && board == player)||(board ==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー)||(ボード==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー)||(ボード==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー) ||(ボード==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー)||(ボード==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー)||(ボード==プレーヤー&&ボード==プレーヤー&&ボード==プレーヤー))(trueを返す;)else(falseを返す;))

それでは、newBoard(新しいボード)とplayer(プレーヤー)の2つの引数を使用してミニマックス関数を定義しましょう。 次に、フィールド上の空きセルのインデックスを見つけて、それらをavailSpots変数に渡します。

//メインミニマックス関数functionminimax(newBoard、player)(//使用可能なセルvar availSpots = emptyIndi​​ces(newBoard);

さらに、最終状態を追跡し、適切な値を返す必要があります。 ゼロが勝った場合、「クロス」の場合は-10を返す必要があります-+ 10。 availSpots配列のサイズがゼロの場合、空きセルはなく、ゲームは引き分けで終了し、ゼロが返されます。

//端末の状態を確認します(win / lost / draw)//それに応じて値を返しますif(winning(newBoard、huPlayer))(return(score:-10);)else if(winning(newBoard、aiPlayer)) (return(score:10);)else if(availSpots.length === 0)(return(score:0);)

その後、空の各セルからポイントを集める必要があります。 これを行うには、移動の配列を作成し、すべての空のセルをループして、各移動のインデックスとスコアを移動オブジェクトに入れます。

次に、origBoardに数値として格納されている空のセルのインデックスを、moveオブジェクトのindexプロパティに設定します。 次に、現在のプレーヤーを新しいフィールドnewBoardの空のセルに移動し、別のプレーヤーと結果のフィールドnewBoardからミニマックス関数を呼び出します。 その後、minimax関数によって返されたオブジェクトのscoreプロパティをmoveオブジェクトのscoreプロパティに入れる必要があります。

ミニマックスが最終状態を見つけられない場合、それが最終状態に達するまで、それは再帰的にゲームプレイに深まり続けます。 その後、この「レベル」の再帰のポイントを1レベル上に渡します。

最後に、この関数はnewBoardをリセットし、moveオブジェクトをmoves配列に配置します。

//すべてのオブジェクトを格納する配列varmoves =; //(var i = 0; iの使用可能なセルを循環します< availSpots.length; i++){ //create an object for each and store the index of that spot var move = {}; move.index = newBoard]; // совершить ход за текущего игрока newBoard] = player; //получить очки, заработанные после вызова минимакса от противника текущего игрока if (player == aiPlayer){ var result = minimax(newBoard, huPlayer); move.score = result.score; } else{ var result = minimax(newBoard, aiPlayer); move.score = result.score; } // очистить клетку newBoard] = move.index; // положить объект в массив moves.push(move); }

次に、Minimaxは、moves配列から最適なmoveを選択する必要があります。 AIの動きの場合はスコアが最も高く、人間の動きの場合はスコアが最も小さい動きが必要です。 したがって、playerの値がaiPlayerの場合、アルゴリズムはbestScore変数を非常に小さい数に初期化し、moves配列をループします。movemoveがbestScoreよりも高いスコアを獲得した場合、アルゴリズムはそのmoveを記憶します。 同じポイントでの移動の場合、アルゴリズムは最初の移動を記憶します。

プレーヤーがhuPlayerと等しい場合、すべてが同じです。現在、bestScoreは多数で初期化され、minimaxは最小のポイント数で移動移動を探します。

最後に、minimaxはbestMoveに格納されているオブジェクトを返します。

// AIの動きの場合は、動きをループして、スコアが最も高い動きを選択しますvar bestMove; if(player === aiPlayer)(var bestScore = -10000; for(var i = 0; i< moves.length; i++){ if(moves[i].score >bestScore)(bestScore = move [i] .score; bestMove = i;)))else(//それ以外の場合は、移動をループして、スコアが最も低い移動を選択しますvar bestScore = 10000; for(var i = 0; i< moves.length; i++){ if(moves[i].score < bestScore){ bestScore = moves[i].score; bestMove = i; } } } // вернуть выбранный ход (объект) из массива ходов return moves; }

次のセクションでは、プログラムをシミュレートして、プログラムがどのように機能するかを理解します。

動作中のミニマックス

次の図を使用して、アルゴリズムの段階的なモデルを分析します。

ノート:図では、大きな数字は関数呼び出しの序数を示し、レベルはアルゴリズムが進んだ数を示します。

  1. アルゴリズムはorigBoardとaiPlayerに供給されます。 見つかった3つの空のセルのリストを作成し、状態が有限であるかどうかを確認して、すべての空のセルをループします。 次に、アルゴリズムはaiPlayerを最初の空のセルに配置することでnewBoardを変更します。 その後、newBoardとhuPlayerから自分自身を呼び出し、2番目の呼び出しが値を返すのを待ちます。
  2. 最初の関数呼び出しがまだ実行されている間に、2番目の関数呼び出しが実行され、2つの空のセルのリストが作成され、状態が有限かどうかがチェックされ、すべての空のセルがループされます。 次に、2番目の呼び出しは、huPlayerを最初の空のセルに配置することによってnewBoardを変更します。 その後、newBoardとaiPlayerから自分自身を呼び出し、3回目の呼び出しで値が返されるのを待ちます。

  3. 2番目の呼び出しで2つの空のセルが見つかったため、minimaxはhuPlayerを2番目の空きセルに配置してnewBoardを変更します。 次に、newBoardとaiPlayerから自分自身を呼び出します。

  4. アルゴリズムは空のセルのリストをコンパイルし、状態の有限性をチェックした後、プレーヤーの勝利を修正します。 したがって、カウントフィールドが(-10)に等しいオブジェクトを返します。

    2番目の関数呼び出しでは、アルゴリズムは3番目と4番目の関数呼び出しによって下位レベルから返された値を受け取ります。 huPlayerの移動により、これら2つの結果が生成されたため、アルゴリズムはそれらのうち最小のものを選択します。 それらは同じであるため、アルゴリズムは最初のものを選択し、それを最初の関数呼び出しに渡します。

    この時点で、最初の関数呼び出しは、最初の空のセルへのaiPlayerの移動の見積もりを受け取りました。 次に、aiPlayerを2番目の空のセルに配置してnewBoardを変更します。 その後、newBoardとhuPlayerから自分自身を呼び出します。

  5. 5番目の関数呼び出しでは、アルゴリズムは空のセルのリストをコンパイルし、状態の有限性をチェックした後、AIの勝利を修正します。 したがって、カウントフィールドが+10のオブジェクトを返します。

    その後、最初の呼び出しでaiPlayerを3番目の空のセルに配置してnewBoardを変更します。 次に、newBoardとhuPlayerから自分自身を呼び出します。

  6. 6番目の呼び出しは、2つの空のセルのリストをコンパイルし、状態が有限であるかどうかを確認し、すべての空のセルをループします。 次に、huPlayerを最初の空のセルに配置してnewBoardを変更します。 次に、newBoardとaiPlayerから自分自身を呼び出し、7番目の呼び出しが値を返すのを待ちます。
  7. 新しい呼び出しは、1つの空のセルをリストし、状態が有限であるかどうかをチェックし、aiPlayerを空のセルに配置することによってnewBoardを変更します。 その後、newBoardとhuPlayerから自分自身を呼び出し、この呼び出しが値を返すのを待ちます。
  8. 8番目の呼び出しは、空のセルの空のリストをコンパイルし、状態の有限性をチェックした後、aiPlayerの勝利を修正します。 したがって、カウントフィールドが1レベル上の(+10)に等しいオブジェクトを、7番目の呼び出しに返します。

    7番目の呼び出しは、下位レベルから1つの正の値のみを受け取りました。 この値はaiPlayerの実行中に受信されたため、アルゴリズムは受信した値の最大値を返します。 したがって、6番目の呼び出しまで1レベル上の正の値(+10)を返します。

    6番目の呼び出しで2つの空のセルが見つかったため、minimaxはhuPlayerを2番目の空のセルに配置してnewBoardを変更します。 次に、newBoardとaiPlayerから自分自身を呼び出します。

  9. その後、アルゴリズムは空のセルのリストをコンパイルし、状態の有限性をチェックした後、aiPlayerの勝利を修正します。 したがって、1レベル上の(+10)に等しいカウントフィールドを持つオブジェクトを返します。

    この時点で、6番目の呼び出しは、7番目の呼び出しによって返されるスコア(+10)と9番目の呼び出しによって返されるスコア(-10)のどちらかを選択する必要があります。 huPlayerの移動により、これら2つの結果が得られたため、アルゴリズムはそれらのうち最小のものを選択し、スコアフィールドとインデックスフィールドを持つオブジェクトとしてレベルを上げて返します。

    最後に、最初の呼び出しの3つのブランチすべてが評価されます(-10、+ 10、-10)。 aiPlayerの移動により、これら3つの結果が得られたため、アルゴリズムは、最高のスコア(+10)とそのインデックス(4)を含むオブジェクトを選択します。

上記のシナリオでは、ミニマックスは、フィールドの中央の正方形に移動することが最善の選択であると判断します。

終わり!

これで、ミニマックスアルゴリズムがどのように機能するかを理解する必要があります。 自分で実装を作成するか、GitHubまたはCodePenで例を確認して最適化してください。

ゲームにおけるAIのトピックに興味がある場合は、このトピックに関する資料を読むことをお勧めします。

ステップ1.フォームパラメータの設定1。 フォームをカスタマイズするには、そのサイズを設定します
水平ドット510個と垂直ドット480個
垂直。 最大値と最小値
同じ値に等しいサイズを指定します。
2.「TicTacToe」という単語で図形に名前を付けます。
3.フォームの背景には、フォルダーのファイルを使用します
background.pngという名前の画像を配置します
フォームの中央にあります。
4.タイトルバーのアイコンの場合
フォルダの使用ファイルを使用
menu4.icoという名前の画像。
5.フォームの背景色を設定する必要があります
MintCream。

ステップ2.フォームにボタンとクラスを追加します

1.配置された要素については、変更します
フォントサイズを12に設定し、背景を設定
トランスペアレント。

1.アイテムを含むメニューバーを作成します
画像に示されているように。

ステップ3.フォームにメニューバーを追加する

1.メニュー項目[ファイル]でコマンドを作成します
出口。
2.の場合
コマンド
出口
処方する
プログラムコードはと同じです
以前のアプリケーション。

ステップ3.フォームにメニューバーを追加する

1.メニュー項目ゲームでチームを作成します
新しいゲーム。
2. New Gameチームの場合、次のように記述します
将来のプログラムコード
いくつかの手順。

ステップ3.フォームにメニューバーを追加する

1. [ヘルプ]メニュー項目で、コマンドを作成します
プログラムについて。
2. [バージョン情報]コマンドで、新しいコマンドを作成します
プログラムコードを作成して記述します
前と同じ
応用。

1.PictureBoxをフォームにドラッグします
サイズを100x100に変更します。
2.透明な背景を設定します。
3.PictureBoxを次のように配置します。
競技場の最初のセルの上の図。

ステップ4.フォームにPICTUREBOXオブジェクトを追加します

1
2
3
4
5
6
7
8
9
1.残りのセルの上に配置します
PictureBoxオブジェクト、最初のコピー
オブジェクト、に示されている番号に従って
画像。

1.コードを書く前に
フォルダに必要
\ Visual Studio
2010 \ Projects \ Tic Tac Toe \ Tic Tac Toe
zeros \ bin \ Debug \をリダイレクトする必要があります
画像フォルダのx.png、0.png、none.pngファイル。
2.最初のマウスをダブルクリックします
PictureBox。

ステップ5.PICTUREBOXオブジェクトのコードを追加する

1.のすべての要素にアクセスできる2次元配列を作成します
整数で構成される3x3要素の形式で作成されます。 すぐに
宣言するときはゼロで埋めます。 空のセルの場合、
「クロス」-1、「ゼロ」-1には0を使用します。

ステップ5.PICTUREBOXオブジェクトのコードを追加する

最初をクリックしたときの手順で
PictureBox、演算子を追加
選択
これは
意思
ステータスチェックを実行します
配列セル。 値が
配列セルは0になります。
これは、「ゼロ」が含まれていないことを意味します。
「クロス」、そしてこのセルで
配列は1で書かれています
PictureBox1
表示
「十字架」のイメージ、そしてもし
配列セルの値は
1に等しい場合、
「クロス」と0が書き込まれ、
空のセルが表示されます。

ステップ5.PICTUREBOXオブジェクトのコードを追加する

1
2
3
4
5
6
7
8
9



フィールドの残りのセルについては、コードを追加します
最初のものと同じように、変更するだけです
PictureBoxオブジェクト番号とセルアドレス
配列。
2番目のセルの例:

ボタンをクリックして手順を実行するには
追加
オペレーター
サイクル
チェックする人
最初から
空のセルの存在。 で、もし
セルが空です
その後、それに
「ゼロ」は、すなわちで書かれています
配列セルは-1と書かれています。
将来の仕事の便宜のために
変数

j
どれの
ループを繰り返すために使用されます
フォーム全体を宣言します。

ステップ6.ウォークボタンのプログラムコードを追加します

ゼロを表示するには
ゲーム
分野
必要
本体にプログラムコードを追加する
セルの空をチェックするサイクル。
ネストされた演算子を使用
分岐
意思
行われる
配列セルアドレスの解析
正しい出力がゼロ
PictureBox。
また、breakステートメントを追加します
時期尚早の終わりのために
空のときにループする
細胞。

ステップ6.ウォークボタンのプログラムコードを追加します

ゲームのステータスを示すため
インターフェイス要素が使用されます
Label1。 プレイヤーは常に動くので
初め
それから

ダウンロード
アプリケーション
必要
v
エレメント
Label1
必要
反射する
フレーズ「あなたの
動く。"
にとって
これ
作成
変数
答え
どれの
このフレーズを見てみましょう。 A
フォーム変数をロードするとき
要素に割り当てる必要があります
Label1、必要なものを作成します
手順
必要
最初にダブルクリック
知らせる

ステップ7.新しいゲームメニューアイテムのコードを追加する

新しいコマンドをクリックすると
ゲームはリセットされます
配列内のすべてのセル、すべてを置き換えます
「クロス」と「ノーツ」
空のセル。 また出力
「あなたの動き」のレタリング

ステップ8.ゲームの結果を表示する

移動の結果を確認するには
必要
分析する
行、列、および
対角線。 3つの要素すべてが
が1に等しい場合、これはプレーヤーの勝利であり、
3 -1の場合、これは敗北です
プレーヤー。
勝利チェックが必要です
行為
フロント
動く
コンピューター、
a
検証
後に敗北。
手順の最後のコマンド
結果が表示されます
動く。

ステップ8.ゲームの結果を表示する

ユーザーの勝利を確認するためのプログラムコード:
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
if(znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1 && znacheniyeYacheyki == 1)otvet = "あなたが勝ちました";
ユーザーの勝利を確認するためのプログラムコード:
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
if(znacheniyeYacheyki == -1&znacheniyeYacheyki == -1&znacheniyeYacheyki == -1)otvet = "あなたが失った";
label1.text =応答;

ステップ9「プレイアビリティ」を改善する

プレイアビリティを向上させる
シリアル出力の代わりに
最初の空で
「ゼロ」のセル、実装
ランダムジェネレーターによる出力
数字。
このためにあなたは追加する必要があります
1つのブール変数
uslovie、およびループタイプをForから変更します
わからないので
正確な繰り返し回数
乱数ジェネレータ
空のセルには分類されません。

ロシア教育科学省

高等専門教育の連邦州予算教育機関

「ヴォロゴダ州立大学」

自動化およびコンピュータ工学科

規律に関するコースプロジェクトの説明文

プログラミングとアルゴリズム化の基礎

"○×ゲーム"

満たされたグループEM-21の学生

ブトロワL.ユウ

受け入れられました RzheutskayaS.Yu。

前書き

1.問題の分析と開発されたプログラムの要件の決定

1プログラムの目的、そのユーザー、開発中に追求される主な機能と目標

2同様の機能を実行する有名なプログラムの概要

3開発の理論的基礎

4開発ツールの選択

開発の一部を設計する

1ユーザーインターフェイスの設計

2.2データ構造の開発(外部およびRAM)

2.3アルゴリズムの開発と分析

C ++でのプログラムの実装

1プログラムアーキテクチャ

2標準の視覚的および非視覚的コンポーネントの選択

試験結果

結論

参考文献

アプリケーション

前書き

Tic-tac-toe-3 x 3セル以上の正方形のフィールド(「エンドレスフィールド」まで)での2人の対戦相手間の論理的なゲーム。 プレイヤーの1人は「クロス」で、2人目は「ノーズ」でプレイします。 このゲームは、コンピューターが登場するずっと前から人気があり、単純な紙とペンでプレイされていました。 伝統的な中国のゲームは黒と白の石を使用しています。

このコースワークでは、ゲームフィールドの基本的なルールと標準サイズ(3x3セル)が保持されます。 ゲームの便宜上、最初の動きの右側はユーザーに任されています。つまり、「クロス」です。

Tic-tac-toeはユーザーを楽しませるために設計されたプログラムであるため、このコース作業でのインターフェイスは、ゲームプレイの感情的な部分を悪化させるポジティブな色の組み合わせを使用したゲームスタイルで作成されます。

ゲームには3つのタイプがあります。X対0-ユーザー対ユーザー、「コンピューターで1レベル」-世界のゲームの基礎を学んでいる人向け、レベル「コンピューターで2レベル」-彼らの勝利を絶対に確信しています。 レベル1と2では、「勝つ」、「負ける」、「引く」の3つの結果が考えられます。 垂直、水平、または対角線が十字またはノーツで完全に満たされている場合、勝利は固定されます。

フィールドの空きセルが終わったが、誰も勝てなかった場合、ゲームは「引き分け」で終了したと見なされます。

1.問題の分析と開発されたプログラムの要件の決定

プログラムクロスインターフェース

1.1プログラムの目的、そのユーザー、開発中に追求される主な機能と目標

このプログラムの目的は、まず第一に、仕事が休む必要があるため、人の待ち時間を明るくするためにユーザーを楽しませることです。このシンプルなゲームは、リラックスして日常生活から気をそらすのに役立ちます。 また、「三目並べ」は、論理的思考を訓練し、集中して記憶を発達させるように設計された知的および論理的ゲームのクラスに属しています。

ユーザーのターゲットオーディエンスは、子供と10代の若者、および大人です。 製品を使用するための主な基準は、プログラムで書かれたテキストを読む能力と、ボタンを使用してコンピューターに必要なタスクを選択する能力です。

このことから、主なタスクは、娯楽のタスクと人の論理的可能性を開発するタスクであると結論付けることができます。

1.2同様の機能を実行する既知のプログラムの概要

インターネット上には、このゲームを実装した作品がたくさんあります。 現在、元の標準から逸脱したこのゲームの多くの類似物があります。 このようなプログラムの例としては、無限フィールド上のTic-Tac-ToeやTic-Tac-Toe3Dがあります。 また、多くのゲームでは、「十字」と「つま先」は、たとえば「石」などの他の記号に置き換えられます。

私のコースプロジェクトはPCアプリケーションです。 このゲームは、対戦相手が人工知能(またはコンピューター)である1人のユーザーと、2人のユーザーの両方を対象に設計されています。 これは、従来の3x3フィールドで表示されます。

私の意見では、最も興味深く珍しいのはゲーム「Tic TacToe3D」でした。 だから私は比較のためにそれを選びました。

三目並べは、紙や通常のフィールドよりもはるかに興味深いものです。 ここでは勝ち負けの機会が多く、引き分けはまれです。 一人で、コンピューターと対戦することも、友達と一緒にプレイすることもできます。 そして、ここで最も珍しいことは、勝つために、任意の1つのレベルだけでなく、壁の平面に沿って、さらには全体の対角線に沿って、あなたの色(黒または白)の3つのボールの組み合わせを作ることができるということですフィールド(図1.1)。

米。 1.1

同様のテーマの多種多様なゲームの中で、各作品で計画の独自の実装を区別することができます。 各プロジェクトは、その個性が他のプロジェクトとは異なります。

1.3開発の理論的基礎

分析

アルゴリズムは各当事者によく知られており、対戦相手のゲームで引き分けを保証します。対戦相手がミスを犯した場合は、勝つことができます。 つまり、ゲームは状態にあります 「誰の死もない」<#"877528.files/image002.gif">

図1.2。 ゲームの状況の木

三目並べのゲームのゲーム状況の部分的なツリーを図1.2に示します。 三目並べのゲームのゲーム状況のツリー。「三目並べ」のプレーヤーが先に進み、上記のアルゴリズムに従って動作し、「三目並べ」のプレーヤーは好きなことを実行できます。 (さらに、1つの頂点は、合理的および非合理的な行為、つまり別の行為のために与えられます)、50ノードで構成されます。

1.4開発ツールの選択

タスクを実装するには、統合されたアプリケーション開発環境が必要です。 したがって、プロジェクトはMicrosoft Visual Studio2008プログラミング環境で開発されました。

Microsoft VisualStudio-Microsoft製品ライン 、統合開発環境を含む ソフトウェアおよび他の多くのツール。 これらの製品を使用すると、コンソールとして開発できます アプリケーション GUIアプリケーションだけでなく 、Windowsフォームテクノロジのサポートを含む だけでなく、ウェブサイト 、 ウェブサービス ネイティブのように 、および制御された Windowsでサポートされているすべてのプラットフォームのコード Windows Mobile 、Windows CE 。ネットフレームワーク 、Xbox 、 ウインドウズの電話 .NET Compact Framework およびSilverlight .

2.開発の一部を設計する

2.1ユーザーインターフェースの設計

ゲームアプリケーションを作成するときは、製品の成功の主要なコンポーネントの1つを考慮する必要があります。これがインターフェイスです。 プログラムのユーザーインターフェイスは、まず第一に、ユーザーにとって理解可能で魅力的なものでなければなりません。 ユーザーの気を散らしたり、不快感を与えたりするすべての瞬間を取り除くようにする必要があります。 プログラムのインターフェース全体は、2つのコンポーネントに分けることができます。

)プログラムのメインメニュー

米。 2.1-プログラムのメインメニュー

メインメニューは、ユーザーがゲームの雰囲気に参加できるように設計されているため、インターフェイスはカラフルで遊び心のある色で作られています。 メニューから、競技場に移動したり、ゲームのルールを確認したり、ゲームを終了したりできます。

) プレイフィールド

図2.2-競技場

競技場には、プレーヤーとコンピューターがアイコンを配置するゲームのすぐ近くの領域が含まれています。 ゲームを開始する前に、ユーザーは「X vs. 0」、「1レベルのコンピューター」、「2レベルのコンピューター」などのゲームタイプを選択する必要があります。そうしないと、プログラムは何をすべきかを示すメッセージを表示します。 プレーヤーがメインメニューに戻るのに役立つボタン。 最後に、追加のウィンドウがポップアップ表示され、決闘の結果について参加者に通知されます。

米。 2.3-追加のゲーム結果ウィンドウ

2.2データ構造の開発(外部およびRAM)

RAMは、競技場の状態を格納する9つの要素で構成される1次元配列に使用されます。配列の各セルは、競技場のセルに対応します。 メモリは静的変数にも費やされます:レベル番号、順番順。

実行するには、803KBの空きメモリが必要です。

.3アルゴリズムの開発と分析

ゲーム思考アルゴリズムを実装するには、静的配列gcnewarrayを指定する必要があります (9); 競技場の状態が保存され、配列の各セルがセルに対応します。 「0」-空のセルに対応します。プレーヤーがセルに移動した場合、つまり「X」の場合、値「1」が記録され、コンピューターが移動した場合、つまり「O」の場合、値は次のようになります。 「2」。 最初は、配列のすべての要素は「0」に等しくなります。 レベルデータを格納する静的変数lvlを設定する必要があります。 このゲームには合計3つのレベルがあります。ユーザーがゲームタイプ「Xvs。O」を選択した場合、lvlは値「1」、「コンピューターとの1レベル」の場合、値「2」を取ります。 「コンピュータとの2レベル」の場合は3」。 変数player-移動の順序を格納します( "true"-プレーヤーの移動、 "false"-コンピューターの移動)。 最初の動きの権利はユーザーに付与されるため、ゲームの開始時にプレーヤー= trueです。 フラグ静的変数は、競技場に空のセルがあるかどうかに関する情報を格納します。フラグ= trueの場合、つまりfalseの場合、空のセルはありません。 検証アルゴリズムには、配列xのパラメーターの列挙が含まれている必要があり、独自のソリューションを提案する必要があります。これは、今後のゲームに最適です。 このプログラムは、コンピューターでゲームの2つのレベルを提示します。 レベル1では、コンピューターのタスクは対戦相手を打ち負かすことではありません。 したがって、この関数は、コンピューターが移動するセルのランダムな値を返します。 このアルゴリズムのコードは[付録1]に示されています。 図2.4に、コード実装のブロック図を示します。

ゲーム開始時に最も勝った動きは、フィールドの中心への動きです。 dif_level()関数では、最初に条件がチェックされます。プレーヤーが中央のフィールドに移動しなかった場合、コンピューターはそこに移動します。 それ以外の場合、プレーヤーが中央に行くと、check(2)関数が呼び出されてコンピューターの組み合わせがチェックされ、勝つことができる場合はセル番号が返されます。 コンピューターが次の動きで勝つことができない場合、check(1)関数が呼び出されます:プレーヤーの組み合わせをチェックします。 セルの数が返され、プレーヤーが勝つ賭けが行われます。 そのような組み合わせがない場合は、low_level()関数が呼び出されます。

図2.4。 -フローチャート

図2.5。 -フローチャート

3. C ++でのプログラムの実装

.1プログラムアーキテクチャ

このプログラムは、メインメニュー(図2.1)、プレイフィールド(図2.2)、ヘルプフィールド(ゲームのルール)の3つのフォームを実装しています。 12枚のパネル。そのうち9枚がメインです。 また、ゲームの終了時に、pictureBoxが表示され、結果が表示されます。合計で5つあります(図2.3)。

基礎として、あなたはパネルクリックハンドラーを取ることができます、そしてその中のちょうど9つが競技場にあります。 各ハンドラーは複数の関数を呼び出します。 最初に条件があり、ユーザーがゲームのタイプ「X対0」を選択すると、セルだけが値1または2(クロスまたはゼロ)で埋められます。 次の関数は次のとおりです。移動の表示(CrossZero())は、クロスをゼロに、またはその逆に変更し、checkingArray()によって占有セルをブロックし、勝者のwinner()を見つけます。 winer()関数では、考えられるすべての勝ちオプションが考慮されます。したがって、プレーヤーの1人が3つの数字(十字またはゼロ)を縦、横、または斜めに並べると、勝ちます。 それ以外の場合、フィールドがいっぱいで、プレーヤーが誰も並んでいない場合は、関数(_friend())が呼び出されます-ドローをチェックし、フィールドに空きセルがあるかどうかをチェックします。 fr = trueの場合、フィールドに空きセルはありません。 値が変更された場合は、フィールドに空きセルがあります。

2番目の条件は、2番目または3番目のゲームタイプが選択されている場合に機能します。 次に、関数が呼び出され、コンピューターの移動move(int n)が実行されます。 プレイヤーがクリックしたセルの番号を受け取ります。 次の関数は次のとおりです。進行状況の表示(CrossZero())、checkingArray()による占有セルのブロック。 次に、winner()関数が呼び出され、プレーヤーがこの動きに勝ったかどうかを確認します。 そうでない場合は、フリーセルの存在がチェックされます。 空きセルがある場合は、コンピューターが移動します。 さらに、プレーヤー「1」または「2」が選択したレベルに応じて、それぞれ次の関数が呼び出されます:low_level()、dif_level()。 low_level()関数は、ゼロをランダムに配置する場所を選択し、dif_level()関数は、コンピューターが勝つための特別なアルゴリズムを提供します。 次の関数は次のとおりです。進行状況の表示(CrossZero())、checkingArray()による占有セルのブロック。 次に、winner()関数が呼び出され、コンピューターがこの移動に勝ったかどうかがチェックされます。 そうでない場合は、フリーセルの存在がチェックされます。 空きセルがある場合、プレーヤーは移動します。

.2標準の視覚的および非視覚的コンポーネントの選択

この作業を実装するために、次のコンポーネントが選択されました。

1)Form1、指定されたパラメーターText = Tic-Tac-Toe、ControlBox = False

2)f2、BackColorが設定されている場合、Text = Game

)指定されたItemsオプションを使用したcomboBox1:

X対0

コンピューターの第1レベル

コンピューターとの第2レベル

4)パネル、指定されたBackColorパラメーター、およびVisibleパラメーターとEnabledパラメーターの異なる値。 一部のパネルでは、Clickなどのイベントが作成されました。

5)Clickなどのイベントが書き込まれたすべてのボタンに対して、指定されたFont、Fore Color、BackColor、Textパラメーターを持つボタン。

6)指定されたパラメータBackColor、Font、Fore Color、Textを使用したラベル。

)pictureBox、画像パラメータが設定されている、SizeMode = StretchImage。

)textBox、指定されたパラメータBackColor、Font、Fore Color、Text =””。

4.テスト結果

3種類のゲームを試してプログラムをテストしてみましょう。

メインメニューボタンの動作を試してみましょう。 ボタンは正しく機能しています。 ゲームの種類を選択せず​​にゲームを始めてみましょう。 プログラムはエラーメッセージを表示し、ゲームの種類を選択するように求めます(図4.1)。

図4.1。

1種類のゲームを選択しましょう-「X対0」、つまり ユーザー対ユーザー。 ゲームのこの段階では、ユーザーは自分で遊ぶこともできます。 (図4.2)

図4.2。

ゲーム「コンピューターとの1レベル」の間、コンピューターは参加者を獲得するという目標を設定しません。 彼は単にフィールドの自由な場所にゼロを置きます。 この段階で、ユーザーは簡単にコンピューターを打ち負かすことができます。 このレベルではありますが、他のシナリオも可能です。

図4.3。

ゲームの種類「コンピューター付きレベル2」。 この段階で、ゲームはすべての動きを分析し、最適な動きを選択しようとします。 イベントの開発の3つのバリエーションはすべて、ここでも可能です。 コンピュータは最初にフリーセルに移動します。 ほとんどの場合、ゲームは引き分けで終了します。

図4.4。

プログラムは、エラーなしですべてのテストバリアントで正常に実行されます。

結論

作業開始時に設定した作業は完了したと言っても過言ではありません。 開発の過程で、有名なTic-Tac-Toeゲームのリミックスプロジェクトが計画され、開発されました。 ゲームは指定された要件を満たし、その機能を実行します。 さまざまなゲームタイプと難易度が作品に実装されています。

作業の過程で、統合開発環境でのプログラミングの新しい方法が習得されました。 C ++言語での作業に関する古い知識が修正されました。 コースワークの準備として、このゲームを実装するためのさまざまな方法とアルゴリズムが分析されました。

このプログラムは明らかに単純ですが、Visual C ++のすべての基本的な手法を使用して実装される多くの問題があります。

このプログラムの機能は次のとおりです。

明確に構築されたアルゴリズム。

直感的なインターフェース;

使いやすさ;

ユーザーマニュアルを完全にクリアします。

余分なものはありません。

参考文献

1. http://www.pravilaigr.ru/xo.php

2. http://2igroka.com/stuff/sportivnye/krestiki_noliki_3d/15-1-0-14

3. https://www.draw.io/

Http://pol-video.ru/QPW9QHEO2GU/uroki_s_krestiki-noliki_ch1.html

附属書1

private:int low_level()(//低い対戦相手のプロシージャ; :: Random ^ rand = gcnew System :: Random();(= rand-> Next(0,8);

)while(x [r]!= 0); r;

付録2

private:bool check(int n)(k = -1; //すべての組み合わせをチェックし、正しいmove(x == n)(((x == n)&&(x == 0))k = 2;( (x == n)&&(x == 0))k = 1;((x == n)&&(x == 0))k = 6;((x == n)&&(x == 0 ))k = 3;((x == n)&&(x == 0))k = 8;((x == n)&&(x == 0))k = 4;

)(x == n)(((x == n)&&(x == 0))k = 0;((x == n)&&(x == 0))k = 7;((x = = n)&&(x == 0))k = 4;

)(x == n)(((x == n)&&(x == 0))k = 4;((x == n)&&(x == 0))k = 6;((x = = n)&&(x == 0))k = 8;((x == n)&&(x == 0))k = 5;

)(x == n)(((x == n)&&(x == 0))k = 0;((x == n)&&(x == 0))k = 5;((x = = n)&&(x == 0))k = 4;

)(x == n)(((x == n)&&(x == 0))k = 0;((x == n)&&(x == 0))k = 3;((x = = n)&&(x == 0))k = 1;((x == n)&&(x == 0))k = 2;

)(x == n)(((x == n)&&(x == 0))k = 2;

)(x == n)(((x == n)&&(x == 0))k = 8;((x == n)&&(x == 0))k = 7;

)(x == n)(((x == n)&&(x == 0))k = 6;

)(k!=-1)trueを返します;それ以外の場合はfalseを返します;

付録3

プライベート:int dif_level()(//難しい敵

// return check(2);(x == 0)return(4);(check(2))return k; else(check(1))return k; そうでなければlow_level();

付録 4

private:void CrossZero()(//クロスをゼロに変更します(進行状況インジケーター)(プレーヤー)(-> Visible = true;-> Visible = false;

)else(-> Visible = true;-> Visible = false;

):voidcheckingArray()(//セルに何かがあるかどうかをチェックする関数。ある場合は、このセルをクリックできなくなります。> Enabled = false;)(x == 2)(panel1-> BackgroundImage = panel10-> BackgroundImage; panel1-> Enabled = false;)(x == 1)(panel2-> BackgroundImage = panel11-> BackgroundImage; panel2-> Enabled = false;)(x == 2)(panel2-> BackgroundImage = panel10-> BackgroundImage; panel2-> Enabled = false;)(x == 1)(panel3-> BackgroundImage = panel11-> BackgroundImage; panel3-> Enabled = false;)(x == 2)(panel3-> BackgroundImage = panel10-> BackgroundImage; panel3-> Enabled = false;)(x == 1)(panel4-> BackgroundImage = panel11-> BackgroundImage; panel4-> Enabled = false;)(x == 2)(panel4-> BackgroundImage = panel10-> BackgroundImage; panel4-> Enabled = false;)(x == 1)(panel5-> BackgroundImage = panel11-> BackgroundImage; panel5-> Enabled = false;)(x == 2)(panel5-> BackgroundImage = panel10-> BackgroundImage; panel5-> Enabled = false;)(x == 1)(panel6-> B ackgroundImage = panel11-> BackgroundImage; panel6-> Enabled = false;)(x == 2)(panel6-> BackgroundImage = panel10-> BackgroundImage; panel6-> Enabled = false;)(x == 1)(panel7-> BackgroundImage = panel11-> BackgroundImage; panel7-> Enabled = false;)(x == 2)(panel7-> BackgroundImage = panel10-> BackgroundImage; panel7-> Enabled = false;)(x == 1)(panel8-> BackgroundImage = panel11-> BackgroundImage; panel8-> Enabled = false;)(x == 2)(panel8-> BackgroundImage = panel10-> BackgroundImage; panel8-> Enabled = false;)(x == 1)(panel9-> BackgroundImage = panel11-> BackgroundImage; panel9-> Enabled = false;)(x == 2)(panel9-> BackgroundImage = panel10-> BackgroundImage; panel9-> Enabled = false;)

):bool winer()(//勝者を確認し、残りのすべてのセルをブロックします。

//ブールフラグ= false;(((x == x)&&(x == x)&&(x == 2))||((x == x)&&(x == x)&&(x = = 2))||((x == x)&&(x == x)&&(x == 2))||((x == x)&&(x == x)&&(x == 2 ))||((x == x)&&(x == x)&&(x == 2))||((x == x)&&(x == x)&&(x == 2)) ||((x == x)&&(x == x)&&(x == 2))||((x == x)&&(x == x)&&(x == 2)))( (lvl == 1)(picturePo-> Visible = true;)(picturePr-> Visible = true;)-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false; true;

)(((x == x)&&(x == x)&&(x == 1))||((x == x)&&(x == x)&&(x == 1))|| ((x == x)&&(x == x)&&(x == 1))||((x == x)&&(x == x)&&(x == 1))||(( x == x)&&(x == x)&&(x == 1))||((x == x)&&(x == x)&&(x == 1))||((x = = = x)&&(x == x)&&(x == 1))||((x == x)&&(x == x)&&(x == 1)))((lvl == 1 )(picturePx-> Visible = true;)(picturePobeda-> Visible = true;)-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false;- > Enabled = false;-> Enabled = false;-> Enabled = false;-> Enabled = false; true;

):void _friend()(fr = true;(int i = 0; i< 9; i++) if (x[i] == 0) {fr = false; break;}(fr) { pictureN->visible = true;)

):void move(int n)(// computer move function = false; [n] = 1; =!player;();();(winner())()((int i = 0; i< 9; i++) if (x[i] == 0) flag = true;(flag){(lvl == 2) = 2; = 2;= !player;();();();

):System :: Void button1_Click(System :: Object ^ sender、System :: EventArgs ^ e)(// new game> Visible = false;> Visible = false;> Visible = false;> Visible = false;> Visible = false; = comboBox1-> Text;(typeGame == "")(:: Show( "最初にゲームタイプを選択してください!");

)else((typeGame == "X vs 0")lvl = 1;(typeGame == "Computer level 1")lvl = 2;(typeGame == "Computer level 2")lvl = 3;(); = true ;(int i = 0; i< 9; i++) x[i] = 0;->BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> BackgroundImage = panel12-> BackgroundImage;-> Enabled = true;-> Enabled = true;-> Enabled = true;-> Enabled = true;->有効= true;->有効= true;->有効= true;->有効= true;->有効= true;

):System :: Void panel1_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 0;(lvl == 1)((player)(= 1;

)=!player;();();();

):System :: Void panel2_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 1;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel3_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 2;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel4_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 3;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel5_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 4;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel6_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 5;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel7_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 6;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel8_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 7;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void panel9_MouseClick(System :: Object ^ sender、System :: Windows :: Forms :: MouseEventArgs ^ e)(n = 8;(lvl == 1)((player)(= 1;

)=!player;();();();

)else if((lvl == 2)||(lvl == 3))((n);

):System :: Void button2_Click(System :: Object ^ sender、System :: EventArgs ^ e)(();

):System :: Void picturePx_Click(System :: Object ^ sender、System :: EventArgs ^ e)(> Visible = false;

):System :: Void picturePo_Click(System :: Object ^ sender、System :: EventArgs ^ e)(> Visible = false;

):System :: Void picturePobeda_Click(System :: Object ^ sender、System :: EventArgs ^ e)(> Visible = false;

):System :: Void picturePr_Click(System :: Object ^ sender、System :: EventArgs ^ e)(> Visible = false;

):System :: Void pictureN_Click(System :: Object ^ sender、System :: EventArgs ^ e)(> Visible = false;

親愛なる友人の皆さん、こんにちは! このチュートリアルでは、JavaScriptでブラウザゲーム(tic-tac-toe)を作成する方法を紹介します。 あなたは皆、このゲームが何であるか、そしてそれをどのようにプレイするかを知っていますが、もう一度思い出させてください:

Tic-tac-toeは、3 x 3の正方形のフィールド(おそらくそれよりも大きい)上の2人のプレーヤー間の論理ゲームです。 1つは「十字架」で、もう1つは「つま先」で遊んでいます。

P.S. 同様のすべてのJavaScriptチュートリアルと同様に、記事の最後でソースファイルをダウンロードしたり、デモ例での作業の結果を確認したりできます。

作成中のゲームの説明

ゲームの機能を見てみましょう:

  • ページが読み込まれた直後にゲームが開始されます。
  • 最初に移動する権利はランダムに選択されます(歩き始めるか、コンピューターのどちらか)。
  • 配置する記号はランダムに選択されます(クロスまたはゼロ)。
  • プレーヤーが勝った場合、勝ったシンボル(十字またはゼロのストリップ)は緑色で強調表示されます。
  • プレーヤーがコンピューターに負けた場合、バーは赤で強調表示されます。
  • フィールドの上には、結果(勝利または敗北)が表示される情報の行があります。

ロジック

私は3x 3セルの競技場用の複雑な(普遍的な)アルゴリズムを思いつきませんでした、私は逆に行きました-ブルートフォース! (これについては後で詳しく説明します)。 ロジック全体が置かれている3つの主要なシーケンシャルステージを特定しました。

ステージ1:チェック-プレーヤーは勝ちましたか?

この段階で、同じプレーヤーシンボル(クロスまたはゼロ)で満たされた3つのセル(同じ行上)があるかどうかを確認します。 それらの。 この動きが何であれ(最初の動きであっても)、私たちは常にプレイヤーが勝ったかどうかを最初にチェックします。 これは勝利がどのように見えるかです:

ステージ2:チェック-コンピューターは次の動きで勝つことができますか?

この段階で、2つのセルがコンピューターで満たされ、1つの空のセルが存在するラインを探しています。つまり、プレーヤーの不注意のために勝とうとしています。 これは敗北がどのように見えるかです(つまり、コンピューターの勝利):

ステージ3:勝てないで!

ここでは、第2段階と同じ行を探しています。プレーヤーのゲームのサインを入力する必要があるのは、2つのセルだけです。つまり、この段階では、空のセルにサインを置いてコンピューターを失うことはありません。 各ステージは独立した関数です。これは、以下のjsコードで確認できます。

実装

競技場のレイアウトは非常に単純です。メインブロックには情報の行(クラス-結果)とセルである9つのブロック(クラス-ブロック)が含まれています。セルのHTMLマークアップ:

あなたの番!

セルヘルパークラスは、競技場で目的のセルを正確に識別するために必要です。 競技場のCSSスタイル:

Krestiki_noliki(width:306px; margin:0 auto;)。krestiki_noliki .block(width:100px; height:100px; border:1px solid #ccc; cursor:pointer; float:left; text-align:center; font-size: 100px;行の高さ:94px;)

次に、JSコード全体を見てみましょう。その後、要点について説明します。

$(document).ready(function()(var znak_user = "O"; var znak_comp = "X"; var rand_num = Math.round((Math.random()*(9-1)+ 1)); if (rand_num> 3)(var znak_comp = "O"; var znak_user = "X"; $( "。cell" + rand_num).text(znak_comp);)var exit_flag = false; var win_user_array = ["123"、 " 456 "、" 789 "、" 147 "、" 258 "、" 369 "、" 159 "、" 357 "]; //プレーヤーの勝利関数を決定しますcheck_3_user(znak)(for(var i = 0; i< 8; i++) { var first = "cell" + win_user_array[i].substr(0,1); var second = "cell" + win_user_array[i].substr(1,1); var third = "cell" + win_user_array[i].substr(2,1); if($("."+first).text() == znak && $("."+second).text() == znak && $("."+third).text() == znak){ $("."+first+",."+second+",."+third).css("background-color", "#83e2c3"); $(".result").text("Вы выиграли!"); $(".krestiki_noliki .block").unbind("click"); exit_flag = true; } } } //Определяем возможность победы компьютера function check_2_comp(znak){ for (var i = 0; i < 8; i++) { var first = "cell" + win_user_array[i].substr(0,1); var second = "cell" + win_user_array[i].substr(1,1); var third = "cell" + win_user_array[i].substr(2,1); if($("."+first).text() == znak && $("."+second).text() == znak && $("."+third).text() == "" && exit_flag == false){ $("."+third).text(znak); $("."+first+",."+second+",."+third).css("background-color", "#EF7C7C"); $(".result").text("Вы проиграли!"); $(".krestiki_noliki .block").unbind("click"); exit_flag = true; } if($("."+first).text() == znak && $("."+second).text() == "" && $("."+third).text() == znak && exit_flag == false){ $("."+second).text(znak); $("."+first+",."+second+",."+third).css("background-color", "#EF7C7C"); $(".result").text("Вы проиграли!"); $(".krestiki_noliki .block").unbind("click"); exit_flag = true; } if($("."+first).text() == "" && $("."+second).text() == znak && $("."+third).text() == znak && exit_flag == false){ $("."+first).text(znak); $("."+first+",."+second+",."+third).css("background-color", "#EF7C7C"); $(".result").text("Вы проиграли!"); $(".krestiki_noliki .block").unbind("click"); exit_flag = true; } } } //Определяем ход компьютера function check_2_user(znak){ for (var i = 0; i < 8; i++) { var first = "cell" + win_user_array[i].substr(0,1); var second = "cell" + win_user_array[i].substr(1,1); var third = "cell" + win_user_array[i].substr(2,1); if(exit_flag == false){ if($("."+first).text() == znak && $("."+second).text() == znak && $("."+third).text() == ""){ $("."+third).text(znak_comp); exit_flag = true; } } if(exit_flag == false){ if($("."+first).text() == znak && $("."+second).text() == "" && $("."+third).text() == znak){ $("."+second).text(znak_comp); exit_flag = true; } } if($("."+first).text() == "" && $("."+second).text() == znak && $("."+third).text() == znak){ $("."+first).text(znak_comp); exit_flag = true; } if(exit_flag) break; } } $(".krestiki_noliki .block").click(function(){ //Если клетка пустая if($(this).text() == ""){ $(this).text(znak_user); check_3_user(znak_user); check_2_comp(znak_comp); check_2_user(znak_user); if(exit_flag == false){ for (var i = 1; i < 10; i++) { if($(".cell"+i).text() == ""){ $(".cell"+i).text(znak_comp); break; } } }else exit_flag = false; } }); });

まず、変数を宣言します。znak_user-この変数には、ユーザーがプレイする記号を格納します(デフォルトでは、ゼロが格納されます-これは英語のブース「O」です)。 znak_comp-この変数には、コンピューターが再生する記号を格納します(デフォルトでは、そこにクロスが格納されます-これは英語のブース「x」です)。

論理は次のとおりです。乱数が3より大きい場合、コンピューターはゼロで再生し、コンピューター(コンピューター)が最初の動きをします。

このロジックを好みに合わせて変更できます。たとえば、乱数を作成して、誰が少なくとも最初の文字になり、どの文字になるかについてより多くのオプションを作成できます。 exit_flag-このフラグ(変数)は、関数を終了する役割を果たします。たとえば、コンピューターがすでに移動を行っており、関数を終了して移動をプレーヤーに転送する必要がある場合です。 win_user_array-この配列は、セルを埋めるためのすべての勝利オプションを格納します。 明確にするために、この写真を見てみましょう:

配列の各要素は3桁の文字列であり、これは勝利の組み合わせです。たとえば、1、2、3の数字の下のセルに入力すると、勝利(または敗北)が発生します。 ご覧のとおり、合計8つの勝ちオプションがあります。私たちのタスクは、これらすべてのオプションを並べ替えることです。 以下は3つの機能です。

  1. check_3_user();
  2. check_2_comp();
  3. check_2_user();

これらの関数の目的は、ロジックセクション(上記)で(3つのステップで)説明されています。 これらの関数は、フィールドのセルのいずれかをクリックすることで呼び出されます。 パラメータ(znak)は、各関数に渡されます。これは、プレーヤーまたはコンピューターの記号(クロスまたはゼロ)です。たとえば、プレーヤーの勝利を決定する関数(check_3_user)では、記号を渡します。同じ行に3つの同一の標識を見つけるためのプレーヤーの。

3つの機能の後(コンピューターがまだ移動していない場合)、コンピューターは空きセルの1つを埋めます。 ここでは、たとえば、中央のセルが空いている場合(セル番号5)に最初に賭け、占有されている場合は空いているコーナーの1つに賭けるようにすることで、ゲームプレイを複雑にすることができます(これらはセルNo.1、3、7、9)など-一般的に、ここではあなた次第です。

原則として、そのようなゲームを作成するために必要なのはそれだけです。

これで、デモでゲームを視聴し、ソースファイル(1ファイルのみ)をダウンロードできます。

2018年6月8日-手紙の作者に注意を払ってくれてありがとう:Patvakan Baghdasaryan、コンピューターにいくつかの可能な勝利オプションがあり、すべての勝利の動きが塗りつぶされたときのバグが修正されました(3ではなく4から6セルに) )。

これですべてです。このチュートリアルがお役に立てば幸いです。幸運を祈ります。さようなら!

トピックの続き:
インターネット

半導体ダイオードは、新しいキャリア分布がすぐには確立されないため、電流または電圧の十分に速い変化に対して不活性です。 どのように...