1 using System;
2 using System.Drawing;
3 using System.Windows.Forms;
4
5 internal class tetris : Form
6 {
7 private static void Main()
8 {
9 Application.EnableVisualStyles();
10 Application.Run(new tetris());
11 }
12
13 private const int dimension = 8;
14 private const int maxwidth = 16;
15 private const int maxheight = 32;
16 private const int boardwidth = 8;
17 private const int nextwidth = boardwidth - 2;
18 private const int invalid = 255;
19
20 private Timer timer;
21
22 private byte[,] matrix;
23
24 private tetris_object item;
25 private tetris_object next;
26
27 private bool start;
28 private bool pause;
29 private string message;
30 private int score;
31 private int ox;
32 private int oy;
33
34 private int offsetx
35 {
36 get
37 {
38 return ox;
39 }
40 set
41 {
42 if (0 != item.check(value, oy, matrix))
43 ox = value;
44 }
45 }
46
47 private int offsety
48 {
49 get
50 {
51 return oy;
52 }
53 set
54 {
55 int result = item.check(ox, value, matrix);
56
57 if (0 == result)
58 {
59 item.shift(ox, oy, matrix);
60
61 check();
62
63 item = next;
64 next = generate();
65
66 ox = (maxwidth - 4) / 2;
67 oy = -item.bottom;
68 }
69 else if (-1 == result)
70 {
71 lost("game over");
72 }
73 else
74 {
75 oy = value;
76 }
77 }
78 }
79
80 private tetris()
81 {
82 timer = new Timer();
83
84 timer.Interval = 500;
85
86 timer.Tick += timer_tick;
87
88 DoubleBuffered = true;
89 MaximizeBox = false;
90 FormBorderStyle = FormBorderStyle.FixedDialog;
91 StartPosition = FormStartPosition.CenterScreen;
92 ClientSize = new Size(dimension * (maxwidth + boardwidth), dimension * maxheight);
93 Font = new Font("Consolas", dimension);
94
95 KeyPress += key_press;
96 Paint += paint;
97
98 pause = true;
99 }
100
101 private void timer_tick(object o, EventArgs e)
102 {
103 ++offsety;
104
105 Refresh();
106 }
107
108 private void key_press(object o, KeyPressEventArgs e)
109 {
110 if (!pause)
111 switch (e.KeyChar)
112 {
113 case 'a':
114 case 'A': --offsetx; break;
115
116 case 'd':
117 case 'D': ++offsetx; break;
118
119 case 's':
120 case 'S': ++offsety; break;
121
122 case 'w':
123 case 'W': item.rotate(ox, oy, matrix); break;
124 }
125
126 if ('e' == e.KeyChar || 'E' == e.KeyChar)
127 {
128 if (!start)
129 init();
130
131 timer.Enabled = pause;
132
133 pause = !pause;
134 }
135 else if ('r' == e.KeyChar || 'R' == e.KeyChar)
136 {
137 lost("");
138 }
139
140 Refresh();
141 }
142
143 private void paint(object o, PaintEventArgs e)
144 {
145 e.Graphics.FillRectangle(Brushes.WhiteSmoke, 0, 0, dimension * maxwidth, dimension * maxheight);
146 e.Graphics.FillRectangle(Brushes.Gray, dimension * maxwidth, 0, dimension * boardwidth, dimension * maxheight);
147 e.Graphics.FillRectangle(Brushes.LightGray, dimension * (maxwidth + (boardwidth - nextwidth) / 2), dimension * 1, dimension * nextwidth, dimension * nextwidth);
148
149 e.Graphics.DrawString(string.Format("a:left\nd:right\ns:down\nw:rotate\ne:pause\nr:reset"), Font, Brushes.Black, dimension * (maxwidth + (boardwidth - nextwidth) / 2), dimension * (nextwidth + 4));
150
151 if (start)
152 {
153 if (pause)
154 e.Graphics.DrawString("pause", Font, Brushes.Black, dimension * 1, dimension * (maxheight / 2));
155
156 e.Graphics.DrawString(string.Format("{0:d7}", score), Font, Brushes.Black, dimension * (maxwidth + (boardwidth - nextwidth) / 2), dimension * (nextwidth + 2));
157
158 for (int y = 0; y < maxheight; ++y)
159 for (int x = 0; x < maxwidth; ++x)
160 if (invalid != matrix[x, y])
161 e.Graphics.FillRectangle(tetris_object.colors[matrix[x, y]], dimension * x, dimension * y, dimension - 1, dimension - 1);
162
163 item.draw(ox, oy, e.Graphics);
164 next.draw(maxwidth + (boardwidth - 4) / 2, 2, e.Graphics);
165 }
166 else
167 {
168 e.Graphics.DrawString(message, Font, Brushes.Black, dimension * 1, dimension * (maxheight / 2 - 2));
169 e.Graphics.DrawString("press \"e\" to start", Font, Brushes.Black, dimension * 1, dimension * (maxheight / 2));
170 }
171 }
172
173 private void init()
174 {
175 matrix = new byte[maxwidth, maxheight];
176
177 for (int y = 0; y < maxheight; ++y)
178 for (int x = 0; x < maxwidth; ++x)
179 matrix[x, y] = invalid;
180
181 item = generate();
182 next = generate();
183
184 start = true;
185 pause = true;
186 message = "";
187 score = 0;
188 ox = (maxwidth - 4) / 2;
189 oy = -item.bottom;
190 }
191
192 private void lost(string text)
193 {
194 timer.Enabled = false;
195
196 start = false;
197 message = text;
198 }
199
200 private tetris_object generate()
201 {
202 tetris_object current = new tetris_object();
203
204 return current;
205 }
206
207 private void check()
208 {
209 byte[,] target = new byte[maxwidth, maxheight];
210
211 for (int y = 0; y < maxheight; ++y)
212 for (int x = 0; x < maxwidth; ++x)
213 target[x, y] = invalid;
214
215 for (int y = maxheight, ty = maxheight; y-- > 0; )
216 if (!check(y))
217 {
218 --ty;
219
220 for (int x = 0; x < maxwidth; ++x)
221 target[x, ty] = matrix[x, y];
222 }
223
224 matrix = target;
225 }
226
227 private bool check(int y)
228 {
229 for (int x = 0; x < maxwidth; ++x)
230 if (invalid == matrix[x, y])
231 return false;
232
233 score = score + 100;
234
235 if (0 == score % 1000)
236 if (100 < timer.Interval)
237 timer.Interval = timer.Interval - 50;
238
239 return true;
240 }
241
242 private void remove(int y)
243 {
244 }
245
246 private class tetris_object
247 {
248 private static readonly byte[][][] objects =
249 {
250 new byte[][]
251 {
252 new byte[] { 8, 9, 10, 11, },
253 new byte[] { 1, 5, 9, 13, },
254 },
255 new byte[][]
256 {
257 new byte[] { 9, 10, 13, 14, },
258 },
259 new byte[][]
260 {
261 new byte[] { 5, 8, 9, 10, },
262 new byte[] { 5, 9, 10, 13, },
263 new byte[] { 8, 9, 10, 13, },
264 new byte[] { 5, 8, 9, 13, },
265 },
266 new byte[][]
267 {
268 new byte[] { 4, 8, 9, 10, },
269 new byte[] { 5, 6, 9, 13, },
270 new byte[] { 8, 9, 10, 14, },
271 new byte[] { 5, 9, 12, 13, },
272 },
273 new byte[][]
274 {
275 new byte[] { 6, 8, 9, 10, },
276 new byte[] { 5, 9, 13, 14, },
277 new byte[] { 8, 9, 10, 12, },
278 new byte[] { 4, 5, 9, 13, },
279 },
280 new byte[][]
281 {
282 new byte[] { 4, 5, 9, 10, },
283 new byte[] { 6, 9, 10, 13, },
284 },
285 new byte[][]
286 {
287 new byte[] { 5, 6, 8, 9, },
288 new byte[] { 5, 9, 10, 14, },
289 },
290 };
291 private static readonly Brush[] brushes =
292 {
293 Brushes.Salmon,
294 Brushes.Peru,
295 Brushes.Teal,
296 Brushes.Purple,
297 Brushes.Indigo,
298 Brushes.Olive,
299 Brushes.Green,
300 };
301
302 private int column;
303 private int row;
304
305 internal static Brush[] colors
306 {
307 get
308 {
309 return brushes;
310 }
311 }
312
313 internal int bottom
314 {
315 get
316 {
317 return objects[column][row][3] / 4 + 1;
318 }
319 }
320
321 internal tetris_object()
322 {
323 Random random = new Random();
324
325 column = random.Next() % objects.Length;
326 row = random.Next() % objects[column].Length;
327 }
328
329 internal void rotate(int x, int y, byte[,] matrix)
330 {
331 int original = row;
332
333 while (++original < objects[column].Length)
334 if (0 != check(objects[column][original], x, y, matrix))
335 goto _rotate;
336
337 for (original = 0; original < row; ++original)
338 if (0 != check(objects[column][original], x, y, matrix))
339 goto _rotate;
340
341 return;
342
343 _rotate:
344 row = original;
345 }
346
347 private int check(byte[] cubes, int x, int y, byte[,] matrix)
348 {
349 int minx = Math.Min(Math.Min(cubes[0] % 4, cubes[1] % 4), Math.Min(cubes[2] % 4, cubes[3] % 4));
350 int maxx = Math.Max(Math.Max(cubes[0] % 4, cubes[1] % 4), Math.Max(cubes[2] % 4, cubes[3] % 4));
351
352 if (-minx > x || maxwidth - maxx <= x)
353 return 0;
354
355 if (maxheight <= y + cubes[3] / 4)
356 return 0;
357
358 foreach (byte cube in cubes)
359 {
360 int l = x + cube % 4;
361 int t = y + cube / 4;
362
363 if (0 <= l && maxwidth > l && 0 <= t && maxheight > t)
364 if (invalid != matrix[l, t])
365 if (1 > y + cubes[0] / 4)
366 return -1;
367 else
368 return 0;
369 }
370
371 return 1;
372 }
373
374 internal int check(int x, int y, byte[,] matrix)
375 {
376 return check(objects[column][row], x, y, matrix);
377 }
378
379 internal void shift(int x, int y, byte[,] matrix)
380 {
381 foreach (byte cube in objects[column][row])
382 matrix[x + cube % 4, y + cube / 4] = (byte)column;
383 }
384
385 internal void draw(int x, int y, Graphics graphics)
386 {
387 foreach (byte cube in objects[column][row])
388 graphics.FillRectangle(brushes[column], dimension * (x + cube % 4), dimension * (y + cube / 4), dimension - 1, dimension - 1);
389 }
390 }
391 }