Ejemplo n.º 1
0
        [InlineData(1, "X", "A -> 'AB'", "X")] // implicit identity rule if no rule is found for a given symbol
        public void GenerateReturnsCorrectStateForGeneration(int n, string axiom, string rules, string expected)
        {
            var r   = ParseRules(rules);
            var gen = new DeterministicStringGenerator(r);

            Assert.Equal(expected, gen.Generate(axiom, n));
        }
Ejemplo n.º 2
0
        public void CanAddProductions()
        {
            var gen = new DeterministicStringGenerator();

            gen.AddProduction('A', "AB");
            Assert.Equal("AB", gen.Generate("A", 1));
        }
Ejemplo n.º 3
0
        private static string RunFractal(int width, int height, string name, int generation)
        {
            var ctx = new SvgContext(width, height);

            double initialX;
            double initialY;
            int    stepSize;
            double initialAngle;
            double turnAngle;

            string initialState;
            var    lsys = new DeterministicStringGenerator();

            switch (name)
            {
            case "koch-curve":
                initialX     = 0;
                initialY     = height / 2D;
                stepSize     = 8;
                initialAngle = 0;
                turnAngle    = 60;
                lsys.AddProduction('F', "F+F--F+F");
                initialState = "F";
                break;

            case "koch-curve-right":
                initialX     = 0;
                initialY     = height / 2D;
                stepSize     = 8;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('F', "F+F-F-F+F");
                initialState = "F";
                break;

            case "sierpinski-arrow":
                initialX     = 0;
                initialY     = height;
                stepSize     = 2;
                initialAngle = 0;
                turnAngle    = 60;
                lsys.AddProduction('F', "G-F-G");
                lsys.AddProduction('G', "F+G+F");
                initialState = "F";
                break;

            case "sierpinski-tri":
                initialX     = width / 2D;
                initialY     = height / 4D;
                stepSize     = 6;
                initialAngle = 0;
                turnAngle    = 60;
                lsys.AddProduction('F', "FF");
                lsys.AddProduction('X', "--FXF++FXF++FXF--");
                initialState = "FXF--FF--FF";
                break;

            case "plant1":
                initialX     = width / 2D;
                initialY     = height;
                stepSize     = 7;
                initialAngle = 75;
                turnAngle    = 22.5;
                lsys.AddProduction('0', "F-[[0]+0]+F[+F0]-0");
                lsys.AddProduction('F', "FF");
                initialState = "0";
                break;

            case "plant2":
                initialX     = width / 2D;
                initialY     = height;
                stepSize     = 10;
                initialAngle = 80;
                turnAngle    = 22.5;
                lsys.AddProduction('F', "FF-[-F+F+F]+[+F-F-F]");
                initialState = "F";
                break;

            case "dragon-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 4;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('X', "X+YF+");
                lsys.AddProduction('Y', "-FX-Y");
                initialState = "FX";
                break;

            case "hex-gosper-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 6;
                initialAngle = 60;
                turnAngle    = 60;
                lsys.AddProduction('F', "F-G--G+F++FF+G-");
                lsys.AddProduction('G', "+F-GG--G-F++F+G");
                initialState = "F";
                break;

            case "peano-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 4;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('F', "F+F-F-F-F+F+F+F-F");
                initialState = "F";
                break;

            case "quad-koch-island":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 3;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('F', "F-F+F+FFF-F-F+F");
                initialState = "F+F+F+F";
                break;

            case "32-segment-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 2;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('F', "-F+F-F-F+F+FF-F+F+FF+F-F-FF+FF-FF+F+F-FF-F-F+FF-F-F+F+F-F+");
                initialState = "F+F+F+F";
                break;

            case "sierpinski-arrow-alt":
                initialX     = width / 4D;
                initialY     = height;
                stepSize     = 2;
                initialAngle = 0;
                turnAngle    = 60;
                lsys.AddProduction('X', "YF+XF+Y");
                lsys.AddProduction('Y', "XF-YF-X");
                initialState = "YF";
                break;

            case "peano-gosper-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 4;
                initialAngle = 0;
                turnAngle    = 60;
                lsys.AddProduction('X', "X+YF++YF-FX--FXFX-YF+");
                lsys.AddProduction('Y', "-FX+YFYF++YF+FX--FX-Y");
                initialState = "FX";
                break;

            case "square-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 4;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('X', "XF-F+F-XF+F+XF-F+F-X");
                initialState = "F+XF+F+XF";
                break;

            case "hilbert-curve":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 6;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('L', "+RF-LFL-FR+");
                lsys.AddProduction('R', "-LF+RFR+FL-");
                initialState = "L";
                break;

            case "hilbert-curve-2":
                initialX     = width / 2D;
                initialY     = height / 2D;
                stepSize     = 4;
                initialAngle = 0;
                turnAngle    = 90;
                lsys.AddProduction('X', "XFYFX+F+YFXFY-F-XFYFX");
                lsys.AddProduction('Y', "YFXFY-F-XFYFX+F+YFXFY");
                initialState = "X";
                break;

            default:
                var fileName = $"{name}.lsys";
                var files    = Directory.GetFiles(Directory.GetCurrentDirectory());
                if (files.All(s => Path.GetFileName(s) != fileName))
                {
                    throw new ArgumentException($"Unknown fractal name: '{name}'");
                }

                var file   = File.OpenText(fileName);
                var parsed = new FractalDefinitionParser().Parse(file);
                initialX     = parsed.StartX;
                initialY     = parsed.StartY;
                stepSize     = parsed.StepSize;
                initialAngle = parsed.StartAngle;
                turnAngle    = parsed.TurnAngle;
                initialState = parsed.Axiom;
                foreach (var kvp in parsed.Rules)
                {
                    lsys.AddProduction(kvp.Key, kvp.Value);
                }
                break;
            }

            var turtle = new Turtle(ctx, stepSize, initialX, initialY, initialAngle);

            var interpreter = new TurtleStringInterpreter(turtle);

            interpreter.AddAction('F', t => t.Forward()).AddAction('G', t => t.Forward());
            interpreter.AddAction('f', t => t.Move()).AddAction('g', t => t.Move());
            interpreter.AddAction('-', t => t.TurnRight(turnAngle));
            interpreter.AddAction('+', t => t.TurnLeft(turnAngle));
            interpreter.AddAction('[', t => t.PushState());
            interpreter.AddAction(']', t => t.PopState());

            var derivation = lsys.Generate(initialState, generation);

            interpreter.Run(derivation);

            return(ctx.ToString());
        }