Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Piece.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // @flow
  2. import ShapeL from '../Shapes/ShapeL';
  3. import ShapeI from '../Shapes/ShapeI';
  4. import ShapeJ from '../Shapes/ShapeJ';
  5. import ShapeO from '../Shapes/ShapeO';
  6. import ShapeS from '../Shapes/ShapeS';
  7. import ShapeT from '../Shapes/ShapeT';
  8. import ShapeZ from '../Shapes/ShapeZ';
  9. import type {CoordinatesType} from '../Shapes/BaseShape';
  10. import BaseShape from '../Shapes/BaseShape';
  11. import type {GridType} from '../components/GridComponent';
  12. import type {CustomThemeType} from '../../../managers/ThemeManager';
  13. /**
  14. * Class used as an abstraction layer for shapes.
  15. * Use this class to manipulate pieces rather than Shapes directly
  16. *
  17. */
  18. export default class Piece {
  19. shapes = [ShapeL, ShapeI, ShapeJ, ShapeO, ShapeS, ShapeT, ShapeZ];
  20. currentShape: BaseShape;
  21. theme: CustomThemeType;
  22. /**
  23. * Initializes this piece's color and shape
  24. *
  25. * @param theme Object containing current theme
  26. */
  27. constructor(theme: CustomThemeType) {
  28. this.currentShape = this.getRandomShape(theme);
  29. this.theme = theme;
  30. }
  31. /**
  32. * Gets a random shape object
  33. *
  34. * @param theme Object containing current theme
  35. */
  36. getRandomShape(theme: CustomThemeType): BaseShape {
  37. return new this.shapes[Math.floor(Math.random() * 7)](theme);
  38. }
  39. /**
  40. * Removes the piece from the given grid
  41. *
  42. * @param grid The grid to remove the piece from
  43. */
  44. removeFromGrid(grid: GridType) {
  45. const pos: Array<CoordinatesType> = this.currentShape.getCellsCoordinates(
  46. true,
  47. );
  48. pos.forEach((coordinates: CoordinatesType) => {
  49. // eslint-disable-next-line no-param-reassign
  50. grid[coordinates.y][coordinates.x] = {
  51. color: this.theme.colors.tetrisBackground,
  52. isEmpty: true,
  53. key: grid[coordinates.y][coordinates.x].key,
  54. };
  55. });
  56. }
  57. /**
  58. * Adds this piece to the given grid
  59. *
  60. * @param grid The grid to add the piece to
  61. * @param isPreview Should we use this piece's current position to determine the cells?
  62. */
  63. toGrid(grid: GridType, isPreview: boolean) {
  64. const pos: Array<CoordinatesType> = this.currentShape.getCellsCoordinates(
  65. !isPreview,
  66. );
  67. pos.forEach((coordinates: CoordinatesType) => {
  68. // eslint-disable-next-line no-param-reassign
  69. grid[coordinates.y][coordinates.x] = {
  70. color: this.currentShape.getColor(),
  71. isEmpty: false,
  72. key: grid[coordinates.y][coordinates.x].key,
  73. };
  74. });
  75. }
  76. /**
  77. * Checks if the piece's current position is valid
  78. *
  79. * @param grid The current game grid
  80. * @param width The grid's width
  81. * @param height The grid's height
  82. * @return {boolean} If the position is valid
  83. */
  84. isPositionValid(grid: GridType, width: number, height: number): boolean {
  85. let isValid = true;
  86. const pos: Array<CoordinatesType> = this.currentShape.getCellsCoordinates(
  87. true,
  88. );
  89. for (let i = 0; i < pos.length; i += 1) {
  90. if (
  91. pos[i].x >= width ||
  92. pos[i].x < 0 ||
  93. pos[i].y >= height ||
  94. pos[i].y < 0 ||
  95. !grid[pos[i].y][pos[i].x].isEmpty
  96. ) {
  97. isValid = false;
  98. break;
  99. }
  100. }
  101. return isValid;
  102. }
  103. /**
  104. * Tries to move the piece by the given offset on the given grid
  105. *
  106. * @param x Position X offset
  107. * @param y Position Y offset
  108. * @param grid The grid to move the piece on
  109. * @param width The grid's width
  110. * @param height The grid's height
  111. * @param freezeCallback Callback to use if the piece should freeze itself
  112. * @return {boolean} True if the move was valid, false otherwise
  113. */
  114. tryMove(
  115. x: number,
  116. y: number,
  117. grid: GridType,
  118. width: number,
  119. height: number,
  120. freezeCallback: () => void,
  121. ): boolean {
  122. let newX = x;
  123. let newY = y;
  124. if (x > 1) newX = 1; // Prevent moving from more than one tile
  125. if (x < -1) newX = -1;
  126. if (y > 1) newY = 1;
  127. if (y < -1) newY = -1;
  128. if (x !== 0 && y !== 0) newY = 0; // Prevent diagonal movement
  129. this.removeFromGrid(grid);
  130. this.currentShape.move(newX, newY);
  131. const isValid = this.isPositionValid(grid, width, height);
  132. if (!isValid) this.currentShape.move(-newX, -newY);
  133. const shouldFreeze = !isValid && newY !== 0;
  134. this.toGrid(grid, false);
  135. if (shouldFreeze) freezeCallback();
  136. return isValid;
  137. }
  138. /**
  139. * Tries to rotate the piece
  140. *
  141. * @param grid The grid to rotate the piece on
  142. * @param width The grid's width
  143. * @param height The grid's height
  144. * @return {boolean} True if the rotation was valid, false otherwise
  145. */
  146. tryRotate(grid: GridType, width: number, height: number): boolean {
  147. this.removeFromGrid(grid);
  148. this.currentShape.rotate(true);
  149. if (!this.isPositionValid(grid, width, height)) {
  150. this.currentShape.rotate(false);
  151. this.toGrid(grid, false);
  152. return false;
  153. }
  154. this.toGrid(grid, false);
  155. return true;
  156. }
  157. /**
  158. * Gets this piece used cells coordinates
  159. *
  160. * @return {Array<CoordinatesType>} An array of coordinates
  161. */
  162. getCoordinates(): Array<CoordinatesType> {
  163. return this.currentShape.getCellsCoordinates(true);
  164. }
  165. getCurrentShape(): BaseShape {
  166. return this.currentShape;
  167. }
  168. }