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が後手です。

実行すると下記のような感じになります。

ランダムにマークするので、一人対戦モードの相手が弱いという感じですね。
