| using System; |
| using UnityEngine; |
| using Unity.MLAgents; |
|
|
| namespace Unity.MLAgentsExamples |
| { |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| enum State |
| { |
| |
| |
| |
| Invalid = -1, |
|
|
| |
| |
| |
| FindMatches = 0, |
|
|
| |
| |
| |
| ClearMatched = 1, |
|
|
| |
| |
| |
| Drop = 2, |
|
|
| |
| |
| |
| FillEmpty = 3, |
|
|
| |
| |
| |
| WaitForMove = 4, |
| } |
|
|
| public class Match3Agent : Agent |
| { |
| [HideInInspector] |
| public Match3Board Board; |
|
|
| public float MoveTime = 1.0f; |
| public int MaxMoves = 500; |
|
|
|
|
| State m_CurrentState = State.WaitForMove; |
| float m_TimeUntilMove; |
| private int m_MovesMade; |
| private ModelOverrider m_ModelOverrider; |
|
|
| private const float k_RewardMultiplier = 0.01f; |
| protected override void Awake() |
| { |
| base.Awake(); |
| Board = GetComponent<Match3Board>(); |
| m_ModelOverrider = GetComponent<ModelOverrider>(); |
| } |
|
|
| public override void OnEpisodeBegin() |
| { |
| base.OnEpisodeBegin(); |
|
|
| Board.UpdateCurrentBoardSize(); |
| Board.InitSettled(); |
| m_CurrentState = State.FindMatches; |
| m_TimeUntilMove = MoveTime; |
| m_MovesMade = 0; |
| } |
|
|
| private void FixedUpdate() |
| { |
| |
| var useFast = Academy.Instance.IsCommunicatorOn || (m_ModelOverrider != null && m_ModelOverrider.HasOverrides); |
| if (useFast) |
| { |
| FastUpdate(); |
| } |
| else |
| { |
| AnimatedUpdate(); |
| } |
|
|
| |
| |
| |
| if (m_MovesMade >= MaxMoves) |
| { |
| EpisodeInterrupted(); |
| } |
| } |
|
|
| void FastUpdate() |
| { |
| while (true) |
| { |
| var hasMatched = Board.MarkMatchedCells(); |
| if (!hasMatched) |
| { |
| break; |
| } |
| var pointsEarned = Board.ClearMatchedCells(); |
| AddReward(k_RewardMultiplier * pointsEarned); |
| Board.DropCells(); |
| Board.FillFromAbove(); |
| } |
|
|
| while (!HasValidMoves()) |
| { |
| |
| Board.InitSettled(); |
| } |
| RequestDecision(); |
| m_MovesMade++; |
| } |
|
|
| void AnimatedUpdate() |
| { |
| m_TimeUntilMove -= Time.deltaTime; |
| if (m_TimeUntilMove > 0.0f) |
| { |
| return; |
| } |
|
|
| m_TimeUntilMove = MoveTime; |
|
|
| State nextState; |
| switch (m_CurrentState) |
| { |
| case State.FindMatches: |
| var hasMatched = Board.MarkMatchedCells(); |
| nextState = hasMatched ? State.ClearMatched : State.WaitForMove; |
| if (nextState == State.WaitForMove) |
| { |
| m_MovesMade++; |
| } |
| break; |
| case State.ClearMatched: |
| var pointsEarned = Board.ClearMatchedCells(); |
| AddReward(k_RewardMultiplier * pointsEarned); |
| nextState = State.Drop; |
| break; |
| case State.Drop: |
| Board.DropCells(); |
| nextState = State.FillEmpty; |
| break; |
| case State.FillEmpty: |
| Board.FillFromAbove(); |
| nextState = State.FindMatches; |
| break; |
| case State.WaitForMove: |
| while (true) |
| { |
| |
| bool hasMoves = HasValidMoves(); |
| if (hasMoves) |
| { |
| break; |
| } |
| Board.InitSettled(); |
| } |
| RequestDecision(); |
|
|
| nextState = State.FindMatches; |
| break; |
| default: |
| throw new ArgumentOutOfRangeException(); |
| } |
|
|
| m_CurrentState = nextState; |
| } |
|
|
| bool HasValidMoves() |
| { |
| foreach (var unused in Board.ValidMoves()) |
| { |
| return true; |
| } |
|
|
| return false; |
| } |
|
|
| } |
|
|
| } |
|
|