1 module wireworld;
2 
3 private
4 {
5 	import qte5;
6 }
7 
8 // элементы мира WireWorld
9 final enum Element : byte 
10 {
11 	Empty,        // пустое поле
12 	Head,         // голова электрона
13 	Tail,         // хвост электрона
14 	Conductor     // проводник
15 }
16 
17 // мир WireWorld
18 class WireWorld(size_t WORLD_WIDTH, size_t WORLD_HEIGHT)
19 {
20 	private
21 	{
22 		// мир
23 		byte[WORLD_HEIGHT][WORLD_WIDTH] world;
24 		// копия мира
25 		byte[WORLD_HEIGHT][WORLD_WIDTH] reserved;
26 
27 		// резервное копирование мира
28 		void backupWorld()
29 		{
30 			for (int i = 0; i < WORLD_WIDTH; i++)
31 			{
32 				for (int j = 0; j < WORLD_HEIGHT; j++)
33 				{
34 					reserved[i][j] = world[i][j];
35 				}
36 			}
37 		}
38 	}
39 
40 	this()
41 	{
42 		
43 	}
44 
45 	// извлечение элемента
46 	auto opIndex(size_t i, size_t j)
47 	{
48 		return world[i][j];
49 	}
50 
51 	// присвоение элемента
52 	void opIndexAssign(Element element, size_t i, size_t j)
53 	{
54 		world[i][j] = element;
55 	}
56 
57 	// одно поколение клеточного автомата
58 	auto execute()
59 	{
60 		// скопировать мир
61 		backupWorld;
62 
63 		// трансформация ячейки с проводником
64 		void transformConductorCell(int i, int j)
65 		{
66 			auto up = ((j + 1) >= WORLD_HEIGHT) ? WORLD_HEIGHT - 1 : j + 1;
67 			auto down = ((j - 1) < 0) ? 0 : j - 1;
68 			auto right = ((i + 1) >= WORLD_WIDTH) ?  WORLD_WIDTH - 1 : i + 1;
69 			auto left = ((i - 1) < 0) ? 0 : i - 1;
70 
71 			auto counter = 0;
72 
73 			if (reserved[i][up] == Element.Head)
74 			{
75 				counter++;
76 			}
77 
78 			if (reserved[i][down] == Element.Head)
79 			{
80 				counter++;
81 			}
82 
83 			if (reserved[left][j] == Element.Head)
84 			{
85 				counter++;
86 			}
87 
88 			if (reserved[right][j] == Element.Head)
89 			{
90 				counter++;
91 			}
92 
93 			if (reserved[left][up] == Element.Head)
94 			{
95 				counter++;
96 			}
97 
98 			if (reserved[left][down] == Element.Head)
99 			{
100 				counter++;
101 			}
102 
103 			if (reserved[right][up] == Element.Head)
104 			{
105 				counter++;
106 			}
107 
108 			if (reserved[right][down] == Element.Head)
109 			{
110 				counter++;
111 			}
112 
113 			if ((counter == 1) || (counter == 2))
114 			{
115 				world[i][j] = Element.Head;
116 			}
117 			else
118 			{
119 				world[i][j] = Element.Conductor;
120 			}
121 		}
122 
123 		for (int i = 0; i < WORLD_WIDTH; i++)
124 		{
125 			for (int j = 0; j < WORLD_HEIGHT; j++)
126 			{
127 				auto currentCell = reserved[i][j];
128 				
129 				final switch (currentCell) with (Element)
130 				{
131 					case Empty:
132 						world[i][j] = Empty;
133 						break;
134 					case Head:
135 						world[i][j] = Tail;
136 						break;
137 					case Tail:
138 						world[i][j] = Conductor;
139 						break;
140 					case Conductor:
141 						transformConductorCell(i, j);
142 						break;
143 				}
144 			}
145 		}
146 	}
147 
148 	// очистка всего мира
149 	void clearWorld()
150 	{
151 		world = typeof(world).init;
152 	}
153 
154 	// нарисовать мир с помощью QtE5
155 	void drawWorld(QPainter painter, int cellWidth, int cellHeight)
156 	{
157 
158 	    QColor BLACK = new QColor(null);
159 	    QColor BLUE = new QColor(null);
160 	    QColor RED = new QColor(null);
161 	    QColor YELLOW = new QColor(null);
162 	    QColor GRAY = new QColor(null);
163 
164 	    BLACK.setRgb(0, 0, 0, 230);
165 		BLUE.setRgb(0, 0, 255, 230);
166 		RED.setRgb(255, 0, 0, 230);
167 		YELLOW.setRgb(255, 255, 0, 230);
168 		GRAY.setRgb(133, 133, 133, 230);
169 
170 		QPen pen = new QPen;
171 		pen.setColor(GRAY);
172 
173 	    for (int i = 0; i < WORLD_WIDTH; i++)
174 		{
175 			for (int j = 0; j < WORLD_HEIGHT; j++)
176 			{
177 				auto currentCell = world[i][j];
178 
179 				// рисование прямоугольника
180 				QRect rect = new QRect;
181 	    		rect.setRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
182 
183 				final switch (currentCell) with (Element)
184 				{
185 					case Empty:
186 						painter.fillRect(rect, BLACK);			
187 						break;
188 					case Head:
189 						painter.fillRect(rect, BLUE);
190 						break;
191 					case Tail:
192 						painter.fillRect(rect, RED);
193 						break;
194 					case Conductor:
195 						painter.fillRect(rect, YELLOW);
196 						break;
197 				}
198 
199 				painter.setPen(pen);
200 				painter.drawRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
201 			}
202 		}
203 	}
204 }