IEnumerable <int> InvalidMoveIndices() { var numValidMoves = m_Board.NumMoves(); foreach (var move in m_Board.InvalidMoves()) { numValidMoves--; if (numValidMoves == 0) { // If all the moves are invalid and we mask all the actions out, this will cause an assert // later on in IDiscreteActionMask. Instead, fire a callback to the user if they provided one, // (or log a warning if not) and leave the last action unmasked. This isn't great, but // an invalid move should be easier to handle than an exception.. if (m_Board.OnNoValidMovesAction != null) { m_Board.OnNoValidMovesAction(); } else { Debug.LogWarning( "No valid moves are available. The last action will be left unmasked, so " + "an invalid move will be passed to AbstractBoard.MakeMove()." ); } // This means the last move won't be returned as an invalid index. yield break; } yield return(move.MoveIndex); } }
/// <inheritdoc/> public void WriteDiscreteActionMask(IDiscreteActionMask actionMask) { var currentBoardSize = m_Board.GetCurrentBoardSize(); m_Board.CheckBoardSizes(m_MaxBoardSize); const int branch = 0; bool foundValidMove = false; using (TimerStack.Instance.Scoped("WriteDiscreteActionMask")) { var numMoves = m_Board.NumMoves(); var currentMove = Move.FromMoveIndex(0, m_MaxBoardSize); for (var i = 0; i < numMoves; i++) { // Check that the move is allowed for the current boardSize (e.g. it won't move a piece out of // bounds), and that it's allowed by the game itself. if (currentMove.InRangeForBoard(currentBoardSize) && m_Board.IsMoveValid(currentMove)) { foundValidMove = true; } else { actionMask.SetActionEnabled(branch, i, false); } currentMove.Next(m_MaxBoardSize); } if (!foundValidMove) { // If all the moves are invalid and we mask all the actions out, this will cause an assert // later on in IDiscreteActionMask. Instead, fire a callback to the user if they provided one, // (or log a warning if not) and leave the last action unmasked. This isn't great, but // an invalid move should be easier to handle than an exception.. if (m_Board.OnNoValidMovesAction != null) { m_Board.OnNoValidMovesAction(); } else { Debug.LogWarning( "No valid moves are available. The last action will be left unmasked, so " + "an invalid move will be passed to AbstractBoard.MakeMove()." ); } actionMask.SetActionEnabled(branch, numMoves - 1, true); } } }
/// <inheritdoc/> public void WriteDiscreteActionMask(IDiscreteActionMask actionMask) { const int branch = 0; bool foundValidMove = false; using (TimerStack.Instance.Scoped("WriteDiscreteActionMask")) { var numMoves = m_Board.NumMoves(); var currentMove = Move.FromMoveIndex(0, m_Board.Rows, m_Board.Columns); for (var i = 0; i < numMoves; i++) { if (m_Board.IsMoveValid(currentMove)) { foundValidMove = true; } else { actionMask.SetActionEnabled(branch, i, false); } currentMove.Next(m_Board.Rows, m_Board.Columns); } if (!foundValidMove) { // If all the moves are invalid and we mask all the actions out, this will cause an assert // later on in IDiscreteActionMask. Instead, fire a callback to the user if they provided one, // (or log a warning if not) and leave the last action unmasked. This isn't great, but // an invalid move should be easier to handle than an exception.. if (m_Board.OnNoValidMovesAction != null) { m_Board.OnNoValidMovesAction(); } else { Debug.LogWarning( "No valid moves are available. The last action will be left unmasked, so " + "an invalid move will be passed to AbstractBoard.MakeMove()." ); } actionMask.SetActionEnabled(branch, numMoves - 1, true); } } }