Unity2Dで「三目並べ(まるばつゲーム)」を作成。Part3では自動でランダムにマークするAIを実装していきます。
はじめに
part1は下記から。
今回やる事
Part1ではUIとマークを付けるのを作成、Part2で交互にマークをセット、勝利判定を実装しました、Part3ではランダムなAIの実装をしていきます。(ランダムにマークするのでAIとは言えないですが、「自動でマークする相手」を分かりやすいようにAIとしています)
実装開始
はじめに、勝利した後もゲームが続くので勝利した場合はマークできないようにしてから、ランダムにマークするAIを実装します。
スクリプトの作成
下記は「ゲーム終了フラグ」と「マーク数をカウント」する部分です。スクリプトに追加しておきます。
private bool isGameFinished; private int marksCount; public void OnButtonClick(Button btn) { if (isGameFinished == true) return; marksCount++; if (IsWinner(img.sprite)) { Debug.Log(isPlayer ? "X Win" : "O Win"); isGameFinished = true; } if (marksCount == 9) { Debug.Log("Draw"); isGameFinished = true; return; } }
ランダムにマークする
次にランダムにマークするのを実装します。下記スクリプトがランダムにマークする部分のスクリプトです。Nomarksにマークされていない場所を格納して、空き場所をランダムに選択してマークします。
private List<int> Nomarks = new List<int>(); private void RandomChoice() { Nomarks.Clear(); for (int i = 0; i < buttons.Length; i++) { if (buttons[i].interactable == true) Nomarks.Add(i); } int RandomIndex = Nomarks[Random.Range(0, Nomarks.Count)]; Button button = buttons[RandomIndex]; OnButtonClick(button); }
最終的な全体のスクリプトは下記になります。
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class GameManager : MonoBehaviour { [SerializeField] private Sprite spriteX; [SerializeField] private Sprite spriteO; [SerializeField] private Color colorX; [SerializeField] private Color colorO; [SerializeField] private Button[] buttons; [SerializeField] private bool isAImode; [SerializeField] private bool isAIplayer; private bool isPlayer; private bool isGameFinished; private int marksCount; private List<int> Nomarks = new List<int>(); private void Awake() { isPlayer = true; isGameFinished = false; marksCount = 0; } private void Start() { if (isAImode && IsAIplay()) RandomChoice(); } public void OnButtonClick(Button btn) { if (isGameFinished == true) return; Image img = btn.GetComponent<Image>(); img.sprite = isPlayer ? spriteX : spriteO; img.color = isPlayer ? colorX : colorO; btn.interactable = false; marksCount++; if (IsWinner(img.sprite)) { Debug.Log(isPlayer ? "X Win" : "O Win"); isGameFinished = true; } if (marksCount == 9) { Debug.Log("Draw"); isGameFinished = true; return; } isPlayer = !isPlayer; if (isAImode && IsAIplay()) RandomChoice(); } private bool IsAIplay() { return (isPlayer && isAIplayer) || (!isPlayer && !isAIplayer); } private void RandomChoice() { Nomarks.Clear(); for (int i = 0; i < buttons.Length; i++) { if (buttons[i].interactable == true) Nomarks.Add(i); } int RandomIndex = Nomarks[Random.Range(0, Nomarks.Count)]; Button button = buttons[RandomIndex]; OnButtonClick(button); } private bool IsWinner(Sprite sprite) { if (IsMatched(0, 1, 2, sprite) || IsMatched(3, 4, 5, sprite) || IsMatched(6, 7, 8, sprite) || IsMatched(0, 3, 6, sprite) || IsMatched(1, 4, 7, sprite) || IsMatched(2, 5, 8, sprite) || IsMatched(0, 4, 8, sprite) || IsMatched(6, 4, 2, sprite)) { return true; } return false; } private bool IsMatched(int i, int j, int k, Sprite sprite) { Image img1 = buttons[i].GetComponent<Image>(); Image img2 = buttons[j].GetComponent<Image>(); Image img3 = buttons[k].GetComponent<Image>(); bool matched = (img1.sprite == sprite && img2.sprite == sprite && img3.sprite == sprite); return matched; } }
「isAImode」にチェックを入れるとランダムにマークするモードになります。isAIplayerで先手か、後手かをセットできます。下記のようにセットすると自分が先手、AIが後手です。
実行すると下記のような感じになります。
ランダムにマークするので、一人対戦モードの相手が弱いという感じですね。