Board.cs 16 KB

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