/// <summary>
 /// action direction :
 /// -----------------------------------------------------
 /// *    0  |  1  |  2
 /// * -----------------------
 /// *    7  |  X  |  3
 /// * -----------------------
 /// *    6  |  5  |  4
 /// </summary>
 /// <param name="action"></param>
 /// <returns></returns>
 public (double[] state, double reward) Step(double[] action)
 {
     if (action == null)
     {
         var(_c_x, _c_y, _c_action) = (_current_x, _current_y, _current_action);
         (_current_x, _current_y, _current_action) = RandomAccessMemory();
         double[] raw = _pRasterLayerCursorTool.PickRagneNormalValue(_c_x, _c_y, _maskx, _masky);
         return(raw, 0);
     }
     else
     {
         double reward = NP.Equal(action, _current_action) ? 1.0 : -1.0;
         (_current_x, _current_y, _current_action) = RandomAccessMemory();
         double[] raw = _pRasterLayerCursorTool.PickRagneNormalValue(_current_x, _current_y, _maskx, _masky);
         return(raw, reward);
     }
 }
        /// <summary>
        /// -----------------------------------------------------
        /// *    0  |  1  |  2
        /// * -----------------------
        /// *    7  |  8  |  3
        /// * -----------------------
        /// *    6  |  5  |  4
        /// </summary>
        /// <returns></returns>
        private (int x, int y, double[] actions) RandomAccessMemory()
        {
            //
            int   rawValueIndex = NP.Random(_randomSeedKeys);
            Point pt            = _memory[rawValueIndex].RandomTake();

            //
            double[] actions = new double[ActionNum];
            //快速搜索x++方向点
            List <Point> points = new List <Point>()
            {
                new Point(pt.X - 1, pt.Y - 1), //(-1,-1)
                new Point(pt.X, pt.Y - 1),     //(0,-1)
                new Point(pt.X + 1, pt.Y - 1), //(1,-1)
                new Point(pt.X + 1, pt.Y),     //(1,0)
                new Point(pt.X + 1, pt.Y + 1), //(1,1)
                new Point(pt.X, pt.Y + 1),     //(0,1)
                new Point(pt.X - 1, pt.Y + 1), //(-1,1)
                new Point(pt.X - 1, pt.Y),     //(-1,0)
            };

            //search next point
            for (int pointIndex = 0; pointIndex < ActionNum; pointIndex++)
            {
                Point p = points[pointIndex];
                //if reach to the end, use original point
                if (p.X >= _limit_x || p.X < 0 || p.Y >= _limit_y || p.Y < 0)
                {
                    continue;
                }
                //store right action(one-hot)
                if (_queryTable[p.X, p.Y] == rawValueIndex)
                {
                    actions.CombineOneHot(NP.ToOneHot(pointIndex, ActionNum));
                }
            }
            //
            if (!_existActions.Exists(p => NP.Equal(p, actions)))
            {
                _existActions.Add(actions);
            }
            //
            return(pt.X, pt.Y, actions);
        }