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.ts 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import ShapeL from '../Shapes/ShapeL';
  20. import ShapeI from '../Shapes/ShapeI';
  21. import ShapeJ from '../Shapes/ShapeJ';
  22. import ShapeO from '../Shapes/ShapeO';
  23. import ShapeS from '../Shapes/ShapeS';
  24. import ShapeT from '../Shapes/ShapeT';
  25. import ShapeZ from '../Shapes/ShapeZ';
  26. import type { CoordinatesType } from '../Shapes/BaseShape';
  27. import BaseShape from '../Shapes/BaseShape';
  28. import type { GridType } from '../components/GridComponent';
  29. /**
  30. * Class used as an abstraction layer for shapes.
  31. * Use this class to manipulate pieces rather than Shapes directly
  32. *
  33. */
  34. export default class Piece {
  35. shapes = [ShapeL, ShapeI, ShapeJ, ShapeO, ShapeS, ShapeT, ShapeZ];
  36. currentShape: BaseShape;
  37. theme: ReactNativePaper.Theme;
  38. /**
  39. * Initializes this piece's color and shape
  40. *
  41. * @param theme Object containing current theme
  42. */
  43. constructor(theme: ReactNativePaper.Theme) {
  44. this.currentShape = this.getRandomShape(theme);
  45. this.theme = theme;
  46. }
  47. /**
  48. * Gets a random shape object
  49. *
  50. * @param theme Object containing current theme
  51. */
  52. getRandomShape(theme: ReactNativePaper.Theme): BaseShape {
  53. return new this.shapes[Math.floor(Math.random() * 7)](theme);
  54. }
  55. /**
  56. * Removes the piece from the given grid
  57. *
  58. * @param grid The grid to remove the piece from
  59. */
  60. removeFromGrid(grid: GridType) {
  61. const pos: Array<CoordinatesType> =
  62. this.currentShape.getCellsCoordinates(true);
  63. pos.forEach((coordinates: CoordinatesType) => {
  64. grid[coordinates.y][coordinates.x] = {
  65. color: this.theme.colors.tetrisBackground,
  66. isEmpty: true,
  67. key: grid[coordinates.y][coordinates.x].key,
  68. };
  69. });
  70. }
  71. /**
  72. * Adds this piece to the given grid
  73. *
  74. * @param grid The grid to add the piece to
  75. * @param isPreview Should we use this piece's current position to determine the cells?
  76. */
  77. toGrid(grid: GridType, isPreview: boolean) {
  78. const pos: Array<CoordinatesType> = this.currentShape.getCellsCoordinates(
  79. !isPreview
  80. );
  81. pos.forEach((coordinates: CoordinatesType) => {
  82. grid[coordinates.y][coordinates.x] = {
  83. color: this.currentShape.getColor(),
  84. isEmpty: false,
  85. key: grid[coordinates.y][coordinates.x].key,
  86. };
  87. });
  88. }
  89. /**
  90. * Checks if the piece's current position is valid
  91. *
  92. * @param grid The current game grid
  93. * @param width The grid's width
  94. * @param height The grid's height
  95. * @return {boolean} If the position is valid
  96. */
  97. isPositionValid(grid: GridType, width: number, height: number): boolean {
  98. let isValid = true;
  99. const pos: Array<CoordinatesType> =
  100. this.currentShape.getCellsCoordinates(true);
  101. for (let i = 0; i < pos.length; i += 1) {
  102. if (
  103. pos[i].x >= width ||
  104. pos[i].x < 0 ||
  105. pos[i].y >= height ||
  106. pos[i].y < 0 ||
  107. !grid[pos[i].y][pos[i].x].isEmpty
  108. ) {
  109. isValid = false;
  110. break;
  111. }
  112. }
  113. return isValid;
  114. }
  115. /**
  116. * Tries to move the piece by the given offset on the given grid
  117. *
  118. * @param x Position X offset
  119. * @param y Position Y offset
  120. * @param grid The grid to move the piece on
  121. * @param width The grid's width
  122. * @param height The grid's height
  123. * @param freezeCallback Callback to use if the piece should freeze itself
  124. * @return {boolean} True if the move was valid, false otherwise
  125. */
  126. tryMove(
  127. x: number,
  128. y: number,
  129. grid: GridType,
  130. width: number,
  131. height: number,
  132. freezeCallback: () => void
  133. ): boolean {
  134. let newX = x;
  135. let newY = y;
  136. if (x > 1) {
  137. newX = 1;
  138. } // Prevent moving from more than one tile
  139. if (x < -1) {
  140. newX = -1;
  141. }
  142. if (y > 1) {
  143. newY = 1;
  144. }
  145. if (y < -1) {
  146. newY = -1;
  147. }
  148. if (x !== 0 && y !== 0) {
  149. newY = 0;
  150. } // Prevent diagonal movement
  151. this.removeFromGrid(grid);
  152. this.currentShape.move(newX, newY);
  153. const isValid = this.isPositionValid(grid, width, height);
  154. if (!isValid) {
  155. this.currentShape.move(-newX, -newY);
  156. }
  157. const shouldFreeze = !isValid && newY !== 0;
  158. this.toGrid(grid, false);
  159. if (shouldFreeze) {
  160. freezeCallback();
  161. }
  162. return isValid;
  163. }
  164. /**
  165. * Tries to rotate the piece
  166. *
  167. * @param grid The grid to rotate the piece on
  168. * @param width The grid's width
  169. * @param height The grid's height
  170. * @return {boolean} True if the rotation was valid, false otherwise
  171. */
  172. tryRotate(grid: GridType, width: number, height: number): boolean {
  173. this.removeFromGrid(grid);
  174. this.currentShape.rotate(true);
  175. if (!this.isPositionValid(grid, width, height)) {
  176. this.currentShape.rotate(false);
  177. this.toGrid(grid, false);
  178. return false;
  179. }
  180. this.toGrid(grid, false);
  181. return true;
  182. }
  183. /**
  184. * Gets this piece used cells coordinates
  185. *
  186. * @return {Array<CoordinatesType>} An array of coordinates
  187. */
  188. getCoordinates(): Array<CoordinatesType> {
  189. return this.currentShape.getCellsCoordinates(true);
  190. }
  191. getCurrentShape(): BaseShape {
  192. return this.currentShape;
  193. }
  194. }