Board.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. using System;
  2. using System.Collections.Generic;
  3. using Microsoft.Xna.Framework;
  4. using Microsoft.Xna.Framework.Graphics;
  5. namespace Tetris
  6. {
  7. class Board : DrawableGameComponent
  8. {
  9. SpriteBatch sBatch;
  10. Texture2D textures;
  11. Rectangle[] rectangles;
  12. enum FieldState
  13. {
  14. Free,
  15. Static,
  16. Dynamic
  17. };
  18. FieldState[,] boardFields;
  19. Vector2[, ,] Figures;
  20. readonly Vector2 StartPositionForNewFigure = new Vector2 (3, 0);
  21. Vector2 PositionForDynamicFigure;
  22. Vector2[] DynamicFigure = new Vector2[BlocksCountInFigure];
  23. Random random = new Random ();
  24. int[,] BoardColor;
  25. const int height = 20;
  26. const int width = 10;
  27. const int BlocksCountInFigure = 4;
  28. int DynamicFigureNumber;
  29. int DynamicFigureModificationNumber;
  30. int DynamicFigureColor;
  31. bool BlockLine;
  32. bool showNewBlock;
  33. float movement;
  34. float speed;
  35. Queue<int> nextFigures = new Queue<int> ();
  36. Queue<int> nextFiguresModification = new Queue<int> ();
  37. public float Movement {
  38. set { movement = value; }
  39. get { return movement; }
  40. }
  41. public float Speed {
  42. set { speed = value; }
  43. get { return speed; }
  44. }
  45. public Board (Game game, ref Texture2D textures, Rectangle[] rectangles)
  46. : base(game) {
  47. sBatch = (SpriteBatch)Game.Services.GetService (typeof(SpriteBatch));
  48. // Load textures for blocks
  49. this.textures = textures;
  50. // Rectangles to draw figures
  51. this.rectangles = rectangles;
  52. // Create tetris board
  53. boardFields = new FieldState[width, height];
  54. BoardColor = new int[width, height];
  55. // Figures[figure's number, figure's modification, figure's block number] = Vector2
  56. // At all figures is 7, every has 4 modifications (for cube all modifications the same)
  57. // and every figure consists from 4 blocks
  58. Figures = new Vector2[7, 4, 4];
  59. // O-figure
  60. for (int i = 0; i < 4; i++) {
  61. Figures [0, i, 0] = new Vector2 (1, 0);
  62. Figures [0, i, 1] = new Vector2 (2, 0);
  63. Figures [0, i, 2] = new Vector2 (1, 1);
  64. Figures [0, i, 3] = new Vector2 (2, 1);
  65. }
  66. // I-figures
  67. for (int i = 0; i < 4; i += 2) {
  68. Figures [1, i, 0] = new Vector2 (0, 0);
  69. Figures [1, i, 1] = new Vector2 (1, 0);
  70. Figures [1, i, 2] = new Vector2 (2, 0);
  71. Figures [1, i, 3] = new Vector2 (3, 0);
  72. Figures [1, i + 1, 0] = new Vector2 (1, 0);
  73. Figures [1, i + 1, 1] = new Vector2 (1, 1);
  74. Figures [1, i + 1, 2] = new Vector2 (1, 2);
  75. Figures [1, i + 1, 3] = new Vector2 (1, 3);
  76. }
  77. // J-figures
  78. Figures [2, 0, 0] = new Vector2 (0, 0);
  79. Figures [2, 0, 1] = new Vector2 (1, 0);
  80. Figures [2, 0, 2] = new Vector2 (2, 0);
  81. Figures [2, 0, 3] = new Vector2 (2, 1);
  82. Figures [2, 1, 0] = new Vector2 (2, 0);
  83. Figures [2, 1, 1] = new Vector2 (2, 1);
  84. Figures [2, 1, 2] = new Vector2 (1, 2);
  85. Figures [2, 1, 3] = new Vector2 (2, 2);
  86. Figures [2, 2, 0] = new Vector2 (0, 0);
  87. Figures [2, 2, 1] = new Vector2 (0, 1);
  88. Figures [2, 2, 2] = new Vector2 (1, 1);
  89. Figures [2, 2, 3] = new Vector2 (2, 1);
  90. Figures [2, 3, 0] = new Vector2 (1, 0);
  91. Figures [2, 3, 1] = new Vector2 (2, 0);
  92. Figures [2, 3, 2] = new Vector2 (1, 1);
  93. Figures [2, 3, 3] = new Vector2 (1, 2);
  94. // L-figures
  95. Figures [3, 0, 0] = new Vector2 (0, 0);
  96. Figures [3, 0, 1] = new Vector2 (1, 0);
  97. Figures [3, 0, 2] = new Vector2 (2, 0);
  98. Figures [3, 0, 3] = new Vector2 (0, 1);
  99. Figures [3, 1, 0] = new Vector2 (2, 0);
  100. Figures [3, 1, 1] = new Vector2 (2, 1);
  101. Figures [3, 1, 2] = new Vector2 (1, 0);
  102. Figures [3, 1, 3] = new Vector2 (2, 2);
  103. Figures [3, 2, 0] = new Vector2 (0, 1);
  104. Figures [3, 2, 1] = new Vector2 (1, 1);
  105. Figures [3, 2, 2] = new Vector2 (2, 1);
  106. Figures [3, 2, 3] = new Vector2 (2, 0);
  107. Figures [3, 3, 0] = new Vector2 (1, 0);
  108. Figures [3, 3, 1] = new Vector2 (2, 2);
  109. Figures [3, 3, 2] = new Vector2 (1, 1);
  110. Figures [3, 3, 3] = new Vector2 (1, 2);
  111. // S-figures
  112. for (int i = 0; i < 4; i += 2) {
  113. Figures [4, i, 0] = new Vector2 (0, 1);
  114. Figures [4, i, 1] = new Vector2 (1, 1);
  115. Figures [4, i, 2] = new Vector2 (1, 0);
  116. Figures [4, i, 3] = new Vector2 (2, 0);
  117. Figures [4, i + 1, 0] = new Vector2 (1, 0);
  118. Figures [4, i + 1, 1] = new Vector2 (1, 1);
  119. Figures [4, i + 1, 2] = new Vector2 (2, 1);
  120. Figures [4, i + 1, 3] = new Vector2 (2, 2);
  121. }
  122. // Z-figures
  123. for (int i = 0; i < 4; i += 2) {
  124. Figures [5, i, 0] = new Vector2 (0, 0);
  125. Figures [5, i, 1] = new Vector2 (1, 0);
  126. Figures [5, i, 2] = new Vector2 (1, 1);
  127. Figures [5, i, 3] = new Vector2 (2, 1);
  128. Figures [5, i + 1, 0] = new Vector2 (2, 0);
  129. Figures [5, i + 1, 1] = new Vector2 (1, 1);
  130. Figures [5, i + 1, 2] = new Vector2 (2, 1);
  131. Figures [5, i + 1, 3] = new Vector2 (1, 2);
  132. }
  133. // T-figures
  134. Figures [6, 0, 0] = new Vector2 (0, 1);
  135. Figures [6, 0, 1] = new Vector2 (1, 1);
  136. Figures [6, 0, 2] = new Vector2 (2, 1);
  137. Figures [6, 0, 3] = new Vector2 (1, 0);
  138. Figures [6, 1, 0] = new Vector2 (1, 0);
  139. Figures [6, 1, 1] = new Vector2 (1, 1);
  140. Figures [6, 1, 2] = new Vector2 (1, 2);
  141. Figures [6, 1, 3] = new Vector2 (2, 1);
  142. Figures [6, 2, 0] = new Vector2 (0, 0);
  143. Figures [6, 2, 1] = new Vector2 (1, 0);
  144. Figures [6, 2, 2] = new Vector2 (2, 0);
  145. Figures [6, 2, 3] = new Vector2 (1, 1);
  146. Figures [6, 3, 0] = new Vector2 (2, 0);
  147. Figures [6, 3, 1] = new Vector2 (2, 1);
  148. Figures [6, 3, 2] = new Vector2 (2, 2);
  149. Figures [6, 3, 3] = new Vector2 (1, 1);
  150. nextFigures.Enqueue (random.Next (7));
  151. nextFigures.Enqueue (random.Next (7));
  152. nextFigures.Enqueue (random.Next (7));
  153. nextFigures.Enqueue (random.Next (7));
  154. nextFiguresModification.Enqueue (random.Next (4));
  155. nextFiguresModification.Enqueue (random.Next (4));
  156. nextFiguresModification.Enqueue (random.Next (4));
  157. nextFiguresModification.Enqueue (random.Next (4));
  158. }
  159. public override void Initialize ()
  160. {
  161. showNewBlock = true;
  162. movement = 0;
  163. speed = 0.1f;
  164. for (int i = 0; i < width; i++)
  165. for (int j = 0; j < height; j++)
  166. ClearBoardField (i, j);
  167. base.Initialize ();
  168. }
  169. public void FindDynamicFigure ()
  170. {
  171. int BlockNumberInDynamicFigure = 0;
  172. for (int i = 0; i < width; i++)
  173. for (int j = 0; j < height; j++)
  174. if (boardFields [i, j] == FieldState.Dynamic)
  175. DynamicFigure [BlockNumberInDynamicFigure++] = new Vector2 (i, j);
  176. }
  177. /// <summary>
  178. /// Find, destroy and save lines's count
  179. /// </summary>
  180. /// <returns>Number of destoyed lines</returns>
  181. public int DestroyLines ()
  182. {
  183. // Find total lines
  184. int BlockLineCount = 0;
  185. for (int j = 0; j < height; j++) {
  186. for (int i = 0; i < width; i++)
  187. if (boardFields [i, j] == FieldState.Static)
  188. BlockLine = true;
  189. else {
  190. BlockLine = false;
  191. break;
  192. }
  193. //Destroy total lines
  194. if (BlockLine) {
  195. // Save number of total lines
  196. BlockLineCount++;
  197. for (int l = j; l > 0; l--)
  198. for (int k = 0; k < width; k++) {
  199. boardFields [k, l] = boardFields [k, l - 1];
  200. BoardColor [k, l] = BoardColor [k, l - 1];
  201. }
  202. for (int l = 0; l < width; l++) {
  203. boardFields [l, 0] = FieldState.Free;
  204. BoardColor [l, 0] = -1;
  205. }
  206. }
  207. }
  208. return BlockLineCount;
  209. }
  210. /// <summary>
  211. /// Create new shape in the game, if need it
  212. /// </summary>
  213. public bool CreateNewFigure ()
  214. {
  215. if (showNewBlock) {
  216. // Generate new figure's shape
  217. DynamicFigureNumber = nextFigures.Dequeue ();
  218. nextFigures.Enqueue (random.Next (7));
  219. DynamicFigureModificationNumber = nextFiguresModification.Dequeue ();
  220. nextFiguresModification.Enqueue (random.Next (4));
  221. DynamicFigureColor = DynamicFigureNumber;
  222. // Position and coordinates for new dynamic figure
  223. PositionForDynamicFigure = StartPositionForNewFigure;
  224. for (int i = 0; i < BlocksCountInFigure; i++)
  225. DynamicFigure [i] = Figures [DynamicFigureNumber, DynamicFigureModificationNumber, i] +
  226. PositionForDynamicFigure;
  227. if (!DrawFigureOnBoard (DynamicFigure, DynamicFigureColor))
  228. return false;
  229. showNewBlock = false;
  230. }
  231. return true;
  232. }
  233. bool DrawFigureOnBoard (Vector2[] vector, int color)
  234. {
  235. if (!TryPlaceFigureOnBoard (vector))
  236. return false;
  237. for (int i = 0; i <= vector.GetUpperBound(0); i++) {
  238. boardFields [(int)vector [i].X, (int)vector [i].Y] = FieldState.Dynamic;
  239. BoardColor [(int)vector [i].X, (int)vector [i].Y] = color;
  240. }
  241. return true;
  242. }
  243. bool TryPlaceFigureOnBoard (Vector2[] vector)
  244. {
  245. for (int i = 0; i <= vector.GetUpperBound(0); i++)
  246. if ((vector [i].X < 0) || (vector [i].X >= width) ||
  247. (vector [i].Y >= height))
  248. return false;
  249. for (int i = 0; i <= vector.GetUpperBound(0); i++)
  250. if (boardFields [(int)vector [i].X, (int)vector [i].Y] == FieldState.Static)
  251. return false;
  252. return true;
  253. }
  254. public void MoveFigureLeft ()
  255. {
  256. // Sorting blocks fro dynamic figure to correct moving
  257. SortingVector2 (ref DynamicFigure, true, DynamicFigure.GetLowerBound (0), DynamicFigure.GetUpperBound (0));
  258. // Check colisions
  259. for (int i = 0; i < BlocksCountInFigure; i++) {
  260. if ((DynamicFigure [i].X == 0))
  261. return;
  262. if (boardFields [(int)DynamicFigure [i].X - 1, (int)DynamicFigure [i].Y] == FieldState.Static)
  263. return;
  264. }
  265. // Move figure on board
  266. for (int i = 0; i < BlocksCountInFigure; i++) {
  267. boardFields [(int)DynamicFigure [i].X - 1, (int)DynamicFigure [i].Y] =
  268. boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  269. BoardColor [(int)DynamicFigure [i].X - 1, (int)DynamicFigure [i].Y] =
  270. BoardColor [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  271. ClearBoardField ((int)DynamicFigure [i].X, (int)DynamicFigure [i].Y);
  272. // Change position for blocks in DynamicFigure
  273. DynamicFigure [i].X = DynamicFigure [i].X - 1;
  274. }
  275. // Change position vector
  276. //if (PositionForDynamicFigure.X > 0)
  277. PositionForDynamicFigure.X--;
  278. }
  279. public void MoveFigureRight ()
  280. {
  281. // Sorting blocks fro dynamic figure to correct moving
  282. SortingVector2 (ref DynamicFigure, true, DynamicFigure.GetLowerBound (0), DynamicFigure.GetUpperBound (0));
  283. // Check colisions
  284. for (int i = 0; i < BlocksCountInFigure; i++) {
  285. if ((DynamicFigure [i].X == width - 1))
  286. return;
  287. if (boardFields [(int)DynamicFigure [i].X + 1, (int)DynamicFigure [i].Y] == FieldState.Static)
  288. return;
  289. }
  290. // Move figure on board
  291. for (int i = BlocksCountInFigure - 1; i >=0; i--) {
  292. boardFields [(int)DynamicFigure [i].X + 1, (int)DynamicFigure [i].Y] =
  293. boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  294. BoardColor [(int)DynamicFigure [i].X + 1, (int)DynamicFigure [i].Y] =
  295. BoardColor [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  296. ClearBoardField ((int)DynamicFigure [i].X, (int)DynamicFigure [i].Y);
  297. // Change position for blocks in DynamicFigure
  298. DynamicFigure [i].X = DynamicFigure [i].X + 1;
  299. }
  300. // Change position vector
  301. //if (PositionForDynamicFigure.X < width - 1)
  302. PositionForDynamicFigure.X++;
  303. }
  304. public void MoveFigureDown ()
  305. {
  306. // Sorting blocks fro dynamic figure to correct moving
  307. SortingVector2 (ref DynamicFigure, false, DynamicFigure.GetLowerBound (0), DynamicFigure.GetUpperBound (0));
  308. // Check colisions
  309. for (int i = 0; i < BlocksCountInFigure; i++) {
  310. if ((DynamicFigure [i].Y == height - 1)) {
  311. for (int k = 0; k < BlocksCountInFigure; k++)
  312. boardFields [(int)DynamicFigure [k].X, (int)DynamicFigure [k].Y] = FieldState.Static;
  313. showNewBlock = true;
  314. return;
  315. }
  316. if (boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y + 1] == FieldState.Static) {
  317. for (int k = 0; k < BlocksCountInFigure; k++)
  318. boardFields [(int)DynamicFigure [k].X, (int)DynamicFigure [k].Y] = FieldState.Static;
  319. showNewBlock = true;
  320. return;
  321. }
  322. }
  323. // Move figure on board
  324. for (int i = BlocksCountInFigure - 1; i >= 0; i--) {
  325. boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y + 1] =
  326. boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  327. BoardColor [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y + 1] =
  328. BoardColor [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y];
  329. ClearBoardField ((int)DynamicFigure [i].X, (int)DynamicFigure [i].Y);
  330. // Change position for blocks in DynamicFigure
  331. DynamicFigure [i].Y = DynamicFigure [i].Y + 1;
  332. }
  333. // Change position vector
  334. //if (PositionForDynamicFigure.Y < height - 1)
  335. PositionForDynamicFigure.Y++;
  336. }
  337. public void RotateFigure ()
  338. {
  339. // Check colisions for next modification
  340. Vector2[] TestDynamicFigure = new Vector2[DynamicFigure.GetUpperBound (0) + 1];
  341. for (int i = 0; i < BlocksCountInFigure; i++)
  342. TestDynamicFigure [i] = Figures [DynamicFigureNumber, (DynamicFigureModificationNumber + 1) % 4, i] + PositionForDynamicFigure;
  343. // Make sure that figure can rotate if she stand near left and right borders
  344. SortingVector2 (ref TestDynamicFigure, true, TestDynamicFigure.GetLowerBound (0), TestDynamicFigure.GetUpperBound (0));
  345. int leftFigureBound;
  346. int rightFigureBound;
  347. if ((leftFigureBound = (int)TestDynamicFigure [0].X) < 0) {
  348. //int leftFigureBound = (int)TestDynamicFigure[0].X;
  349. for (int i = 0; i < BlocksCountInFigure; i++) {
  350. TestDynamicFigure [i] += new Vector2 (0 - leftFigureBound, 0);
  351. }
  352. if (TryPlaceFigureOnBoard (TestDynamicFigure))
  353. PositionForDynamicFigure +=
  354. new Vector2 (0 - leftFigureBound, 0);
  355. }
  356. if ((rightFigureBound = (int)TestDynamicFigure [BlocksCountInFigure - 1].X) >= width) {
  357. //int rightFigureBound = (int)TestDynamicFigure[BlocksCountInFigure - 1].X;
  358. for (int i = 0; i < BlocksCountInFigure; i++) {
  359. TestDynamicFigure [i] -= new Vector2 (rightFigureBound - width + 1, 0);
  360. }
  361. if (TryPlaceFigureOnBoard (TestDynamicFigure))
  362. PositionForDynamicFigure -=
  363. new Vector2 (rightFigureBound - width + 1, 0);
  364. }
  365. if (TryPlaceFigureOnBoard (TestDynamicFigure)) {
  366. DynamicFigureModificationNumber = (DynamicFigureModificationNumber + 1) % 4;
  367. // Clear dynamic fields
  368. for (int i = 0; i <= DynamicFigure.GetUpperBound(0); i++)
  369. ClearBoardField ((int)DynamicFigure [i].X, (int)DynamicFigure [i].Y);
  370. DynamicFigure = TestDynamicFigure;
  371. for (int i = 0; i <= DynamicFigure.GetUpperBound(0); i++) {
  372. boardFields [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y] = FieldState.Dynamic;
  373. BoardColor [(int)DynamicFigure [i].X, (int)DynamicFigure [i].Y] = DynamicFigureColor;
  374. }
  375. }
  376. }
  377. public void SortingVector2 (ref Vector2[] vector, bool sortByX, int a, int b)
  378. {
  379. if (a >= b)
  380. return;
  381. int i = a;
  382. for (int j = a; j <= b; j++) {
  383. if (sortByX) {
  384. if (vector [j].X <= vector [b].X) {
  385. Vector2 tempVector = vector [i];
  386. vector [i] = vector [j];
  387. vector [j] = tempVector;
  388. i++;
  389. }
  390. } else {
  391. if (vector [j].Y <= vector [b].Y) {
  392. Vector2 tempVector = vector [i];
  393. vector [i] = vector [j];
  394. vector [j] = tempVector;
  395. i++;
  396. }
  397. }
  398. }
  399. int c = i - 1;
  400. SortingVector2 (ref vector, sortByX, a, c - 1);
  401. SortingVector2 (ref vector, sortByX, c + 1, b);
  402. }
  403. void ClearBoardField (int i, int j)
  404. {
  405. boardFields [i, j] = FieldState.Free;
  406. BoardColor [i, j] = -1;
  407. }
  408. public override void Draw (GameTime gameTime)
  409. {
  410. Vector2 startPosition;
  411. // Draw the blocks
  412. for (int i = 0; i < width; i++)
  413. for (int j = 0; j < height; j++)
  414. if (boardFields [i, j] != FieldState.Free) {
  415. startPosition = new Vector2 ((10 + i) * rectangles [0].Width,
  416. (2 + j) * rectangles [0].Height);
  417. sBatch.Draw (textures, startPosition, rectangles [BoardColor [i, j]], Color.White);
  418. }
  419. // Draw next figures
  420. Queue<int>.Enumerator figure = nextFigures.GetEnumerator ();
  421. Queue<int>.Enumerator modification = nextFiguresModification.GetEnumerator ();
  422. for (int i = 0; i < nextFigures.Count; i++) {
  423. figure.MoveNext ();
  424. modification.MoveNext ();
  425. for (int j = 0; j < BlocksCountInFigure; j++) {
  426. startPosition = rectangles [0].Height * (new Vector2 (24, 3 + 5 * i) +
  427. Figures [figure.Current, modification.Current, j]);
  428. sBatch.Draw (textures, startPosition,
  429. rectangles [figure.Current], Color.White);
  430. }
  431. }
  432. base.Draw (gameTime);
  433. }
  434. }
  435. }