Beispiel #1
0
        /// <summary>
        /// Construct a Move from its move index and the board size.
        /// This is useful for iterating through all the Moves on a board, or constructing
        /// the Move corresponding to an Agent decision.
        /// </summary>
        /// <param name="moveIndex">Must be between 0 and NumPotentialMoves(maxRows, maxCols).</param>
        /// <param name="maxBoardSize"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static Move FromMoveIndex(int moveIndex, BoardSize maxBoardSize)
        {
            var maxRows = maxBoardSize.Rows;
            var maxCols = maxBoardSize.Columns;

            if (moveIndex < 0 || moveIndex >= NumPotentialMoves(maxBoardSize))
            {
                throw new ArgumentOutOfRangeException("Invalid move index.");
            }
            Direction dir;
            int       row, col;

            if (moveIndex < (maxCols - 1) * maxRows)
            {
                dir = Direction.Right;
                col = moveIndex % (maxCols - 1);
                row = moveIndex / (maxCols - 1);
            }
            else
            {
                dir = Direction.Up;
                var offset = moveIndex - (maxCols - 1) * maxRows;
                col = offset % maxCols;
                row = offset / maxCols;
            }
            return(new Move
            {
                MoveIndex = moveIndex,
                Direction = dir,
                Row = row,
                Column = col
            });
        }
Beispiel #2
0
        /// <summary>
        /// Increment the Move to the next MoveIndex, and update the Row, Column, and Direction accordingly.
        /// </summary>
        /// <param name="maxBoardSize"></param>
        public void Next(BoardSize maxBoardSize)
        {
            var maxRows = maxBoardSize.Rows;
            var maxCols = maxBoardSize.Columns;

            var switchoverIndex = (maxCols - 1) * maxRows;

            MoveIndex++;
            if (MoveIndex < switchoverIndex)
            {
                Column++;
                if (Column == maxCols - 1)
                {
                    Row++;
                    Column = 0;
                }
            }
            else if (MoveIndex == switchoverIndex)
            {
                // switch from moving right to moving up
                Row       = 0;
                Column    = 0;
                Direction = Direction.Up;
            }
            else
            {
                Column++;
                if (Column == maxCols)
                {
                    Row++;
                    Column = 0;
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Check if the move is valid for the given board size.
        /// This will be passed the return value from AbstractBoard.GetCurrentBoardSize().
        /// </summary>
        /// <param name="boardSize"></param>
        /// <returns></returns>
        public bool InRangeForBoard(BoardSize boardSize)
        {
            var(otherRow, otherCol) = OtherCell();
            // Get the maximum row and column this move would affect.
            var maxMoveRow = Mathf.Max(Row, otherRow);
            var maxMoveCol = Mathf.Max(Column, otherCol);

            return(maxMoveRow < boardSize.Rows && maxMoveCol < boardSize.Columns);
        }
Beispiel #4
0
        /// <summary>
        /// Construct a Move from the row, column, and direction.
        /// </summary>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <param name="dir"></param>
        /// <param name="maxBoardSize"></param>
        /// <returns></returns>
        public static Move FromPositionAndDirection(int row, int col, Direction dir, BoardSize maxBoardSize)
        {
            // Check for out-of-bounds
            if (row < 0 || row >= maxBoardSize.Rows)
            {
                throw new IndexOutOfRangeException($"row was {row}, but must be between 0 and {maxBoardSize.Rows - 1}.");
            }

            if (col < 0 || col >= maxBoardSize.Columns)
            {
                throw new IndexOutOfRangeException($"col was {col}, but must be between 0 and {maxBoardSize.Columns - 1}.");
            }

            // Check moves that would go out of bounds e.g. col == 0 and dir == Left
            if (
                row == 0 && dir == Direction.Down ||
                row == maxBoardSize.Rows - 1 && dir == Direction.Up ||
                col == 0 && dir == Direction.Left ||
                col == maxBoardSize.Columns - 1 && dir == Direction.Right
                )
            {
                throw new IndexOutOfRangeException($"Cannot move cell at row={row} col={col} in Direction={dir}");
            }

            // Normalize - only consider Right and Up
            if (dir == Direction.Left)
            {
                dir = Direction.Right;
                col = col - 1;
            }
            else if (dir == Direction.Down)
            {
                dir = Direction.Up;
                row = row - 1;
            }

            int moveIndex;

            if (dir == Direction.Right)
            {
                moveIndex = col + row * (maxBoardSize.Columns - 1);
            }
            else
            {
                var offset = (maxBoardSize.Columns - 1) * maxBoardSize.Rows;
                moveIndex = offset + col + row * maxBoardSize.Columns;
            }

            return(new Move
            {
                Row = row,
                Column = col,
                Direction = dir,
                MoveIndex = moveIndex,
            });
        }
Beispiel #5
0
        internal void CheckBoardSizes(BoardSize originalMaxBoardSize)
        {
            var currentBoardSize = GetCurrentBoardSize();

            if (!(currentBoardSize <= originalMaxBoardSize))
            {
                Debug.LogWarning(
                    "Current BoardSize is larger than maximum board size was on initialization. This may cause unexpected results.\n" +
                    $"Original GetMaxBoardSize() result: {originalMaxBoardSize}\n" +
                    $"GetCurrentBoardSize() result: {currentBoardSize}"
                    );
            }
        }
Beispiel #6
0
        /// <summary>
        /// Create a sensor for the GridValueProvider with the specified observation type.
        /// </summary>
        /// <remarks>
        /// Use Match3Sensor.CellTypeSensor() or Match3Sensor.SpecialTypeSensor() instead of calling
        /// the constructor directly.
        /// </remarks>
        /// <param name="board">The abstract board.</param>
        /// <param name="gvp">The GridValueProvider, should be either board.GetCellType or board.GetSpecialType.</param>
        /// <param name="oneHotSize">The number of possible values that the GridValueProvider can return.</param>
        /// <param name="obsType">Whether to produce vector or visual observations</param>
        /// <param name="name">Name of the sensor.</param>
        public Match3Sensor(AbstractBoard board, GridValueProvider gvp, int oneHotSize, Match3ObservationType obsType, string name)
        {
            var maxBoardSize = board.GetMaxBoardSize();

            m_Name         = name;
            m_MaxBoardSize = maxBoardSize;
            m_GridValues   = gvp;
            m_OneHotSize   = oneHotSize;
            m_Board        = board;

            m_ObservationType = obsType;
            m_ObservationSpec = obsType == Match3ObservationType.Vector
                ? ObservationSpec.Vector(maxBoardSize.Rows * maxBoardSize.Columns * oneHotSize)
                : ObservationSpec.Visual(maxBoardSize.Rows, maxBoardSize.Columns, oneHotSize);
        }
Beispiel #7
0
        /// <summary>
        /// Create a Match3Actuator.
        /// </summary>
        /// <param name="board"></param>
        /// <param name="forceHeuristic">Whether the inference action should be ignored and the Agent's Heuristic
        /// should be called. This should only be used for generating comparison stats of the Heuristic.</param>
        /// <param name="seed">The seed used to initialize <see cref="System.Random"/>.</param>
        /// <param name="agent"></param>
        /// <param name="name"></param>
        public Match3Actuator(AbstractBoard board,
                              bool forceHeuristic,
                              int seed,
                              string name)
        {
            m_Board        = board;
            m_MaxBoardSize = m_Board.GetMaxBoardSize();
            Name           = name;

            m_ForceHeuristic = forceHeuristic;

            var numMoves = Move.NumPotentialMoves(m_MaxBoardSize);

            m_ActionSpec = ActionSpec.MakeDiscrete(numMoves);
            m_Random     = new System.Random(seed);
        }
Beispiel #8
0
 /// <summary>
 /// Return the number of potential moves for a board of the given size.
 /// This is equivalent to the number of internal edges in the board.
 /// </summary>
 /// <param name="maxBoardSize"></param>
 /// <returns></returns>
 public static int NumPotentialMoves(BoardSize maxBoardSize)
 {
     return(maxBoardSize.Rows * (maxBoardSize.Columns - 1) + (maxBoardSize.Rows - 1) * (maxBoardSize.Columns));
 }