1 module rip.draw.lsystem;
2 
3 private
4 {
5 	import std.math;
6 	import std.string;
7 
8 	import rip.concepts;
9 	import rip.draw.turtle;
10 }
11 
12 // Правила переписывания
13 alias RewritingRules = string[string];
14 
15 // параметры L-системы
16 class LSystemParameters
17 {
18 	private
19 	{
20 		float x;
21 		float y;
22 		float stepIncrement;
23 		float angleIncrement;
24 		ulong numberOfGeneration;
25 	}
26 
27 	this(S, T, U, V, W)(S x, T y, U stepIncrement, V angleIncrement, W numberOfGeneration)
28 		if (allArithmetic!(S, T, U, V, W))
29 	{
30 		this.x = cast(float) x;
31 		this.y = cast(float) y;
32 		this.stepIncrement = cast(float) stepIncrement;
33 		this.angleIncrement = cast(float) angleIncrement;
34 		this.numberOfGeneration = cast(uint) abs(numberOfGeneration);
35 	}
36 
37 	
38 	mixin(addTypedGetter!("x", "getX"));
39 	mixin(addTypedGetter!("y", "getY"));
40 	mixin(addTypedGetter!("stepIncrement", "getStep"));
41 	mixin(addTypedGetter!("angleIncrement", "getAngle"));
42 	mixin(addTypedGetter!("numberOfGeneration", "getGeneration"));
43 
44 	
45 
46 	void setX(T)(T x)
47 		if (allArithmetic!T)
48 	{
49 		this.x = cast(float) x;
50 	}
51 	
52 	void setY(T)(T y)
53 		if (allArithmetic!T)
54 	{
55 		this.y = cast(float) y;
56 	}
57 
58 	void setStep(T)(T angle)
59 		if (allArithmetic!T)
60 	{
61 		this.stepIncrement = cast(float) stepIncrement;
62 	}
63 
64 	void setAngle(T)(T angle)
65 		if (allArithmetic!T)
66 	{
67 		this.angleIncrement = cast(float) angleIncrement;
68 	}
69 
70 	void setGeneration(T)(T angle)
71 		if (allArithmetic!T)
72 	{
73 		this.numberOfGeneration = cast(uint) numberOfGeneration;
74 	}
75 }
76 
77 class LSystem
78 {
79 	private
80 	{
81 		Surface surface;
82 		RGBColor color;
83 
84 		LSystemParameters parameters;
85 		RewritingRules rules;
86 		string axiom;
87 
88 		// процедура переписывания строки
89 		string rewrite(string sourceTerm, string termForRewrite, string newTerm)
90 		{
91 			auto acc = "";
92 			auto search = 0;
93 
94 			for (uint i = 0; i < sourceTerm.length; i++)
95 			{
96 				auto index = indexOf(sourceTerm[search .. search + termForRewrite.length], termForRewrite);
97 
98 				if (index != -1)
99 				{
100 					search += termForRewrite.length;
101 					acc ~= newTerm;
102 				}
103 				else
104 				{
105 					search++;
106 					acc ~= sourceTerm[search-1];
107 				}
108 			}
109 			
110 			return acc;
111 		}
112 	}
113 
114 	this(Surface surface, RGBColor color, LSystemParameters parameters, 
115 		string axiom, RewritingRules rules)
116 	{
117 		this.surface = surface;
118 		this.color = color;
119 		this.parameters = parameters;
120 		this.axiom = axiom;
121 		this.rules = rules;
122 	}
123 
124 	LSystemParameters execute()
125 	{
126 		// новое состояние черепахи
127 		auto turtleState = new TurtleState(
128 			parameters.getX!float, 
129 			parameters.getY!float, 
130 			parameters.getAngle!float
131 			);
132 		// новая черепаха
133 		auto turtle = new Turtle(surface, color, turtleState, 
134 			parameters.getStep!float, 
135 			parameters.getAngle!float
136 			);
137 
138 		// команды L-системы
139 		auto lSystemCmd = axiom;
140 
141 		// запуск процедуры переписывания
142 		for (ulong i = 1; i < parameters.getGeneration!ulong; i++)
143 		{
144 			foreach (rule; rules.keys)
145 			{
146 				lSystemCmd = rewrite(lSystemCmd.idup, rule, rules[rule]);
147 			}
148 		}
149 
150 		turtle.execute(lSystemCmd);
151 
152 		return parameters;
153 	}
154 }
155