Exemple #1
0
 /// <summary>
 /// Returns a singleton MazeDimensions instance.
 /// </summary>
 /// <returns></returns>
 public static MazeDimensions Instance(int version)
 {
     if (instance[version] == null)
     {
         instance[version] = new MazeDimensions(version);
     }
     return(instance[version]);
 }
Exemple #2
0
        /// <summary>
        /// Constructor.
        /// Create a maze whose parameters are encoded in the given code (see property Code).
        /// </summary>
        /// <param name="code">a string of seven letters (case is ignored)</param>
        public Maze(string code)
        {
            int version = MazeCode.GetCodeVersion(code);

            this.dimensionsObj = MazeDimensions.Instance(version);
            this.codeObj       = MazeCode.Instance(version);

            codeObj.Decode(code
                           , out this.seed
                           , out this.xSize, out this.ySize
                           );
            this.random = RandomFactory.CreateRandom(seed);
        }
Exemple #3
0
        /// <summary>
        /// Constructor.
        /// Create a maze with the given dimensions.
        /// </summary>
        /// <param name="xSize"></param>
        /// <param name="ySize"></param>
        /// <param name="version"></param>
        /// <param name="seed"></param>
        internal Maze(int xSize, int ySize, int version, int seed)
        {
            this.dimensionsObj = MazeDimensions.Instance(version);
            this.codeObj       = MazeCode.Instance(version);

            this.xSize = Math.Max(dimensionsObj.MinSize, Math.Min(dimensionsObj.MaxXSize, xSize));
            this.ySize = Math.Max(dimensionsObj.MinSize, Math.Min(dimensionsObj.MaxYSize, ySize));

            // Get an initial random seed and use that to create the Random.
            if (seed < 0)
            {
                Random r = RandomFactory.CreateRandom();
                this.seed = r.Next(codeObj.SeedLimit);
            }
            else
            {
                this.seed = seed;
            }
            this.random = RandomFactory.CreateRandom(this.seed);
        }
Exemple #4
0
        /// <summary>
        /// Extract the Maze parameters from an encoded string.
        /// </summary>
        /// <param name="code"></param>
        /// <param name="seed"></param>
        /// <param name="xSize"></param>
        /// <param name="ySize"></param>
        /// <exception cref="ArgumentOutOfRangeException">decoded parameters are invalid</exception>
        public void Decode(string code
                           , out int seed
                           , out int xSize, out int ySize
                           )
        {
            long           nCode         = 0;
            MazeDimensions dimensionsObj = MazeDimensions.Instance(codeVersion);

            #region Convert the character code (base 26) into a numeric code

            char[] a = code.Replace(this.Separator, "").ToCharArray();

            if (!(a.Length == CodeLength))
            {
                throw new ArgumentOutOfRangeException("code", code,
                                                      "length = " + a.Length + " / Must be " + Description);
            }

            for (int p = 0; p < a.Length; p++)
            {
                int digit = 0;
                digit = CodeDigits.ToString().IndexOf(a[p]);

                if (digit < 0)
                {
                    throw new ArgumentOutOfRangeException("code", code,
                                                          "c = '" + a[p] + "' / Must be " + Description);
                }

                nCode *= CodeDigitRange;
                nCode += digit;
            }

            #endregion

            #region Decode items in the code in reverse order of encoding

            long nCodeOriginal = nCode; // for debugging

            long itemRange;

            itemRange = SeedLimit;
            seed      = (int)(nCode % itemRange);
            nCode    /= itemRange;

            itemRange = dimensionsObj.MaxXSize - dimensionsObj.MinSize + 1;
            xSize     = (int)(nCode % itemRange) + dimensionsObj.MinSize;
            nCode    /= itemRange;

            itemRange = dimensionsObj.MaxYSize - dimensionsObj.MinSize + 1;
            ySize     = (int)(nCode % itemRange) + dimensionsObj.MinSize;
            nCode    /= itemRange;

            if (codeVersion == 0)
            {
                #region Decoding of obsolete Version 0 parameters

                WallPosition direction;
                int          xStart, yStart;
                int          xEnd, yEnd;
                int          d1, d2, c1, c2;

                itemRange = (int)WallPosition.WP_NUM;
                direction = (WallPosition)(nCode % itemRange);
                nCode    /= itemRange;

                itemRange = dimensionsObj.MaxXSize + 1;
                c2        = (int)(nCode % itemRange);
                nCode    /= itemRange;

                itemRange = dimensionsObj.MaxXSize + 1;
                c1        = (int)(nCode % itemRange);
                nCode    /= itemRange;

                itemRange = dimensionsObj.MaxBorderDistance + 1;
                d2        = (int)(nCode % itemRange);
                nCode    /= itemRange;

                itemRange = dimensionsObj.MaxBorderDistance + 1;
                d1        = (int)(nCode % itemRange);
                nCode    /= itemRange;

                switch (direction)
                {
                case WallPosition.WP_E:
                    xStart = d1;
                    xEnd   = xSize - 1 - d2;
                    yStart = c1;
                    yEnd   = c2;
                    break;

                case WallPosition.WP_W:
                    xEnd   = d1;
                    xStart = xSize - 1 - d2;
                    yEnd   = c1;
                    yStart = c2;
                    break;

                case WallPosition.WP_S:
                    yStart = d1;
                    yEnd   = ySize - 1 - d2;
                    xStart = c1;
                    xEnd   = c2;
                    break;

                case WallPosition.WP_N:
                    yEnd   = d1;
                    yStart = ySize - 1 - d2;
                    xEnd   = c1;
                    xStart = c2;
                    break;

                default:
                    xStart = yStart = xEnd = yEnd = -1;
                    break;
                }

                #endregion
            }

            #endregion

            #region Verify the validity of the decoded items

            if (!(nCode == 0))
            {
                throw new ArgumentOutOfRangeException("remainder(code)", nCode, "Must be a zero.");
            }
            ValidateCodeItemRange("seed", seed, 0, SeedLimit - 1);
            ValidateCodeItemRange("xSize", xSize, dimensionsObj.MinSize, dimensionsObj.MaxXSize);
            ValidateCodeItemRange("ySize", ySize, dimensionsObj.MinSize, dimensionsObj.MaxYSize);

            #endregion
        }
Exemple #5
0
        /// <summary>
        /// A string that encodes the maze parameters.
        /// This code can be used to construct an identical maze.
        /// </summary>
        public string Code(Maze maze)
        {
            long           nCode         = 0;
            MazeDimensions dimensionsObj = MazeDimensions.Instance(codeVersion);

            #region Encode the relevant parameters into a numeric code

            // Items are encoded in reverse order of decoding.
            // Some items must be encoded before others if decoding requires them.

            if (codeVersion == 0)
            {
                // Encode the start and end points.
                // Instead of the direct coordinates we will use the following information:
                // * travel direction
                // * distance from the border (instead of coordinate)
                // * other coordinate
                // The scaling factor is always MazeDimensions.MaxXSize, as it is greater than MazeDimensions.MaxYSize.

                int d1, d2, c1, c2;

                switch (maze.Direction)
                {
                case WallPosition.WP_E:
                    d1 = maze.StartSquare.XPos;
                    d2 = maze.XSize - 1 - maze.EndSquare.XPos;
                    c1 = maze.StartSquare.YPos;
                    c2 = maze.EndSquare.YPos;
                    break;

                case WallPosition.WP_W:
                    d1 = maze.EndSquare.XPos;
                    d2 = maze.XSize - 1 - maze.StartSquare.XPos;
                    c1 = maze.EndSquare.YPos;
                    c2 = maze.StartSquare.YPos;
                    break;

                case WallPosition.WP_S:
                    d1 = maze.StartSquare.YPos;
                    d2 = maze.YSize - 1 - maze.EndSquare.YPos;
                    c1 = maze.StartSquare.XPos;
                    c2 = maze.EndSquare.XPos;
                    break;

                case WallPosition.WP_N:
                    d1 = maze.EndSquare.YPos;
                    d2 = maze.YSize - 1 - maze.StartSquare.YPos;
                    c1 = maze.EndSquare.XPos;
                    c2 = maze.StartSquare.XPos;
                    break;

                default:
                    d1 = d2 = c1 = c2 = -1;
                    break;
                }

                nCode *= (dimensionsObj.MaxBorderDistance + 1);
                nCode += d1;

                nCode *= (dimensionsObj.MaxBorderDistance + 1);
                nCode += d2;

                nCode *= (dimensionsObj.MaxXSize + 1);
                nCode += c1;

                nCode *= (dimensionsObj.MaxXSize + 1);
                nCode += c2;

                nCode *= (int)WallPosition.WP_NUM;
                nCode += (int)maze.Direction;
            }

            // Encode maze dimension.

            nCode *= (dimensionsObj.MaxYSize - dimensionsObj.MinSize + 1);
            nCode += (maze.YSize - dimensionsObj.MinSize);

            nCode *= (dimensionsObj.MaxXSize - dimensionsObj.MinSize + 1);
            nCode += (maze.XSize - dimensionsObj.MinSize);

            // Encode initial seed.

            nCode *= SeedLimit;
            nCode += maze.Seed;

            #endregion

            // v0: The resulting nCode is less than 26^12.  See SWA.Ariadne.Model.Tests unit tests.
            // v1: The resulting nCode is less than 36^6.  See SWA.Ariadne.Model.Tests unit tests.

            #region Convert the numeric code into a character code (base 26)

            StringBuilder result = new StringBuilder(7);

            for (int p = CodeLength; p-- > 0;)
            {
                int digit = (int)(nCode % CodeDigitRange);
                nCode /= CodeDigitRange;
                char c = CodeDigits[digit];
                result.Insert(0, c);
            }

            switch (codeVersion)
            {
            case 0:
                result.Insert(8, this.Separator);
                result.Insert(4, this.Separator);
                break;

            case 1:
                result.Insert(3, this.Separator);
                break;

            case 2:
                result.Insert(3, this.Separator);
                break;
            }

            #endregion

            return(result.ToString());
        }